18b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Copyright 2013 Google Inc. All Rights Reserved.
28b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora//
38b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Use of this source code is governed by a BSD-style license
48b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// that can be found in the COPYING file in the root of the source
58b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// tree. An additional intellectual property rights grant can be found
68b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// in the file PATENTS. All contributing project authors may
78b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// be found in the AUTHORS file in the root of the source tree.
88b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// -----------------------------------------------------------------------------
98b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora//
108b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Utilities for processing transparent channel.
118b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora//
128b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Author: Skal (pascal.massimino@gmail.com)
138b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
148b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#include <assert.h>
1533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include "./dsp.h"
168b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
178b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// Tables can be faster on some platform but incur some extra binary size (~2k).
188b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// #define USE_TABLES_FOR_ALPHA_MULT
198b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
208b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora// -----------------------------------------------------------------------------
218b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
228b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define MFIX 24    // 24bit fixed-point arithmetic
238b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define HALF ((1u << MFIX) >> 1)
248b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#define KINV_255 ((1u << MFIX) / 255u)
258b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
268b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic uint32_t Mult(uint8_t x, uint32_t mult) {
278b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  const uint32_t v = (x * mult + HALF) >> MFIX;
288b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  assert(v <= 255);  // <- 24bit precision is enough to ensure that.
298b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return v;
308b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
318b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
328b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#ifdef USE_TABLES_FOR_ALPHA_MULT
338b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
348b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic const uint32_t kMultTables[2][256] = {
358b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  {    // (255u << MFIX) / alpha
368b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00000000, 0xff000000, 0x7f800000, 0x55000000, 0x3fc00000, 0x33000000,
378b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x2a800000, 0x246db6db, 0x1fe00000, 0x1c555555, 0x19800000, 0x172e8ba2,
388b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x15400000, 0x139d89d8, 0x1236db6d, 0x11000000, 0x0ff00000, 0x0f000000,
398b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x0e2aaaaa, 0x0d6bca1a, 0x0cc00000, 0x0c249249, 0x0b9745d1, 0x0b1642c8,
408b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x0aa00000, 0x0a333333, 0x09cec4ec, 0x0971c71c, 0x091b6db6, 0x08cb08d3,
418b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x08800000, 0x0839ce73, 0x07f80000, 0x07ba2e8b, 0x07800000, 0x07492492,
428b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x07155555, 0x06e45306, 0x06b5e50d, 0x0689d89d, 0x06600000, 0x063831f3,
438b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x06124924, 0x05ee23b8, 0x05cba2e8, 0x05aaaaaa, 0x058b2164, 0x056cefa8,
448b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x05500000, 0x05343eb1, 0x05199999, 0x05000000, 0x04e76276, 0x04cfb2b7,
458b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x04b8e38e, 0x04a2e8ba, 0x048db6db, 0x0479435e, 0x04658469, 0x045270d0,
468b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x04400000, 0x042e29f7, 0x041ce739, 0x040c30c3, 0x03fc0000, 0x03ec4ec4,
478b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x03dd1745, 0x03ce540f, 0x03c00000, 0x03b21642, 0x03a49249, 0x03976fc6,
488b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x038aaaaa, 0x037e3f1f, 0x03722983, 0x03666666, 0x035af286, 0x034fcace,
498b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x0344ec4e, 0x033a5440, 0x03300000, 0x0325ed09, 0x031c18f9, 0x0312818a,
508b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x03092492, 0x03000000, 0x02f711dc, 0x02ee5846, 0x02e5d174, 0x02dd7baf,
518b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x02d55555, 0x02cd5cd5, 0x02c590b2, 0x02bdef7b, 0x02b677d4, 0x02af286b,
528b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x02a80000, 0x02a0fd5c, 0x029a1f58, 0x029364d9, 0x028ccccc, 0x0286562d,
538b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x02800000, 0x0279c952, 0x0273b13b, 0x026db6db, 0x0267d95b, 0x026217ec,
548b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x025c71c7, 0x0256e62a, 0x0251745d, 0x024c1bac, 0x0246db6d, 0x0241b2f9,
558b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x023ca1af, 0x0237a6f4, 0x0232c234, 0x022df2df, 0x02293868, 0x02249249,
568b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x02200000, 0x021b810e, 0x021714fb, 0x0212bb51, 0x020e739c, 0x020a3d70,
578b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x02061861, 0x02020408, 0x01fe0000, 0x01fa0be8, 0x01f62762, 0x01f25213,
588b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01ee8ba2, 0x01ead3ba, 0x01e72a07, 0x01e38e38, 0x01e00000, 0x01dc7f10,
598b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01d90b21, 0x01d5a3e9, 0x01d24924, 0x01cefa8d, 0x01cbb7e3, 0x01c880e5,
608b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01c55555, 0x01c234f7, 0x01bf1f8f, 0x01bc14e5, 0x01b914c1, 0x01b61eed,
618b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01b33333, 0x01b05160, 0x01ad7943, 0x01aaaaaa, 0x01a7e567, 0x01a5294a,
628b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01a27627, 0x019fcbd2, 0x019d2a20, 0x019a90e7, 0x01980000, 0x01957741,
638b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x0192f684, 0x01907da4, 0x018e0c7c, 0x018ba2e8, 0x018940c5, 0x0186e5f0,
648b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01849249, 0x018245ae, 0x01800000, 0x017dc11f, 0x017b88ee, 0x0179574e,
658b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01772c23, 0x01750750, 0x0172e8ba, 0x0170d045, 0x016ebdd7, 0x016cb157,
668b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x016aaaaa, 0x0168a9b9, 0x0166ae6a, 0x0164b8a7, 0x0162c859, 0x0160dd67,
678b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x015ef7bd, 0x015d1745, 0x015b3bea, 0x01596596, 0x01579435, 0x0155c7b4,
688b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01540000, 0x01523d03, 0x01507eae, 0x014ec4ec, 0x014d0fac, 0x014b5edc,
698b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x0149b26c, 0x01480a4a, 0x01466666, 0x0144c6af, 0x01432b16, 0x0141938b,
708b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01400000, 0x013e7063, 0x013ce4a9, 0x013b5cc0, 0x0139d89d, 0x01385830,
718b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x0136db6d, 0x01356246, 0x0133ecad, 0x01327a97, 0x01310bf6, 0x012fa0be,
728b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x012e38e3, 0x012cd459, 0x012b7315, 0x012a150a, 0x0128ba2e, 0x01276276,
738b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01260dd6, 0x0124bc44, 0x01236db6, 0x01222222, 0x0120d97c, 0x011f93bc,
748b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x011e50d7, 0x011d10c4, 0x011bd37a, 0x011a98ef, 0x0119611a, 0x01182bf2,
758b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x0116f96f, 0x0115c988, 0x01149c34, 0x0113716a, 0x01124924, 0x01112358,
768b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01100000, 0x010edf12, 0x010dc087, 0x010ca458, 0x010b8a7d, 0x010a72f0,
778b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01095da8, 0x01084a9f, 0x010739ce, 0x01062b2e, 0x01051eb8, 0x01041465,
788b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x01030c30, 0x01020612, 0x01010204, 0x01000000 },
798b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  {   // alpha * KINV_255
808b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00000000, 0x00010101, 0x00020202, 0x00030303, 0x00040404, 0x00050505,
818b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00060606, 0x00070707, 0x00080808, 0x00090909, 0x000a0a0a, 0x000b0b0b,
828b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x000c0c0c, 0x000d0d0d, 0x000e0e0e, 0x000f0f0f, 0x00101010, 0x00111111,
838b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00121212, 0x00131313, 0x00141414, 0x00151515, 0x00161616, 0x00171717,
848b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00181818, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d,
858b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x001e1e1e, 0x001f1f1f, 0x00202020, 0x00212121, 0x00222222, 0x00232323,
868b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00242424, 0x00252525, 0x00262626, 0x00272727, 0x00282828, 0x00292929,
878b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x002a2a2a, 0x002b2b2b, 0x002c2c2c, 0x002d2d2d, 0x002e2e2e, 0x002f2f2f,
888b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00303030, 0x00313131, 0x00323232, 0x00333333, 0x00343434, 0x00353535,
898b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00363636, 0x00373737, 0x00383838, 0x00393939, 0x003a3a3a, 0x003b3b3b,
908b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x003c3c3c, 0x003d3d3d, 0x003e3e3e, 0x003f3f3f, 0x00404040, 0x00414141,
918b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00424242, 0x00434343, 0x00444444, 0x00454545, 0x00464646, 0x00474747,
928b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00484848, 0x00494949, 0x004a4a4a, 0x004b4b4b, 0x004c4c4c, 0x004d4d4d,
938b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x004e4e4e, 0x004f4f4f, 0x00505050, 0x00515151, 0x00525252, 0x00535353,
948b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00545454, 0x00555555, 0x00565656, 0x00575757, 0x00585858, 0x00595959,
958b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x005a5a5a, 0x005b5b5b, 0x005c5c5c, 0x005d5d5d, 0x005e5e5e, 0x005f5f5f,
968b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00606060, 0x00616161, 0x00626262, 0x00636363, 0x00646464, 0x00656565,
978b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00666666, 0x00676767, 0x00686868, 0x00696969, 0x006a6a6a, 0x006b6b6b,
988b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x006c6c6c, 0x006d6d6d, 0x006e6e6e, 0x006f6f6f, 0x00707070, 0x00717171,
998b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00727272, 0x00737373, 0x00747474, 0x00757575, 0x00767676, 0x00777777,
1008b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00787878, 0x00797979, 0x007a7a7a, 0x007b7b7b, 0x007c7c7c, 0x007d7d7d,
1018b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x007e7e7e, 0x007f7f7f, 0x00808080, 0x00818181, 0x00828282, 0x00838383,
1028b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00848484, 0x00858585, 0x00868686, 0x00878787, 0x00888888, 0x00898989,
1038b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x008a8a8a, 0x008b8b8b, 0x008c8c8c, 0x008d8d8d, 0x008e8e8e, 0x008f8f8f,
1048b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00909090, 0x00919191, 0x00929292, 0x00939393, 0x00949494, 0x00959595,
1058b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00969696, 0x00979797, 0x00989898, 0x00999999, 0x009a9a9a, 0x009b9b9b,
1068b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x009c9c9c, 0x009d9d9d, 0x009e9e9e, 0x009f9f9f, 0x00a0a0a0, 0x00a1a1a1,
1078b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00a2a2a2, 0x00a3a3a3, 0x00a4a4a4, 0x00a5a5a5, 0x00a6a6a6, 0x00a7a7a7,
1088b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00a8a8a8, 0x00a9a9a9, 0x00aaaaaa, 0x00ababab, 0x00acacac, 0x00adadad,
1098b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00aeaeae, 0x00afafaf, 0x00b0b0b0, 0x00b1b1b1, 0x00b2b2b2, 0x00b3b3b3,
1108b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00b4b4b4, 0x00b5b5b5, 0x00b6b6b6, 0x00b7b7b7, 0x00b8b8b8, 0x00b9b9b9,
1118b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00bababa, 0x00bbbbbb, 0x00bcbcbc, 0x00bdbdbd, 0x00bebebe, 0x00bfbfbf,
1128b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00c0c0c0, 0x00c1c1c1, 0x00c2c2c2, 0x00c3c3c3, 0x00c4c4c4, 0x00c5c5c5,
1138b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00c6c6c6, 0x00c7c7c7, 0x00c8c8c8, 0x00c9c9c9, 0x00cacaca, 0x00cbcbcb,
1148b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00cccccc, 0x00cdcdcd, 0x00cecece, 0x00cfcfcf, 0x00d0d0d0, 0x00d1d1d1,
1158b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00d2d2d2, 0x00d3d3d3, 0x00d4d4d4, 0x00d5d5d5, 0x00d6d6d6, 0x00d7d7d7,
1168b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00d8d8d8, 0x00d9d9d9, 0x00dadada, 0x00dbdbdb, 0x00dcdcdc, 0x00dddddd,
1178b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00dedede, 0x00dfdfdf, 0x00e0e0e0, 0x00e1e1e1, 0x00e2e2e2, 0x00e3e3e3,
1188b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00e4e4e4, 0x00e5e5e5, 0x00e6e6e6, 0x00e7e7e7, 0x00e8e8e8, 0x00e9e9e9,
1198b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00eaeaea, 0x00ebebeb, 0x00ececec, 0x00ededed, 0x00eeeeee, 0x00efefef,
1208b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00f0f0f0, 0x00f1f1f1, 0x00f2f2f2, 0x00f3f3f3, 0x00f4f4f4, 0x00f5f5f5,
1218b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00f6f6f6, 0x00f7f7f7, 0x00f8f8f8, 0x00f9f9f9, 0x00fafafa, 0x00fbfbfb,
1228b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    0x00fcfcfc, 0x00fdfdfd, 0x00fefefe, 0x00ffffff }
1238b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora};
1248b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
1258b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
1268b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return kMultTables[!inverse][a];
1278b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
1288b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
1298b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#else
1308b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
1318b720228d581a84fd173b6dcb2fa295b59db489aVikas Arorastatic WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
1328b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  return inverse ? (255u << MFIX) / a : a * KINV_255;
1338b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
1348b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
1358b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora#endif    // USE_TABLES_FOR_ALPHA_MULT
1368b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
13733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void MultARGBRow(uint32_t* const ptr, int width, int inverse) {
1388b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int x;
1398b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  for (x = 0; x < width; ++x) {
1408b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const uint32_t argb = ptr[x];
1418b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    if (argb < 0xff000000u) {      // alpha < 255
1428b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      if (argb <= 0x00ffffffu) {   // alpha == 0
1438b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        ptr[x] = 0;
1448b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      } else {
1458b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        const uint32_t alpha = (argb >> 24) & 0xff;
1468b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        const uint32_t scale = GetScale(alpha, inverse);
1478b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        uint32_t out = argb & 0xff000000u;
1488b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        out |= Mult(argb >>  0, scale) <<  0;
1498b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        out |= Mult(argb >>  8, scale) <<  8;
1508b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        out |= Mult(argb >> 16, scale) << 16;
1518b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        ptr[x] = out;
1528b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      }
1538b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    }
1548b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  }
1558b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
1568b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
15733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void MultRow(uint8_t* const ptr, const uint8_t* const alpha,
15833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                    int width, int inverse) {
1598b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int x;
1608b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  for (x = 0; x < width; ++x) {
1618b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    const uint32_t a = alpha[x];
1628b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    if (a != 255) {
1638b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      if (a == 0) {
1648b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        ptr[x] = 0;
1658b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      } else {
1668b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        const uint32_t scale = GetScale(a, inverse);
1678b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora        ptr[x] = Mult(ptr[x], scale);
1688b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora      }
1698b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    }
1708b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  }
1718b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
1728b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
17333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef KINV_255
17433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef HALF
17533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef MFIX
17633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
17733f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
17833f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
17933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                    int width, int inverse);
18033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
18133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
18233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Generic per-plane calls
18333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
18433f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
18533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                      int inverse) {
18633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int n;
18733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  for (n = 0; n < num_rows; ++n) {
18833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    WebPMultARGBRow((uint32_t*)ptr, width, inverse);
18933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    ptr += stride;
19033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
19133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
19233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1938b720228d581a84fd173b6dcb2fa295b59db489aVikas Aroravoid WebPMultRows(uint8_t* ptr, int stride,
1948b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                  const uint8_t* alpha, int alpha_stride,
1958b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora                  int width, int num_rows, int inverse) {
1968b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  int n;
1978b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  for (n = 0; n < num_rows; ++n) {
1988b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    WebPMultRow(ptr, alpha, width, inverse);
1998b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    ptr += stride;
2008b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora    alpha += alpha_stride;
2018b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora  }
2028b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora}
2038b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
20433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
20533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Premultiplied modes
20633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
20733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// non dithered-modes
20833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
20933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
21033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
21133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
21233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if 1     // (int)(x * a / 255.)
21333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define MULTIPLIER(a)   ((a) * 32897U)
21433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
21533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#else     // (int)(x * a / 255. + .5)
21633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define MULTIPLIER(a) ((a) * 65793U)
21733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
21833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif
21933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
22033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
22133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                               int w, int h, int stride) {
22233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (h-- > 0) {
22333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
22433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
22533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int i;
22633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (i = 0; i < w; ++i) {
22733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint32_t a = alpha[4 * i];
22833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      if (a != 0xff) {
22933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        const uint32_t mult = MULTIPLIER(a);
23033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
23133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
23233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
23333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
23433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
23533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    rgba += stride;
23633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
23733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
23833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef MULTIPLIER
23933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef PREMULTIPLY
24033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
24133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// rgbA4444
24233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
24333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define MULTIPLIER(a)  ((a) * 0x1111)    // 0x1111 ~= (1 << 16) / 15
24433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
24533f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint8_t dither_hi(uint8_t x) {
24633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (x & 0xf0) | (x >> 4);
24733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
24833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
24933f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint8_t dither_lo(uint8_t x) {
25033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (x & 0x0f) | (x << 4);
25133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
25233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
25333f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
25433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (x * m) >> 16;
25533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
25633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
25733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
25833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                               int w, int h, int stride,
25933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                               int rg_byte_pos /* 0 or 1 */) {
26033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (h-- > 0) {
26133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int i;
26233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (i = 0; i < w; ++i) {
26333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint32_t rg = rgba4444[2 * i + rg_byte_pos];
26433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint32_t ba = rgba4444[2 * i + (rg_byte_pos ^ 1)];
26533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t a = ba & 0x0f;
26633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint32_t mult = MULTIPLIER(a);
26733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t r = multiply(dither_hi(rg), mult);
26833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t g = multiply(dither_lo(rg), mult);
26933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t b = multiply(dither_hi(ba), mult);
27033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      rgba4444[2 * i + rg_byte_pos] = (r & 0xf0) | ((g >> 4) & 0x0f);
27133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      rgba4444[2 * i + (rg_byte_pos ^ 1)] = (b & 0xf0) | a;
27233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
27333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    rgba4444 += stride;
27433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
27533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
27633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef MULTIPLIER
2778b720228d581a84fd173b6dcb2fa295b59db489aVikas Arora
27833f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
27933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                                   int w, int h, int stride) {
28033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#ifdef WEBP_SWAP_16BIT_CSP
28133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ApplyAlphaMultiply4444(rgba4444, w, h, stride, 1);
28233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#else
28333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  ApplyAlphaMultiply4444(rgba4444, w, h, stride, 0);
28433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif
28533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
28633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int ExtractAlpha(const uint8_t* argb, int argb_stride,
2888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                        int width, int height,
2898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                        uint8_t* alpha, int alpha_stride) {
2908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  uint8_t alpha_mask = 0xff;
2918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
2928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (j = 0; j < height; ++j) {
2948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (i = 0; i < width; ++i) {
2958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const uint8_t alpha_value = argb[4 * i];
2968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      alpha[i] = alpha_value;
2978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      alpha_mask &= alpha_value;
2988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
2998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    argb += argb_stride;
3008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    alpha += alpha_stride;
3018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (alpha_mask == 0xff);
3038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
30533f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
30633f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
3078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroraint (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
30833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
30933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
31033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Init function
31133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
3128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroraextern void WebPInitAlphaProcessingSSE2(void);
3138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3149e80ee991168a0a6c2a906dd2c17c5e17df4566eJames Zernstatic volatile VP8CPUInfo alpha_processing_last_cpuinfo_used =
3159e80ee991168a0a6c2a906dd2c17c5e17df4566eJames Zern    (VP8CPUInfo)&alpha_processing_last_cpuinfo_used;
3169e80ee991168a0a6c2a906dd2c17c5e17df4566eJames Zern
31733f74dabbc7920a65ed435d7417987589febdc16Vikas Aroravoid WebPInitAlphaProcessing(void) {
3189e80ee991168a0a6c2a906dd2c17c5e17df4566eJames Zern  if (alpha_processing_last_cpuinfo_used == VP8GetCPUInfo) return;
3199e80ee991168a0a6c2a906dd2c17c5e17df4566eJames Zern
32033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPMultARGBRow = MultARGBRow;
32133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPMultRow = MultRow;
32233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPApplyAlphaMultiply = ApplyAlphaMultiply;
32333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
3248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPExtractAlpha = ExtractAlpha;
3258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // If defined, use CPUInfo() to overwrite some pointers with faster versions.
3278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (VP8GetCPUInfo != NULL) {
3288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(WEBP_USE_SSE2)
3298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (VP8GetCPUInfo(kSSE2)) {
3308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      WebPInitAlphaProcessingSSE2();
3318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
3328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
3338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3349e80ee991168a0a6c2a906dd2c17c5e17df4566eJames Zern  alpha_processing_last_cpuinfo_used = VP8GetCPUInfo;
33533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
336