1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../../include/fxge/fx_ge.h"
8#include "../../../include/fxcodec/fx_codec.h"
9#include "dib_int.h"
10const FX_BYTE g_GammaRamp[256] = {
11    0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1,
12    1,   1,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,   3,
13    4,   4,   4,   4,   4,   5,   5,   5,   5,   6,   6,   6,   6,   7,   7,   7,
14    8,   8,   8,   8,   9,   9,   9,  10,  10,  10,  11,  11,  12,  12,  12,  13,
15    13,  13,  14,  14,  15,  15,  16,  16,  17,  17,  17,  18,  18,  19,  19,  20,
16    20,  21,  22,  22,  23,  23,  24,  24,  25,  25,  26,  27,  27,  28,  29,  29,
17    30,  30,  31,  32,  32,  33,  34,  35,  35,  36,  37,  37,  38,  39,  40,  41,
18    41,  42,  43,  44,  45,  45,  46,  47,  48,  49,  50,  51,  51,  52,  53,  54,
19    55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,
20    71,  72,  73,  74,  76,  77,  78,  79,  80,  81,  82,  84,  85,  86,  87,  88,
21    90,  91,  92,  93,  95,  96,  97,  99, 100, 101, 103, 104, 105, 107, 108, 109,
22    111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 125, 127, 128, 130, 131, 133,
23    134, 136, 138, 139, 141, 142, 144, 146, 147, 149, 151, 152, 154, 156, 157, 159,
24    161, 163, 164, 166, 168, 170, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188,
25    190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220,
26    222, 224, 226, 229, 231, 233, 235, 237, 239, 242, 244, 246, 248, 250, 253, 255,
27};
28const FX_BYTE g_GammaInverse[256] = {
29    0,  13,  22,  28,  34,  38,  42,  46,  50,  53,  56,  59,  61,  64,  66,  69,
30    71,  73,  75,  77,  79,  81,  83,  85,  86,  88,  90,  92,  93,  95,  96,  98,
31    99, 101, 102, 104, 105, 106, 108, 109, 110, 112, 113, 114, 115, 117, 118, 119,
32    120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136,
33    137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151,
34    152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164,
35    165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 175, 176,
36    177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184, 185, 185, 186, 187, 187,
37    188, 189, 189, 190, 190, 191, 192, 192, 193, 194, 194, 195, 196, 196, 197, 197,
38    198, 199, 199, 200, 200, 201, 202, 202, 203, 203, 204, 205, 205, 206, 206, 207,
39    208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215, 216,
40    216, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224, 224,
41    225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
42    233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240,
43    241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248,
44    248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255,
45};
46const FX_BYTE _color_sqrt[256] = {
47    0x00, 0x03, 0x07, 0x0B, 0x0F, 0x12, 0x16, 0x19, 0x1D, 0x20, 0x23, 0x26, 0x29, 0x2C, 0x2F, 0x32,
48    0x35, 0x37, 0x3A, 0x3C, 0x3F, 0x41, 0x43, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56,
49    0x57, 0x59, 0x5B, 0x5C, 0x5E, 0x60, 0x61, 0x63, 0x64, 0x65, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D,
50    0x6E, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E,
51    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E,
52    0x8F, 0x90, 0x91, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C,
53    0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA4, 0xA5, 0xA6, 0xA7, 0xA7, 0xA8,
54    0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAD, 0xAE, 0xAF, 0xB0, 0xB0, 0xB1, 0xB2, 0xB3, 0xB3, 0xB4,
55    0xB5, 0xB5, 0xB6, 0xB7, 0xB7, 0xB8, 0xB9, 0xBA, 0xBA, 0xBB, 0xBC, 0xBC, 0xBD, 0xBE, 0xBE, 0xBF,
56    0xC0, 0xC0, 0xC1, 0xC2, 0xC2, 0xC3, 0xC4, 0xC4, 0xC5, 0xC6, 0xC6, 0xC7, 0xC7, 0xC8, 0xC9, 0xC9,
57    0xCA, 0xCB, 0xCB, 0xCC, 0xCC, 0xCD, 0xCE, 0xCE, 0xCF, 0xD0, 0xD0, 0xD1, 0xD1, 0xD2, 0xD3, 0xD3,
58    0xD4, 0xD4, 0xD5, 0xD6, 0xD6, 0xD7, 0xD7, 0xD8, 0xD9, 0xD9, 0xDA, 0xDA, 0xDB, 0xDC, 0xDC, 0xDD,
59    0xDD, 0xDE, 0xDE, 0xDF, 0xE0, 0xE0, 0xE1, 0xE1, 0xE2, 0xE2, 0xE3, 0xE4, 0xE4, 0xE5, 0xE5, 0xE6,
60    0xE6, 0xE7, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEA, 0xEB, 0xEB, 0xEC, 0xEC, 0xED, 0xED, 0xEE, 0xEE,
61    0xEF, 0xF0, 0xF0, 0xF1, 0xF1, 0xF2, 0xF2, 0xF3, 0xF3, 0xF4, 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7,
62    0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF
63};
64int _BLEND(int blend_mode, int back_color, int src_color)
65{
66    switch (blend_mode) {
67        case FXDIB_BLEND_NORMAL:
68            return src_color;
69        case FXDIB_BLEND_MULTIPLY:
70            return src_color * back_color / 255;
71        case FXDIB_BLEND_SCREEN:
72            return src_color + back_color - src_color * back_color / 255;
73        case FXDIB_BLEND_OVERLAY:
74            return _BLEND(FXDIB_BLEND_HARDLIGHT, src_color, back_color);
75        case FXDIB_BLEND_DARKEN:
76            return src_color < back_color ? src_color : back_color;
77        case FXDIB_BLEND_LIGHTEN:
78            return src_color > back_color ? src_color : back_color;
79        case FXDIB_BLEND_COLORDODGE: {
80                if (src_color == 255) {
81                    return src_color;
82                }
83                int result = back_color * 255 / (255 - src_color);
84                if (result > 255) {
85                    return 255;
86                }
87                return result;
88            }
89        case FXDIB_BLEND_COLORBURN: {
90                if (src_color == 0) {
91                    return src_color;
92                }
93                int result = (255 - back_color) * 255 / src_color;
94                if (result > 255) {
95                    result = 255;
96                }
97                return 255 - result;
98            }
99        case FXDIB_BLEND_HARDLIGHT:
100            if (src_color < 128) {
101                return (src_color * back_color * 2) / 255;
102            }
103            return _BLEND(FXDIB_BLEND_SCREEN, back_color, 2 * src_color - 255);
104        case FXDIB_BLEND_SOFTLIGHT: {
105                if (src_color < 128) {
106                    return back_color - (255 - 2 * src_color) * back_color * (255 - back_color) / 255 / 255;
107                }
108                return back_color + (2 * src_color - 255) * (_color_sqrt[back_color] - back_color) / 255;
109            }
110        case FXDIB_BLEND_DIFFERENCE:
111            return back_color < src_color ? src_color - back_color : back_color - src_color;
112        case FXDIB_BLEND_EXCLUSION:
113            return back_color + src_color - 2 * back_color * src_color / 255;
114    }
115    return src_color;
116}
117struct _RGB {
118    int red;
119    int green;
120    int blue;
121};
122static inline int _Lum(_RGB color)
123{
124    return (color.red * 30 + color.green * 59 + color.blue * 11) / 100;
125}
126static _RGB _ClipColor(_RGB color)
127{
128    int l = _Lum(color);
129    int n = color.red;
130    if (color.green < n) {
131        n = color.green;
132    }
133    if (color.blue < n) {
134        n = color.blue;
135    }
136    int x = color.red;
137    if (color.green > x) {
138        x = color.green;
139    }
140    if (color.blue > x) {
141        x = color.blue;
142    }
143    if (n < 0) {
144        color.red = l + ((color.red - l) * l / (l - n));
145        color.green = l + ((color.green - l) * l / (l - n));
146        color.blue = l + ((color.blue - l) * l / (l - n));
147    }
148    if (x > 255) {
149        color.red = l + ((color.red - l) * (255 - l) / (x - l));
150        color.green = l + ((color.green - l) * (255 - l) / (x - l));
151        color.blue = l + ((color.blue - l) * (255 - l) / (x - l));
152    }
153    return color;
154}
155static _RGB _SetLum(_RGB color, int l)
156{
157    int d = l - _Lum(color);
158    color.red += d;
159    color.green += d;
160    color.blue += d;
161    return _ClipColor(color);
162}
163static int _Sat(_RGB color)
164{
165    int n = color.red;
166    if (color.green < n) {
167        n = color.green;
168    }
169    if (color.blue < n) {
170        n = color.blue;
171    }
172    int x = color.red;
173    if (color.green > x) {
174        x = color.green;
175    }
176    if (color.blue > x) {
177        x = color.blue;
178    }
179    return x - n;
180}
181static _RGB _SetSat(_RGB color, int s)
182{
183    int* max = &color.red;
184    int* mid = &color.red;
185    int* min = &color.red;
186    if (color.green > *max) {
187        max = &color.green;
188    }
189    if (color.blue > *max) {
190        max = &color.blue;
191    }
192    if (color.green < *min) {
193        min = &color.green;
194    }
195    if (color.blue < *min) {
196        min = &color.blue;
197    }
198    if (*max == *min) {
199        color.red = 0;
200        color.green = 0;
201        color.blue = 0;
202        return color;
203    }
204    if (max == &color.red) {
205        if (min == &color.green) {
206            mid = &color.blue;
207        } else {
208            mid = &color.green;
209        }
210    } else if (max == &color.green) {
211        if (min == &color.red) {
212            mid = &color.blue;
213        } else {
214            mid = &color.red;
215        }
216    } else {
217        if (min == &color.green) {
218            mid = &color.red;
219        } else {
220            mid = &color.green;
221        }
222    }
223    if (*max > *min) {
224        *mid = (*mid - *min) * s / (*max - *min);
225        *max = s;
226        *min = 0;
227    }
228    return color;
229}
230void _RGB_Blend(int blend_mode, FX_LPCBYTE src_scan, FX_BYTE* dest_scan, int results[3])
231{
232    _RGB src, back, result;
233    src.red = src_scan[2];
234    src.green = src_scan[1];
235    src.blue = src_scan[0];
236    back.red = dest_scan[2];
237    back.green = dest_scan[1];
238    back.blue = dest_scan[0];
239    switch (blend_mode) {
240        case FXDIB_BLEND_HUE:
241            result = _SetLum(_SetSat(src, _Sat(back)), _Lum(back));
242            break;
243        case FXDIB_BLEND_SATURATION:
244            result = _SetLum(_SetSat(back, _Sat(src)), _Lum(back));
245            break;
246        case FXDIB_BLEND_COLOR:
247            result = _SetLum(src, _Lum(back));
248            break;
249        case FXDIB_BLEND_LUMINOSITY:
250            result = _SetLum(back, _Lum(src));
251            break;
252    }
253    results[0] = result.blue;
254    results[1] = result.green;
255    results[2] = result.red;
256}
257inline void _CompositeRow_Argb2Mask(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int pixel_count, FX_LPCBYTE clip_scan)
258{
259    src_scan += 3;
260    for (int col = 0; col < pixel_count; col ++) {
261        int src_alpha = *src_scan;
262        if (clip_scan) {
263            src_alpha = clip_scan[col] * src_alpha / 255;
264        }
265        FX_BYTE back_alpha = *dest_scan;
266        if (!back_alpha) {
267            *dest_scan = src_alpha;
268        } else if (src_alpha) {
269            *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
270        }
271        dest_scan ++;
272        src_scan += 4;
273    }
274}
275void _CompositeRow_Rgba2Mask(FX_LPBYTE dest_scan, FX_LPCBYTE src_alpha_scan, int pixel_count, FX_LPCBYTE clip_scan)
276{
277    for (int col = 0; col < pixel_count; col ++) {
278        int src_alpha = *src_alpha_scan++;
279        if (clip_scan) {
280            src_alpha = clip_scan[col] * src_alpha / 255;
281        }
282        FX_BYTE back_alpha = *dest_scan;
283        if (!back_alpha) {
284            *dest_scan = src_alpha;
285        } else if (src_alpha) {
286            *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
287        }
288        dest_scan ++;
289    }
290}
291void _CompositeRow_Rgb2Mask(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan)
292{
293    if (clip_scan) {
294        for (int i = 0; i < width; i ++) {
295            *dest_scan = FXDIB_ALPHA_UNION(*dest_scan, *clip_scan);
296            dest_scan ++;
297            clip_scan ++;
298        }
299    } else {
300        FXSYS_memset8(dest_scan, 0xff, width);
301    }
302}
303void _CompositeRow_Argb2Graya(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int pixel_count, int blend_type, FX_LPCBYTE clip_scan,
304                              FX_LPCBYTE src_alpha_scan, FX_LPBYTE dst_alpha_scan, void* pIccTransform)
305{
306    ICodec_IccModule* pIccModule = NULL;
307    if (pIccTransform) {
308        pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
309    }
310    if (blend_type) {
311        FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
312        int blended_color;
313        if (src_alpha_scan) {
314            for (int col = 0; col < pixel_count; col ++) {
315                FX_BYTE back_alpha = *dst_alpha_scan;
316                if (back_alpha == 0) {
317                    int src_alpha = *src_alpha_scan++;
318                    if (clip_scan) {
319                        src_alpha = clip_scan[col] * src_alpha / 255;
320                    }
321                    if (src_alpha) {
322                        if (pIccTransform) {
323                            pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1);
324                        } else {
325                            *dest_scan =  FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
326                        }
327                        *dst_alpha_scan = src_alpha;
328                    }
329                    dest_scan ++;
330                    dst_alpha_scan ++;
331                    src_scan += 3;
332                    continue;
333                }
334                FX_BYTE src_alpha = *src_alpha_scan++;
335                if (clip_scan) {
336                    src_alpha = clip_scan[col] * src_alpha / 255;
337                }
338                if (src_alpha == 0) {
339                    dest_scan ++;
340                    dst_alpha_scan ++;
341                    src_scan += 3;
342                    continue;
343                }
344                *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha);
345                int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan);
346                FX_BYTE gray;
347                if (pIccTransform) {
348                    pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
349                } else {
350                    gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
351                }
352                if (bNonseparableBlend) {
353                    blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
354                }
355                gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
356                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
357                dest_scan ++;
358                dst_alpha_scan++;
359                src_scan += 3;
360            }
361        } else
362            for (int col = 0; col < pixel_count; col ++) {
363                FX_BYTE back_alpha = *dst_alpha_scan;
364                if (back_alpha == 0) {
365                    int src_alpha = src_scan[3];
366                    if (clip_scan) {
367                        src_alpha = clip_scan[col] * src_alpha / 255;
368                    }
369                    if (src_alpha) {
370                        if (pIccTransform) {
371                            pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1);
372                        } else {
373                            *dest_scan =  FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
374                        }
375                        *dst_alpha_scan = src_alpha;
376                    }
377                    dest_scan ++;
378                    dst_alpha_scan ++;
379                    src_scan += 4;
380                    continue;
381                }
382                FX_BYTE src_alpha = src_scan[3];
383                if (clip_scan) {
384                    src_alpha = clip_scan[col] * src_alpha / 255;
385                }
386                if (src_alpha == 0) {
387                    dest_scan ++;
388                    dst_alpha_scan ++;
389                    src_scan += 4;
390                    continue;
391                }
392                *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha);
393                int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan);
394                FX_BYTE gray;
395                if (pIccTransform) {
396                    pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
397                } else {
398                    gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
399                }
400                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
401                dest_scan ++;
402                dst_alpha_scan++;
403                src_scan += 4;
404            }
405        return;
406    }
407    if (src_alpha_scan) {
408        for (int col = 0; col < pixel_count; col ++) {
409            FX_BYTE back_alpha = *dst_alpha_scan;
410            if (back_alpha == 0) {
411                int src_alpha = *src_alpha_scan++;
412                if (clip_scan) {
413                    src_alpha = clip_scan[col] * src_alpha / 255;
414                }
415                if (src_alpha) {
416                    if (pIccTransform) {
417                        pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1);
418                    } else {
419                        *dest_scan =  FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
420                    }
421                    *dst_alpha_scan = src_alpha;
422                }
423                dest_scan ++;
424                dst_alpha_scan ++;
425                src_scan += 3;
426                continue;
427            }
428            FX_BYTE src_alpha = *src_alpha_scan++;
429            if (clip_scan) {
430                src_alpha = clip_scan[col] * src_alpha / 255;
431            }
432            if (src_alpha == 0) {
433                dest_scan ++;
434                dst_alpha_scan ++;
435                src_scan += 3;
436                continue;
437            }
438            *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha);
439            int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan);
440            FX_BYTE gray;
441            if (pIccTransform) {
442                pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
443            } else {
444                gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
445            }
446            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
447            dest_scan ++;
448            dst_alpha_scan++;
449            src_scan += 3;
450        }
451    } else
452        for (int col = 0; col < pixel_count; col ++) {
453            FX_BYTE back_alpha = *dst_alpha_scan;
454            if (back_alpha == 0) {
455                int src_alpha = src_scan[3];
456                if (clip_scan) {
457                    src_alpha = clip_scan[col] * src_alpha / 255;
458                }
459                if (src_alpha) {
460                    if (pIccTransform) {
461                        pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1);
462                    } else {
463                        *dest_scan =  FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
464                    }
465                    *dst_alpha_scan = src_alpha;
466                }
467                dest_scan ++;
468                dst_alpha_scan ++;
469                src_scan += 4;
470                continue;
471            }
472            FX_BYTE src_alpha = src_scan[3];
473            if (clip_scan) {
474                src_alpha = clip_scan[col] * src_alpha / 255;
475            }
476            if (src_alpha == 0) {
477                dest_scan ++;
478                dst_alpha_scan ++;
479                src_scan += 4;
480                continue;
481            }
482            *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha);
483            int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan);
484            FX_BYTE gray;
485            if (pIccTransform) {
486                pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
487            } else {
488                gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
489            }
490            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
491            dest_scan ++;
492            dst_alpha_scan++;
493            src_scan += 4;
494        }
495}
496inline void _CompositeRow_Argb2Gray(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int pixel_count,
497                                    int blend_type, FX_LPCBYTE clip_scan,
498                                    FX_LPCBYTE src_alpha_scan, void* pIccTransform)
499{
500    ICodec_IccModule* pIccModule = NULL;
501    FX_BYTE gray;
502    if (pIccTransform) {
503        pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
504    }
505    if (blend_type) {
506        FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
507        int blended_color;
508        if (src_alpha_scan) {
509            for (int col = 0; col < pixel_count; col ++) {
510                int src_alpha = *src_alpha_scan++;
511                if (clip_scan) {
512                    src_alpha = clip_scan[col] * src_alpha / 255;
513                }
514                if (src_alpha) {
515                    if (pIccTransform) {
516                        pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
517                    } else {
518                        gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
519                    }
520                    if (bNonseparableBlend) {
521                        blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
522                    }
523                    gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
524                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
525                }
526                dest_scan ++;
527                src_scan += 3;
528            }
529        } else
530            for (int col = 0; col < pixel_count; col ++) {
531                int src_alpha = src_scan[3];
532                if (clip_scan) {
533                    src_alpha = clip_scan[col] * src_alpha / 255;
534                }
535                if (src_alpha) {
536                    if (pIccTransform) {
537                        pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
538                    } else {
539                        gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
540                    }
541                    if (bNonseparableBlend) {
542                        blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
543                    }
544                    gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
545                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
546                }
547                dest_scan ++;
548                src_scan += 4;
549            }
550        return;
551    }
552    if (src_alpha_scan) {
553        for (int col = 0; col < pixel_count; col ++) {
554            int src_alpha = *src_alpha_scan++;
555            if (clip_scan) {
556                src_alpha = clip_scan[col] * src_alpha / 255;
557            }
558            if (src_alpha) {
559                if (pIccTransform) {
560                    pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
561                } else {
562                    gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
563                }
564                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
565            }
566            dest_scan ++;
567            src_scan += 3;
568        }
569    } else
570        for (int col = 0; col < pixel_count; col ++) {
571            int src_alpha = src_scan[3];
572            if (clip_scan) {
573                src_alpha = clip_scan[col] * src_alpha / 255;
574            }
575            if (src_alpha) {
576                if (pIccTransform) {
577                    pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
578                } else {
579                    gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
580                }
581                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
582            }
583            dest_scan ++;
584            src_scan += 4;
585        }
586}
587inline void _CompositeRow_Rgb2Gray(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_Bpp, int pixel_count,
588                                   int blend_type, FX_LPCBYTE clip_scan,
589                                   void* pIccTransform)
590{
591    ICodec_IccModule* pIccModule = NULL;
592    FX_BYTE gray;
593    if (pIccTransform) {
594        pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
595    }
596    if (blend_type) {
597        FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
598        int blended_color;
599        for (int col = 0; col < pixel_count; col ++) {
600            if (pIccTransform) {
601                pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
602            } else {
603                gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
604            }
605            if (bNonseparableBlend) {
606                blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
607            }
608            gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
609            if (clip_scan && clip_scan[col] < 255) {
610                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
611            } else {
612                *dest_scan = gray;
613            }
614            dest_scan ++;
615            src_scan += src_Bpp;
616        }
617        return;
618    }
619    for (int col = 0; col < pixel_count; col ++) {
620        if (pIccTransform) {
621            pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
622        } else {
623            gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
624        }
625        if (clip_scan && clip_scan[col] < 255) {
626            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
627        } else {
628            *dest_scan = gray;
629        }
630        dest_scan ++;
631        src_scan += src_Bpp;
632    }
633}
634void _CompositeRow_Rgb2Graya(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_Bpp, int pixel_count,
635                             int blend_type, FX_LPCBYTE clip_scan,
636                             FX_LPBYTE dest_alpha_scan, void* pIccTransform)
637{
638    ICodec_IccModule* pIccModule = NULL;
639    if (pIccTransform) {
640        pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
641    }
642    if (blend_type) {
643        int blended_color;
644        FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
645        for (int col = 0; col < pixel_count; col ++) {
646            int back_alpha = *dest_alpha_scan;
647            if (back_alpha == 0) {
648                if (pIccTransform) {
649                    pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1);
650                } else {
651                    *dest_scan = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
652                }
653                dest_scan ++;
654                dest_alpha_scan++;
655                src_scan += src_Bpp;
656                continue;
657            }
658            int src_alpha = 255;
659            if (clip_scan) {
660                src_alpha = clip_scan[col];
661            }
662            if (src_alpha == 0) {
663                dest_scan ++;
664                dest_alpha_scan ++;
665                src_scan += src_Bpp;
666                continue;
667            }
668            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
669            *dest_alpha_scan++ = dest_alpha;
670            int alpha_ratio = src_alpha * 255 / dest_alpha;
671            FX_BYTE gray;
672            if (pIccTransform) {
673                pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
674            } else {
675                gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
676            }
677            if (bNonseparableBlend) {
678                blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
679            }
680            gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
681            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
682            dest_scan ++;
683            src_scan += src_Bpp;
684        }
685        return;
686    }
687    for (int col = 0; col < pixel_count; col ++) {
688        int src_alpha = 255;
689        if (clip_scan) {
690            src_alpha = clip_scan[col];
691        }
692        if (src_alpha == 255) {
693            if (pIccTransform) {
694                pIccModule->TranslateScanline(pIccTransform, dest_scan, src_scan, 1);
695            } else {
696                *dest_scan = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
697            }
698            dest_scan ++;
699            *dest_alpha_scan++ = 255;
700            src_scan += src_Bpp;
701            continue;
702        }
703        if (src_alpha == 0) {
704            dest_scan ++;
705            dest_alpha_scan ++;
706            src_scan += src_Bpp;
707            continue;
708        }
709        int back_alpha = *dest_alpha_scan;
710        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
711        *dest_alpha_scan++ = dest_alpha;
712        int alpha_ratio = src_alpha * 255 / dest_alpha;
713        FX_BYTE gray;
714        if (pIccTransform) {
715            pIccModule->TranslateScanline(pIccTransform, &gray, src_scan, 1);
716        } else {
717            gray = FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
718        }
719        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
720        dest_scan ++;
721        src_scan += src_Bpp;
722    }
723}
724void _CompositeRow_Argb2Argb(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int pixel_count, int blend_type, FX_LPCBYTE clip_scan,
725                             FX_LPBYTE dest_alpha_scan, FX_LPCBYTE src_alpha_scan)
726{
727    int blended_colors[3];
728    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
729    if (dest_alpha_scan == NULL) {
730        if (src_alpha_scan == NULL) {
731            FX_BYTE back_alpha = 0;
732            for (int col = 0; col < pixel_count; col ++) {
733                back_alpha = dest_scan[3];
734                if (back_alpha == 0) {
735                    if (clip_scan) {
736                        int src_alpha = clip_scan[col] * src_scan[3] / 255;
737                        FXARGB_SETDIB(dest_scan, (FXARGB_GETDIB(src_scan) & 0xffffff) | (src_alpha << 24));
738                    } else {
739                        FXARGB_COPY(dest_scan, src_scan);
740                    }
741                    dest_scan += 4;
742                    src_scan += 4;
743                    continue;
744                }
745                FX_BYTE src_alpha;
746                if (clip_scan == NULL) {
747                    src_alpha = src_scan[3];
748                } else {
749                    src_alpha = clip_scan[col] * src_scan[3] / 255;
750                }
751                if (src_alpha == 0) {
752                    dest_scan += 4;
753                    src_scan += 4;
754                    continue;
755                }
756                FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
757                dest_scan[3] = dest_alpha;
758                int alpha_ratio = src_alpha * 255 / dest_alpha;
759                if (bNonseparableBlend) {
760                    _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
761                }
762                for (int color = 0; color < 3; color ++) {
763                    if (blend_type) {
764                        int blended = bNonseparableBlend ? blended_colors[color] :
765                                      _BLEND(blend_type, *dest_scan, *src_scan);
766                        blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha);
767                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
768                    } else {
769                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
770                    }
771                    dest_scan ++;
772                    src_scan ++;
773                }
774                dest_scan ++;
775                src_scan ++;
776            }
777        } else {
778            for (int col = 0; col < pixel_count; col ++) {
779                FX_BYTE back_alpha = dest_scan[3];
780                if (back_alpha == 0) {
781                    if (clip_scan) {
782                        int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255;
783                        FXARGB_SETDIB(dest_scan, FXARGB_MAKE((src_alpha << 24), src_scan[2], src_scan[1], *src_scan));
784                    } else {
785                        FXARGB_SETDIB(dest_scan, FXARGB_MAKE((*src_alpha_scan << 24), src_scan[2], src_scan[1], *src_scan));
786                    }
787                    dest_scan += 4;
788                    src_scan += 3;
789                    src_alpha_scan ++;
790                    continue;
791                }
792                FX_BYTE src_alpha;
793                if (clip_scan == NULL) {
794                    src_alpha = *src_alpha_scan ++;
795                } else {
796                    src_alpha = clip_scan[col] * (*src_alpha_scan ++) / 255;
797                }
798                if (src_alpha == 0) {
799                    dest_scan += 4;
800                    src_scan += 3;
801                    continue;
802                }
803                FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
804                dest_scan[3] = dest_alpha;
805                int alpha_ratio = src_alpha * 255 / dest_alpha;
806                if (bNonseparableBlend) {
807                    _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
808                }
809                for (int color = 0; color < 3; color ++) {
810                    if (blend_type) {
811                        int blended = bNonseparableBlend ? blended_colors[color] :
812                                      _BLEND(blend_type, *dest_scan, *src_scan);
813                        blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha);
814                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
815                    } else {
816                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
817                    }
818                    dest_scan ++;
819                    src_scan ++;
820                }
821                dest_scan ++;
822            }
823        }
824    } else {
825        if (src_alpha_scan) {
826            for (int col = 0; col < pixel_count; col ++) {
827                FX_BYTE back_alpha = *dest_alpha_scan;
828                if (back_alpha == 0) {
829                    if (clip_scan) {
830                        int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255;
831                        *dest_alpha_scan = src_alpha;
832                        *dest_scan++ = *src_scan++;
833                        *dest_scan++ = *src_scan++;
834                        *dest_scan++ = *src_scan++;
835                    } else {
836                        *dest_alpha_scan = *src_alpha_scan;
837                        *dest_scan++ = *src_scan++;
838                        *dest_scan++ = *src_scan++;
839                        *dest_scan++ = *src_scan++;
840                    }
841                    dest_alpha_scan ++;
842                    src_alpha_scan ++;
843                    continue;
844                }
845                FX_BYTE src_alpha;
846                if (clip_scan == NULL) {
847                    src_alpha = *src_alpha_scan ++;
848                } else {
849                    src_alpha = clip_scan[col] * (*src_alpha_scan ++) / 255;
850                }
851                if (src_alpha == 0) {
852                    dest_scan += 3;
853                    src_scan += 3;
854                    dest_alpha_scan ++;
855                    continue;
856                }
857                FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
858                *dest_alpha_scan ++ = dest_alpha;
859                int alpha_ratio = src_alpha * 255 / dest_alpha;
860                if (bNonseparableBlend) {
861                    _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
862                }
863                for (int color = 0; color < 3; color ++) {
864                    if (blend_type) {
865                        int blended = bNonseparableBlend ? blended_colors[color] :
866                                      _BLEND(blend_type, *dest_scan, *src_scan);
867                        blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha);
868                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
869                    } else {
870                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
871                    }
872                    dest_scan ++;
873                    src_scan ++;
874                }
875            }
876        } else {
877            for (int col = 0; col < pixel_count; col ++) {
878                FX_BYTE back_alpha = *dest_alpha_scan;
879                if (back_alpha == 0) {
880                    if (clip_scan) {
881                        int src_alpha = clip_scan[col] * src_scan[3] / 255;
882                        *dest_alpha_scan = src_alpha;
883                        *dest_scan++ = *src_scan++;
884                        *dest_scan++ = *src_scan++;
885                        *dest_scan++ = *src_scan++;
886                    } else {
887                        *dest_alpha_scan = src_scan[3];
888                        *dest_scan++ = *src_scan++;
889                        *dest_scan++ = *src_scan++;
890                        *dest_scan++ = *src_scan++;
891                    }
892                    dest_alpha_scan ++;
893                    src_scan ++;
894                    continue;
895                }
896                FX_BYTE src_alpha;
897                if (clip_scan == NULL) {
898                    src_alpha = src_scan[3];
899                } else {
900                    src_alpha = clip_scan[col] * src_scan[3] / 255;
901                }
902                if (src_alpha == 0) {
903                    dest_scan += 3;
904                    src_scan += 4;
905                    dest_alpha_scan ++;
906                    continue;
907                }
908                FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
909                *dest_alpha_scan++ = dest_alpha;
910                int alpha_ratio = src_alpha * 255 / dest_alpha;
911                if (bNonseparableBlend) {
912                    _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
913                }
914                for (int color = 0; color < 3; color ++) {
915                    if (blend_type) {
916                        int blended = bNonseparableBlend ? blended_colors[color] :
917                                      _BLEND(blend_type, *dest_scan, *src_scan);
918                        blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha);
919                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
920                    } else {
921                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
922                    }
923                    dest_scan ++;
924                    src_scan ++;
925                }
926                src_scan ++;
927            }
928        }
929    }
930}
931void _CompositeRow_Rgb2Argb_Blend_NoClip(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int src_Bpp,
932        FX_LPBYTE dest_alpha_scan)
933{
934    int blended_colors[3];
935    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
936    int src_gap = src_Bpp - 3;
937    if (dest_alpha_scan == NULL) {
938        for (int col = 0; col < width; col ++) {
939            FX_BYTE back_alpha = dest_scan[3];
940            if (back_alpha == 0) {
941                if (src_Bpp == 4) {
942                    FXARGB_SETDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan));
943                } else {
944                    FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[2], src_scan[1], src_scan[0]));
945                }
946                dest_scan += 4;
947                src_scan += src_Bpp;
948                continue;
949            }
950            dest_scan[3] = 0xff;
951            if (bNonseparableBlend) {
952                _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
953            }
954            for (int color = 0; color < 3; color ++) {
955                int src_color = *src_scan;
956                int blended = bNonseparableBlend ? blended_colors[color] :
957                              _BLEND(blend_type, *dest_scan, src_color);
958                *dest_scan = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
959                dest_scan ++;
960                src_scan ++;
961            }
962            dest_scan ++;
963            src_scan += src_gap;
964        }
965    } else {
966        for (int col = 0; col < width; col ++) {
967            FX_BYTE back_alpha = *dest_alpha_scan;
968            if (back_alpha == 0) {
969                *dest_scan++ = *src_scan++;
970                *dest_scan++ = *src_scan++;
971                *dest_scan++ = *src_scan++;
972                *dest_alpha_scan++ = 0xff;
973                src_scan += src_gap;
974                continue;
975            }
976            *dest_alpha_scan++ = 0xff;
977            if (bNonseparableBlend) {
978                _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
979            }
980            for (int color = 0; color < 3; color ++) {
981                int src_color = *src_scan;
982                int blended = bNonseparableBlend ? blended_colors[color] :
983                              _BLEND(blend_type, *dest_scan, src_color);
984                *dest_scan = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
985                dest_scan ++;
986                src_scan ++;
987            }
988            src_scan += src_gap;
989        }
990    }
991}
992inline void _CompositeRow_Rgb2Argb_Blend_Clip(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int src_Bpp, FX_LPCBYTE clip_scan,
993        FX_LPBYTE dest_alpha_scan)
994{
995    int blended_colors[3];
996    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
997    int src_gap = src_Bpp - 3;
998    if (dest_alpha_scan == NULL) {
999        for (int col = 0; col < width; col ++) {
1000            int src_alpha = *clip_scan ++;
1001            FX_BYTE back_alpha = dest_scan[3];
1002            if (back_alpha == 0) {
1003                *dest_scan++ = *src_scan++;
1004                *dest_scan++ = *src_scan++;
1005                *dest_scan++ = *src_scan++;
1006                src_scan += src_gap;
1007                dest_scan ++;
1008                continue;
1009            }
1010            if (src_alpha == 0) {
1011                dest_scan += 4;
1012                src_scan += src_Bpp;
1013                continue;
1014            }
1015            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1016            dest_scan[3] = dest_alpha;
1017            int alpha_ratio = src_alpha * 255 / dest_alpha;
1018            if (bNonseparableBlend) {
1019                _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
1020            }
1021            for (int color = 0; color < 3; color ++) {
1022                int src_color = *src_scan;
1023                int blended = bNonseparableBlend ? blended_colors[color] :
1024                              _BLEND(blend_type, *dest_scan, src_color);
1025                blended = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
1026                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1027                dest_scan ++;
1028                src_scan ++;
1029            }
1030            dest_scan ++;
1031            src_scan += src_gap;
1032        }
1033    } else {
1034        for (int col = 0; col < width; col ++) {
1035            int src_alpha = *clip_scan ++;
1036            FX_BYTE back_alpha = *dest_alpha_scan;
1037            if (back_alpha == 0) {
1038                *dest_scan++ = *src_scan++;
1039                *dest_scan++ = *src_scan++;
1040                *dest_scan++ = *src_scan++;
1041                src_scan += src_gap;
1042                dest_alpha_scan++;
1043                continue;
1044            }
1045            if (src_alpha == 0) {
1046                dest_scan += 3;
1047                dest_alpha_scan++;
1048                src_scan += src_Bpp;
1049                continue;
1050            }
1051            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1052            *dest_alpha_scan++ = dest_alpha;
1053            int alpha_ratio = src_alpha * 255 / dest_alpha;
1054            if (bNonseparableBlend) {
1055                _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
1056            }
1057            for (int color = 0; color < 3; color ++) {
1058                int src_color = *src_scan;
1059                int blended = bNonseparableBlend ? blended_colors[color] :
1060                              _BLEND(blend_type, *dest_scan, src_color);
1061                blended = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
1062                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1063                dest_scan ++;
1064                src_scan ++;
1065            }
1066            src_scan += src_gap;
1067        }
1068    }
1069}
1070inline void _CompositeRow_Rgb2Argb_NoBlend_Clip(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int src_Bpp, FX_LPCBYTE clip_scan,
1071        FX_LPBYTE dest_alpha_scan)
1072{
1073    int src_gap = src_Bpp - 3;
1074    if (dest_alpha_scan == NULL) {
1075        for (int col = 0; col < width; col ++) {
1076            int src_alpha = clip_scan[col];
1077            if (src_alpha == 255) {
1078                *dest_scan++ = *src_scan++;
1079                *dest_scan++ = *src_scan++;
1080                *dest_scan++ = *src_scan++;
1081                *dest_scan++ = 255;
1082                src_scan += src_gap;
1083                continue;
1084            }
1085            if (src_alpha == 0) {
1086                dest_scan += 4;
1087                src_scan += src_Bpp;
1088                continue;
1089            }
1090            int back_alpha = dest_scan[3];
1091            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1092            dest_scan[3] = dest_alpha;
1093            int alpha_ratio = src_alpha * 255 / dest_alpha;
1094            for (int color = 0; color < 3; color ++) {
1095                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
1096                dest_scan ++;
1097                src_scan ++;
1098            }
1099            dest_scan ++;
1100            src_scan += src_gap;
1101        }
1102    } else {
1103        for (int col = 0; col < width; col ++) {
1104            int src_alpha = clip_scan[col];
1105            if (src_alpha == 255) {
1106                *dest_scan++ = *src_scan++;
1107                *dest_scan++ = *src_scan++;
1108                *dest_scan++ = *src_scan++;
1109                *dest_alpha_scan++ = 255;
1110                src_scan += src_gap;
1111                continue;
1112            }
1113            if (src_alpha == 0) {
1114                dest_scan += 3;
1115                dest_alpha_scan ++;
1116                src_scan += src_Bpp;
1117                continue;
1118            }
1119            int back_alpha = *dest_alpha_scan;
1120            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1121            *dest_alpha_scan ++ = dest_alpha;
1122            int alpha_ratio = src_alpha * 255 / dest_alpha;
1123            for (int color = 0; color < 3; color ++) {
1124                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
1125                dest_scan ++;
1126                src_scan ++;
1127            }
1128            src_scan += src_gap;
1129        }
1130    }
1131}
1132inline void _CompositeRow_Rgb2Argb_NoBlend_NoClip(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int src_Bpp,
1133        FX_LPBYTE dest_alpha_scan)
1134{
1135    if (dest_alpha_scan == NULL) {
1136        for (int col = 0; col < width; col ++) {
1137            if (src_Bpp == 4) {
1138                FXARGB_SETDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan));
1139            } else {
1140                FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[2], src_scan[1], src_scan[0]));
1141            }
1142            dest_scan += 4;
1143            src_scan += src_Bpp;
1144        }
1145    } else {
1146        int src_gap = src_Bpp - 3;
1147        for (int col = 0; col < width; col ++) {
1148            *dest_scan++ = *src_scan++;
1149            *dest_scan++ = *src_scan++;
1150            *dest_scan++ = *src_scan++;
1151            *dest_alpha_scan++ = 0xff;
1152            src_scan += src_gap;
1153        }
1154    }
1155}
1156inline void _CompositeRow_Argb2Rgb_Blend(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, FX_LPCBYTE clip_scan,
1157        FX_LPCBYTE src_alpha_scan)
1158{
1159    int blended_colors[3];
1160    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1161    int dest_gap = dest_Bpp - 3;
1162    if (src_alpha_scan == NULL) {
1163        for (int col = 0; col < width; col ++) {
1164            FX_BYTE src_alpha;
1165            if (clip_scan) {
1166                src_alpha = src_scan[3] * (*clip_scan++) / 255;
1167            } else {
1168                src_alpha = src_scan[3];
1169            }
1170            if (src_alpha == 0) {
1171                dest_scan += dest_Bpp;
1172                src_scan += 4;
1173                continue;
1174            }
1175            if (bNonseparableBlend) {
1176                _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
1177            }
1178            for (int color = 0; color < 3; color ++) {
1179                int back_color = *dest_scan;
1180                int blended = bNonseparableBlend ? blended_colors[color] :
1181                              _BLEND(blend_type, back_color, *src_scan);
1182                *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
1183                dest_scan ++;
1184                src_scan ++;
1185            }
1186            dest_scan += dest_gap;
1187            src_scan ++;
1188        }
1189    } else {
1190        for (int col = 0; col < width; col ++) {
1191            FX_BYTE src_alpha;
1192            if (clip_scan) {
1193                src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255;
1194            } else {
1195                src_alpha = *src_alpha_scan++;
1196            }
1197            if (src_alpha == 0) {
1198                dest_scan += dest_Bpp;
1199                src_scan += 3;
1200                continue;
1201            }
1202            if (bNonseparableBlend) {
1203                _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
1204            }
1205            for (int color = 0; color < 3; color ++) {
1206                int back_color = *dest_scan;
1207                int blended = bNonseparableBlend ? blended_colors[color] :
1208                              _BLEND(blend_type, back_color, *src_scan);
1209                *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
1210                dest_scan ++;
1211                src_scan ++;
1212            }
1213            dest_scan += dest_gap;
1214        }
1215    }
1216}
1217inline void _CompositeRow_Argb2Rgb_NoBlend(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, FX_LPCBYTE clip_scan,
1218        FX_LPCBYTE src_alpha_scan)
1219{
1220    int dest_gap = dest_Bpp - 3;
1221    if (src_alpha_scan == NULL) {
1222        for (int col = 0; col < width; col ++) {
1223            FX_BYTE src_alpha;
1224            if (clip_scan) {
1225                src_alpha = src_scan[3] * (*clip_scan++) / 255;
1226            } else {
1227                src_alpha = src_scan[3];
1228            }
1229            if (src_alpha == 255) {
1230                *dest_scan++ = *src_scan++;
1231                *dest_scan++ = *src_scan++;
1232                *dest_scan++ = *src_scan++;
1233                dest_scan += dest_gap;
1234                src_scan ++;
1235                continue;
1236            }
1237            if (src_alpha == 0) {
1238                dest_scan += dest_Bpp;
1239                src_scan += 4;
1240                continue;
1241            }
1242            for (int color = 0; color < 3; color ++) {
1243                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
1244                dest_scan ++;
1245                src_scan ++;
1246            }
1247            dest_scan += dest_gap;
1248            src_scan ++;
1249        }
1250    } else {
1251        for (int col = 0; col < width; col ++) {
1252            FX_BYTE src_alpha;
1253            if (clip_scan) {
1254                src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255;
1255            } else {
1256                src_alpha = *src_alpha_scan++;
1257            }
1258            if (src_alpha == 255) {
1259                *dest_scan++ = *src_scan++;
1260                *dest_scan++ = *src_scan++;
1261                *dest_scan++ = *src_scan++;
1262                dest_scan += dest_gap;
1263                continue;
1264            }
1265            if (src_alpha == 0) {
1266                dest_scan += dest_Bpp;
1267                src_scan += 3;
1268                continue;
1269            }
1270            for (int color = 0; color < 3; color ++) {
1271                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
1272                dest_scan ++;
1273                src_scan ++;
1274            }
1275            dest_scan += dest_gap;
1276        }
1277    }
1278}
1279inline void _CompositeRow_Rgb2Rgb_Blend_NoClip(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, int src_Bpp)
1280{
1281    int blended_colors[3];
1282    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1283    int dest_gap = dest_Bpp - 3;
1284    int src_gap = src_Bpp - 3;
1285    for (int col = 0; col < width; col ++) {
1286        if (bNonseparableBlend) {
1287            _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
1288        }
1289        for (int color = 0; color < 3; color ++) {
1290            int back_color = *dest_scan;
1291            int src_color = *src_scan;
1292            int blended = bNonseparableBlend ? blended_colors[color] :
1293                          _BLEND(blend_type, back_color, src_color);
1294            *dest_scan = blended;
1295            dest_scan ++;
1296            src_scan ++;
1297        }
1298        dest_scan += dest_gap;
1299        src_scan += src_gap;
1300    }
1301}
1302inline void _CompositeRow_Rgb2Rgb_Blend_Clip(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, int src_Bpp, FX_LPCBYTE clip_scan)
1303{
1304    int blended_colors[3];
1305    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1306    int dest_gap = dest_Bpp - 3;
1307    int src_gap = src_Bpp - 3;
1308    for (int col = 0; col < width; col ++) {
1309        FX_BYTE src_alpha = *clip_scan ++;
1310        if (src_alpha == 0) {
1311            dest_scan += dest_Bpp;
1312            src_scan += src_Bpp;
1313            continue;
1314        }
1315        if (bNonseparableBlend) {
1316            _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
1317        }
1318        for (int color = 0; color < 3; color ++) {
1319            int src_color = *src_scan;
1320            int back_color = *dest_scan;
1321            int blended = bNonseparableBlend ? blended_colors[color] :
1322                          _BLEND(blend_type, back_color, src_color);
1323            *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
1324            dest_scan ++;
1325            src_scan ++;
1326        }
1327        dest_scan += dest_gap;
1328        src_scan += src_gap;
1329    }
1330}
1331inline void _CompositeRow_Rgb2Rgb_NoBlend_NoClip(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, int src_Bpp)
1332{
1333    if (dest_Bpp == src_Bpp) {
1334        FXSYS_memcpy32(dest_scan, src_scan, width * dest_Bpp);
1335        return;
1336    }
1337    for (int col = 0; col < width; col ++) {
1338        dest_scan[0] = src_scan[0];
1339        dest_scan[1] = src_scan[1];
1340        dest_scan[2] = src_scan[2];
1341        dest_scan += dest_Bpp;
1342        src_scan += src_Bpp;
1343    }
1344}
1345inline void _CompositeRow_Rgb2Rgb_NoBlend_Clip(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, int src_Bpp, FX_LPCBYTE clip_scan)
1346{
1347    for (int col = 0; col < width; col ++) {
1348        int src_alpha = clip_scan[col];
1349        if (src_alpha == 255) {
1350            dest_scan[0] = src_scan[0];
1351            dest_scan[1] = src_scan[1];
1352            dest_scan[2] = src_scan[2];
1353        } else if (src_alpha) {
1354            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
1355            dest_scan ++;
1356            src_scan ++;
1357            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
1358            dest_scan ++;
1359            src_scan ++;
1360            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
1361            dest_scan += dest_Bpp - 2;
1362            src_scan += src_Bpp - 2;
1363            continue;
1364        }
1365        dest_scan += dest_Bpp;
1366        src_scan += src_Bpp;
1367    }
1368}
1369void _CompositeRow_Argb2Argb_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int pixel_count, int blend_type, FX_LPCBYTE clip_scan,
1370                                       FX_LPBYTE dest_alpha_scan, FX_LPCBYTE src_alpha_scan, FX_LPBYTE src_cache_scan, void* pIccTransform)
1371{
1372    FX_LPBYTE dp = src_cache_scan;
1373    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1374    if (src_alpha_scan) {
1375        if (dest_alpha_scan == NULL) {
1376            for (int col = 0; col < pixel_count; col ++) {
1377                pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1378                dp[3] = *src_alpha_scan++;
1379                src_scan += 3;
1380                dp += 4;
1381            }
1382            src_alpha_scan = NULL;
1383        } else {
1384            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, pixel_count);
1385        }
1386    } else {
1387        if (dest_alpha_scan == NULL) {
1388            for (int col = 0; col < pixel_count; col ++) {
1389                pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1390                dp[3] = src_scan[3];
1391                src_scan += 4;
1392                dp += 4;
1393            }
1394        } else {
1395            int blended_colors[3];
1396            FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1397            for (int col = 0; col < pixel_count; col ++) {
1398                pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, 1);
1399                FX_BYTE back_alpha = *dest_alpha_scan;
1400                if (back_alpha == 0) {
1401                    if (clip_scan) {
1402                        int src_alpha = clip_scan[col] * src_scan[3] / 255;
1403                        *dest_alpha_scan = src_alpha;
1404                        *dest_scan++ = *src_cache_scan++;
1405                        *dest_scan++ = *src_cache_scan++;
1406                        *dest_scan++ = *src_cache_scan++;
1407                    } else {
1408                        *dest_alpha_scan = src_scan[3];
1409                        *dest_scan++ = *src_cache_scan++;
1410                        *dest_scan++ = *src_cache_scan++;
1411                        *dest_scan++ = *src_cache_scan++;
1412                    }
1413                    dest_alpha_scan ++;
1414                    src_scan += 4;
1415                    continue;
1416                }
1417                FX_BYTE src_alpha;
1418                if (clip_scan == NULL) {
1419                    src_alpha = src_scan[3];
1420                } else {
1421                    src_alpha = clip_scan[col] * src_scan[3] / 255;
1422                }
1423                src_scan += 4;
1424                if (src_alpha == 0) {
1425                    dest_scan += 3;
1426                    src_cache_scan += 3;
1427                    dest_alpha_scan ++;
1428                    continue;
1429                }
1430                FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1431                *dest_alpha_scan ++ = dest_alpha;
1432                int alpha_ratio = src_alpha * 255 / dest_alpha;
1433                if (bNonseparableBlend) {
1434                    _RGB_Blend(blend_type, src_cache_scan, dest_scan, blended_colors);
1435                }
1436                for (int color = 0; color < 3; color ++) {
1437                    if (blend_type) {
1438                        int blended = bNonseparableBlend ? blended_colors[color] :
1439                                      _BLEND(blend_type, *dest_scan, *src_cache_scan);
1440                        blended = FXDIB_ALPHA_MERGE(*src_cache_scan, blended, back_alpha);
1441                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1442                    } else {
1443                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_cache_scan, alpha_ratio);
1444                    }
1445                    dest_scan ++;
1446                    src_cache_scan ++;
1447                }
1448            }
1449            return;
1450        }
1451    }
1452    _CompositeRow_Argb2Argb(dest_scan, src_cache_scan, pixel_count, blend_type, clip_scan, dest_alpha_scan, src_alpha_scan);
1453}
1454void _CompositeRow_Rgb2Argb_Blend_NoClip_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int src_Bpp,
1455        FX_LPBYTE dest_alpha_scan, FX_LPBYTE src_cache_scan, void* pIccTransform)
1456{
1457    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1458    if (src_Bpp == 3) {
1459        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1460    } else {
1461        FX_LPBYTE dp = src_cache_scan;
1462        for (int col = 0; col < width; col ++) {
1463            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1464            src_scan += 4;
1465            dp += 3;
1466        }
1467    }
1468    _CompositeRow_Rgb2Argb_Blend_NoClip(dest_scan, src_cache_scan, width, blend_type, 3, dest_alpha_scan);
1469}
1470inline void _CompositeRow_Rgb2Argb_Blend_Clip_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int src_Bpp, FX_LPCBYTE clip_scan,
1471        FX_LPBYTE dest_alpha_scan, FX_LPBYTE src_cache_scan, void* pIccTransform)
1472{
1473    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1474    if (src_Bpp == 3) {
1475        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1476    } else {
1477        FX_LPBYTE dp = src_cache_scan;
1478        for (int col = 0; col < width; col ++) {
1479            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1480            src_scan += 4;
1481            dp += 3;
1482        }
1483    }
1484    _CompositeRow_Rgb2Argb_Blend_Clip(dest_scan, src_cache_scan, width, blend_type, 3, clip_scan, dest_alpha_scan);
1485}
1486inline void _CompositeRow_Rgb2Argb_NoBlend_Clip_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int src_Bpp, FX_LPCBYTE clip_scan,
1487        FX_LPBYTE dest_alpha_scan, FX_LPBYTE src_cache_scan, void* pIccTransform)
1488{
1489    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1490    if (src_Bpp == 3) {
1491        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1492    } else {
1493        FX_LPBYTE dp = src_cache_scan;
1494        for (int col = 0; col < width; col ++) {
1495            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1496            src_scan += 4;
1497            dp += 3;
1498        }
1499    }
1500    _CompositeRow_Rgb2Argb_NoBlend_Clip(dest_scan, src_cache_scan, width, 3, clip_scan, dest_alpha_scan);
1501}
1502inline void _CompositeRow_Rgb2Argb_NoBlend_NoClip_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int src_Bpp,
1503        FX_LPBYTE dest_alpha_scan, FX_LPBYTE src_cache_scan, void* pIccTransform)
1504{
1505    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1506    if (src_Bpp == 3) {
1507        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1508    } else {
1509        FX_LPBYTE dp = src_cache_scan;
1510        for (int col = 0; col < width; col ++) {
1511            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1512            src_scan += 4;
1513            dp += 3;
1514        }
1515    }
1516    _CompositeRow_Rgb2Argb_NoBlend_NoClip(dest_scan, src_cache_scan, width, 3, dest_alpha_scan);
1517}
1518inline void _CompositeRow_Argb2Rgb_Blend_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, FX_LPCBYTE clip_scan,
1519        FX_LPCBYTE src_alpha_scan, FX_LPBYTE src_cache_scan, void* pIccTransform)
1520{
1521    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1522    if (src_alpha_scan) {
1523        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1524    } else {
1525        int blended_colors[3];
1526        FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1527        int dest_gap = dest_Bpp - 3;
1528        for (int col = 0; col < width; col ++) {
1529            pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, 1);
1530            FX_BYTE src_alpha;
1531            if (clip_scan) {
1532                src_alpha = src_scan[3] * (*clip_scan++) / 255;
1533            } else {
1534                src_alpha = src_scan[3];
1535            }
1536            src_scan += 4;
1537            if (src_alpha == 0) {
1538                dest_scan += dest_Bpp;
1539                src_cache_scan += 3;
1540                continue;
1541            }
1542            if (bNonseparableBlend) {
1543                _RGB_Blend(blend_type, src_cache_scan, dest_scan, blended_colors);
1544            }
1545            for (int color = 0; color < 3; color ++) {
1546                int back_color = *dest_scan;
1547                int blended = bNonseparableBlend ? blended_colors[color] :
1548                              _BLEND(blend_type, back_color, *src_cache_scan);
1549                *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
1550                dest_scan ++;
1551                src_cache_scan ++;
1552            }
1553            dest_scan += dest_gap;
1554        }
1555        return;
1556    }
1557    _CompositeRow_Argb2Rgb_Blend(dest_scan, src_cache_scan, width, blend_type, dest_Bpp, clip_scan, src_alpha_scan);
1558}
1559inline void _CompositeRow_Argb2Rgb_NoBlend_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, FX_LPCBYTE clip_scan,
1560        FX_LPCBYTE src_alpha_scan, FX_LPBYTE src_cache_scan, void* pIccTransform)
1561{
1562    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1563    if (src_alpha_scan) {
1564        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1565    } else {
1566        int dest_gap = dest_Bpp - 3;
1567        for (int col = 0; col < width; col ++) {
1568            pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, 1);
1569            FX_BYTE src_alpha;
1570            if (clip_scan) {
1571                src_alpha = src_scan[3] * (*clip_scan++) / 255;
1572            } else {
1573                src_alpha = src_scan[3];
1574            }
1575            src_scan += 4;
1576            if (src_alpha == 255) {
1577                *dest_scan++ = *src_cache_scan++;
1578                *dest_scan++ = *src_cache_scan++;
1579                *dest_scan++ = *src_cache_scan++;
1580                dest_scan += dest_gap;
1581                continue;
1582            }
1583            if (src_alpha == 0) {
1584                dest_scan += dest_Bpp;
1585                src_cache_scan += 3;
1586                continue;
1587            }
1588            for (int color = 0; color < 3; color ++) {
1589                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_cache_scan, src_alpha);
1590                dest_scan ++;
1591                src_cache_scan ++;
1592            }
1593            dest_scan += dest_gap;
1594        }
1595        return;
1596    }
1597    _CompositeRow_Argb2Rgb_NoBlend(dest_scan, src_cache_scan, width, dest_Bpp, clip_scan, src_alpha_scan);
1598}
1599inline void _CompositeRow_Rgb2Rgb_Blend_NoClip_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, int src_Bpp,
1600        FX_LPBYTE src_cache_scan, void* pIccTransform)
1601{
1602    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1603    if (src_Bpp == 3) {
1604        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1605    } else {
1606        FX_LPBYTE dp = src_cache_scan;
1607        for (int col = 0; col < width; col ++) {
1608            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1609            src_scan += 4;
1610            dp += 3;
1611        }
1612    }
1613    _CompositeRow_Rgb2Rgb_Blend_NoClip(dest_scan, src_cache_scan, width, blend_type, dest_Bpp, 3);
1614}
1615inline void _CompositeRow_Rgb2Rgb_Blend_Clip_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, int src_Bpp, FX_LPCBYTE clip_scan,
1616        FX_LPBYTE src_cache_scan, void* pIccTransform)
1617{
1618    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1619    if (src_Bpp == 3) {
1620        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1621    } else {
1622        FX_LPBYTE dp = src_cache_scan;
1623        for (int col = 0; col < width; col ++) {
1624            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1625            src_scan += 4;
1626            dp += 3;
1627        }
1628    }
1629    _CompositeRow_Rgb2Rgb_Blend_Clip(dest_scan, src_cache_scan, width, blend_type, dest_Bpp, 3, clip_scan);
1630}
1631inline void _CompositeRow_Rgb2Rgb_NoBlend_NoClip_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, int src_Bpp,
1632        FX_LPBYTE src_cache_scan, void* pIccTransform)
1633{
1634    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1635    if (src_Bpp == 3) {
1636        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1637    } else {
1638        FX_LPBYTE dp = src_cache_scan;
1639        for (int col = 0; col < width; col ++) {
1640            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1641            src_scan += 4;
1642            dp += 3;
1643        }
1644    }
1645    _CompositeRow_Rgb2Rgb_NoBlend_NoClip(dest_scan, src_cache_scan, width, dest_Bpp, 3);
1646}
1647inline void _CompositeRow_Rgb2Rgb_NoBlend_Clip_Transform(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, int src_Bpp, FX_LPCBYTE clip_scan,
1648        FX_LPBYTE src_cache_scan, void* pIccTransform)
1649{
1650    ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
1651    if (src_Bpp == 3) {
1652        pIccModule->TranslateScanline(pIccTransform, src_cache_scan, src_scan, width);
1653    } else {
1654        FX_LPBYTE dp = src_cache_scan;
1655        for (int col = 0; col < width; col ++) {
1656            pIccModule->TranslateScanline(pIccTransform, dp, src_scan, 1);
1657            src_scan += 4;
1658            dp += 3;
1659        }
1660    }
1661    _CompositeRow_Rgb2Rgb_NoBlend_Clip(dest_scan, src_cache_scan, width, dest_Bpp, 3, clip_scan);
1662}
1663inline void _CompositeRow_8bppPal2Gray(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, FX_LPCBYTE pPalette, int pixel_count,
1664                                       int blend_type, FX_LPCBYTE clip_scan,
1665                                       FX_LPCBYTE src_alpha_scan)
1666{
1667    if (src_alpha_scan) {
1668        if (blend_type) {
1669            FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1670            int blended_color;
1671            for (int col = 0; col < pixel_count; col ++) {
1672                FX_BYTE gray = pPalette[*src_scan];
1673                int src_alpha = *src_alpha_scan++;
1674                if (clip_scan) {
1675                    src_alpha = clip_scan[col] * src_alpha / 255;
1676                }
1677                if (bNonseparableBlend) {
1678                    blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1679                }
1680                gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
1681                if (src_alpha) {
1682                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
1683                } else {
1684                    *dest_scan = gray;
1685                }
1686                dest_scan ++;
1687                src_scan ++;
1688            }
1689            return;
1690        }
1691        for (int col = 0; col < pixel_count; col ++) {
1692            FX_BYTE gray = pPalette[*src_scan];
1693            int src_alpha = *src_alpha_scan++;
1694            if (clip_scan) {
1695                src_alpha = clip_scan[col] * src_alpha / 255;
1696            }
1697            if (src_alpha) {
1698                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
1699            } else {
1700                *dest_scan = gray;
1701            }
1702            dest_scan ++;
1703            src_scan ++;
1704        }
1705    } else {
1706        if (blend_type) {
1707            FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1708            int blended_color;
1709            for (int col = 0; col < pixel_count; col ++) {
1710                FX_BYTE gray = pPalette[*src_scan];
1711                if (bNonseparableBlend) {
1712                    blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1713                }
1714                gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
1715                if (clip_scan && clip_scan[col] < 255) {
1716                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
1717                } else {
1718                    *dest_scan = gray;
1719                }
1720                dest_scan ++;
1721                src_scan ++;
1722            }
1723            return;
1724        }
1725        for (int col = 0; col < pixel_count; col ++) {
1726            FX_BYTE gray = pPalette[*src_scan];
1727            if (clip_scan && clip_scan[col] < 255) {
1728                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
1729            } else {
1730                *dest_scan = gray;
1731            }
1732            dest_scan ++;
1733            src_scan ++;
1734        }
1735    }
1736}
1737inline void _CompositeRow_8bppPal2Graya(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, FX_LPCBYTE pPalette, int pixel_count,
1738                                        int blend_type, FX_LPCBYTE clip_scan,
1739                                        FX_LPBYTE dest_alpha_scan, FX_LPCBYTE src_alpha_scan)
1740{
1741    if (src_alpha_scan) {
1742        if (blend_type) {
1743            FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1744            int blended_color;
1745            for (int col = 0; col < pixel_count; col ++) {
1746                FX_BYTE gray = pPalette[*src_scan];
1747                src_scan ++;
1748                FX_BYTE back_alpha = *dest_alpha_scan;
1749                if (back_alpha == 0) {
1750                    int src_alpha = *src_alpha_scan ++;
1751                    if (clip_scan) {
1752                        src_alpha = clip_scan[col] * src_alpha / 255;
1753                    }
1754                    if (src_alpha) {
1755                        *dest_scan = gray;
1756                        *dest_alpha_scan = src_alpha;
1757                    }
1758                    dest_scan ++;
1759                    dest_alpha_scan ++;
1760                    continue;
1761                }
1762                FX_BYTE src_alpha = *src_alpha_scan++;
1763                if (clip_scan) {
1764                    src_alpha = clip_scan[col] * src_alpha / 255;
1765                }
1766                if (src_alpha == 0) {
1767                    dest_scan ++;
1768                    dest_alpha_scan ++;
1769                    continue;
1770                }
1771                *dest_alpha_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1772                int alpha_ratio = src_alpha * 255 / (*dest_alpha_scan);
1773                if (bNonseparableBlend) {
1774                    blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1775                }
1776                gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
1777                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1778                dest_alpha_scan ++;
1779                dest_scan ++;
1780            }
1781            return;
1782        }
1783        for (int col = 0; col < pixel_count; col ++) {
1784            FX_BYTE gray = pPalette[*src_scan];
1785            src_scan ++;
1786            FX_BYTE back_alpha = *dest_alpha_scan;
1787            if (back_alpha == 0) {
1788                int src_alpha = *src_alpha_scan ++;
1789                if (clip_scan) {
1790                    src_alpha = clip_scan[col] * src_alpha / 255;
1791                }
1792                if (src_alpha) {
1793                    *dest_scan = gray;
1794                    *dest_alpha_scan = src_alpha;
1795                }
1796                dest_scan ++;
1797                dest_alpha_scan ++;
1798                continue;
1799            }
1800            FX_BYTE src_alpha = *src_alpha_scan++;
1801            if (clip_scan) {
1802                src_alpha = clip_scan[col] * src_alpha / 255;
1803            }
1804            if (src_alpha == 0) {
1805                dest_scan ++;
1806                dest_alpha_scan ++;
1807                continue;
1808            }
1809            *dest_alpha_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1810            int alpha_ratio = src_alpha * 255 / (*dest_alpha_scan);
1811            dest_alpha_scan ++;
1812            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1813            dest_scan ++;
1814        }
1815    } else {
1816        if (blend_type) {
1817            FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1818            int blended_color;
1819            for (int col = 0; col < pixel_count; col ++) {
1820                FX_BYTE gray = pPalette[*src_scan];
1821                src_scan ++;
1822                if (clip_scan == NULL || clip_scan[col] == 255) {
1823                    *dest_scan++ = gray;
1824                    *dest_alpha_scan++ = 255;
1825                    continue;
1826                }
1827                int src_alpha = clip_scan[col];
1828                if (src_alpha == 0) {
1829                    dest_scan ++;
1830                    dest_alpha_scan ++;
1831                    continue;
1832                }
1833                int back_alpha = *dest_alpha_scan;
1834                FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1835                *dest_alpha_scan ++ = dest_alpha;
1836                int alpha_ratio = src_alpha * 255 / dest_alpha;
1837                if (bNonseparableBlend) {
1838                    blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1839                }
1840                gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
1841                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1842                dest_scan ++;
1843            }
1844            return;
1845        }
1846        for (int col = 0; col < pixel_count; col ++) {
1847            FX_BYTE gray = pPalette[*src_scan];
1848            src_scan ++;
1849            if (clip_scan == NULL || clip_scan[col] == 255) {
1850                *dest_scan++ = gray;
1851                *dest_alpha_scan++ = 255;
1852                continue;
1853            }
1854            int src_alpha = clip_scan[col];
1855            if (src_alpha == 0) {
1856                dest_scan ++;
1857                dest_alpha_scan ++;
1858                continue;
1859            }
1860            int back_alpha = *dest_alpha_scan;
1861            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1862            *dest_alpha_scan ++ = dest_alpha;
1863            int alpha_ratio = src_alpha * 255 / dest_alpha;
1864            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1865            dest_scan ++;
1866        }
1867    }
1868}
1869inline void _CompositeRow_1bppPal2Gray(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left,
1870                                       FX_LPCBYTE pPalette, int pixel_count, int blend_type, FX_LPCBYTE clip_scan)
1871{
1872    int reset_gray = pPalette[0];
1873    int set_gray = pPalette[1];
1874    if (blend_type) {
1875        FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1876        int blended_color;
1877        for (int col = 0; col < pixel_count; col ++) {
1878            FX_BYTE gray = (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) ? set_gray : reset_gray;
1879            if (bNonseparableBlend) {
1880                blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1881            }
1882            gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
1883            if (clip_scan && clip_scan[col] < 255) {
1884                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
1885            } else {
1886                *dest_scan = gray;
1887            }
1888            dest_scan ++;
1889        }
1890        return;
1891    }
1892    for (int col = 0; col < pixel_count; col ++) {
1893        FX_BYTE gray = (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) ? set_gray : reset_gray;
1894        if (clip_scan && clip_scan[col] < 255) {
1895            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
1896        } else {
1897            *dest_scan = gray;
1898        }
1899        dest_scan ++;
1900    }
1901}
1902inline void _CompositeRow_1bppPal2Graya(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left,
1903                                        FX_LPCBYTE pPalette, int pixel_count, int blend_type, FX_LPCBYTE clip_scan,
1904                                        FX_LPBYTE dest_alpha_scan)
1905{
1906    int reset_gray = pPalette[0];
1907    int set_gray = pPalette[1];
1908    if (blend_type) {
1909        FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1910        int blended_color;
1911        for (int col = 0; col < pixel_count; col ++) {
1912            FX_BYTE gray = (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) ? set_gray : reset_gray;
1913            if (clip_scan == NULL || clip_scan[col] == 255) {
1914                *dest_scan++ = gray;
1915                *dest_alpha_scan ++ = 255;
1916                continue;
1917            }
1918            int src_alpha = clip_scan[col];
1919            if (src_alpha == 0) {
1920                dest_scan ++;
1921                dest_alpha_scan ++;
1922                continue;
1923            }
1924            int back_alpha = *dest_alpha_scan;
1925            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1926            *dest_alpha_scan ++ = dest_alpha;
1927            int alpha_ratio = src_alpha * 255 / dest_alpha;
1928            if (bNonseparableBlend) {
1929                blended_color = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1930            }
1931            gray = bNonseparableBlend ? blended_color : _BLEND(blend_type, *dest_scan, gray);
1932            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1933            dest_scan ++;
1934        }
1935        return;
1936    }
1937    for (int col = 0; col < pixel_count; col ++) {
1938        FX_BYTE gray = (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) ? set_gray : reset_gray;
1939        if (clip_scan == NULL || clip_scan[col] == 255) {
1940            *dest_scan++ = gray;
1941            *dest_alpha_scan ++ = 255;
1942            continue;
1943        }
1944        int src_alpha = clip_scan[col];
1945        if (src_alpha == 0) {
1946            dest_scan ++;
1947            dest_alpha_scan ++;
1948            continue;
1949        }
1950        int back_alpha = *dest_alpha_scan;
1951        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1952        *dest_alpha_scan ++ = dest_alpha;
1953        int alpha_ratio = src_alpha * 255 / dest_alpha;
1954        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1955        dest_scan ++;
1956    }
1957}
1958inline void _CompositeRow_8bppRgb2Rgb_NoBlend(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, FX_DWORD* pPalette, int pixel_count,
1959        int DestBpp, FX_LPCBYTE clip_scan,
1960        FX_LPCBYTE src_alpha_scan)
1961{
1962    if (src_alpha_scan) {
1963        int dest_gap = DestBpp - 3;
1964        FX_ARGB argb = 0;
1965        for (int col = 0; col < pixel_count; col ++) {
1966            argb = pPalette[*src_scan];
1967            int src_r = FXARGB_R(argb);
1968            int src_g = FXARGB_G(argb);
1969            int src_b = FXARGB_B(argb);
1970            src_scan ++;
1971            FX_BYTE src_alpha = 0;
1972            if (clip_scan) {
1973                src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255;
1974            } else {
1975                src_alpha = *src_alpha_scan++;
1976            }
1977            if (src_alpha == 255) {
1978                *dest_scan++ = src_b;
1979                *dest_scan++ = src_g;
1980                *dest_scan++ = src_r;
1981                dest_scan += dest_gap;
1982                continue;
1983            }
1984            if (src_alpha == 0) {
1985                dest_scan += DestBpp;
1986                continue;
1987            }
1988            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha);
1989            dest_scan ++;
1990            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha);
1991            dest_scan ++;
1992            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha);
1993            dest_scan ++;
1994            dest_scan += dest_gap;
1995        }
1996    } else {
1997        FX_ARGB argb = 0;
1998        for (int col = 0; col < pixel_count; col ++) {
1999            argb = pPalette[*src_scan];
2000            int src_r = FXARGB_R(argb);
2001            int src_g = FXARGB_G(argb);
2002            int src_b = FXARGB_B(argb);
2003            if (clip_scan && clip_scan[col] < 255) {
2004                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, clip_scan[col]);
2005                dest_scan ++;
2006                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, clip_scan[col]);
2007                dest_scan ++;
2008                *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, clip_scan[col]);
2009                dest_scan ++;
2010            } else {
2011                *dest_scan++ = src_b;
2012                *dest_scan++ = src_g;
2013                *dest_scan++ = src_r;
2014            }
2015            if (DestBpp == 4) {
2016                dest_scan++;
2017            }
2018            src_scan ++;
2019        }
2020    }
2021}
2022inline void _CompositeRow_1bppRgb2Rgb_NoBlend(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left,
2023        FX_DWORD* pPalette, int pixel_count, int DestBpp, FX_LPCBYTE clip_scan)
2024{
2025    int reset_r, reset_g, reset_b;
2026    int set_r, set_g, set_b;
2027    reset_r = FXARGB_R(pPalette[0]);
2028    reset_g = FXARGB_G(pPalette[0]);
2029    reset_b = FXARGB_B(pPalette[0]);
2030    set_r = FXARGB_R(pPalette[1]);
2031    set_g = FXARGB_G(pPalette[1]);
2032    set_b = FXARGB_B(pPalette[1]);
2033    for (int col = 0; col < pixel_count; col ++) {
2034        int src_r, src_g, src_b;
2035        if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
2036            src_r = set_r;
2037            src_g = set_g;
2038            src_b = set_b;
2039        } else {
2040            src_r = reset_r;
2041            src_g = reset_g;
2042            src_b = reset_b;
2043        }
2044        if (clip_scan && clip_scan[col] < 255) {
2045            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, clip_scan[col]);
2046            dest_scan ++;
2047            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, clip_scan[col]);
2048            dest_scan ++;
2049            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, clip_scan[col]);
2050            dest_scan ++;
2051        } else {
2052            *dest_scan++ = src_b;
2053            *dest_scan++ = src_g;
2054            *dest_scan++ = src_r;
2055        }
2056        if (DestBpp == 4) {
2057            dest_scan++;
2058        }
2059    }
2060}
2061inline void _CompositeRow_8bppRgb2Argb_NoBlend(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width,
2062        FX_DWORD* pPalette, FX_LPCBYTE clip_scan,
2063        FX_LPCBYTE src_alpha_scan)
2064{
2065    if (src_alpha_scan) {
2066        for (int col = 0; col < width; col ++) {
2067            FX_ARGB argb = pPalette[*src_scan];
2068            src_scan ++;
2069            int src_r = FXARGB_R(argb);
2070            int src_g = FXARGB_G(argb);
2071            int src_b = FXARGB_B(argb);
2072            FX_BYTE back_alpha = dest_scan[3];
2073            if (back_alpha == 0) {
2074                if (clip_scan) {
2075                    int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255;
2076                    FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
2077                } else {
2078                    FXARGB_SETDIB(dest_scan, FXARGB_MAKE(*src_alpha_scan, src_r, src_g, src_b));
2079                }
2080                dest_scan += 4;
2081                src_alpha_scan ++;
2082                continue;
2083            }
2084            FX_BYTE src_alpha;
2085            if (clip_scan == NULL) {
2086                src_alpha = *src_alpha_scan ++;
2087            } else {
2088                src_alpha = clip_scan[col] * (*src_alpha_scan++) / 255;
2089            }
2090            if (src_alpha == 0) {
2091                dest_scan += 4;
2092                continue;
2093            }
2094            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2095            dest_scan[3] = dest_alpha;
2096            int alpha_ratio = src_alpha * 255 / dest_alpha;
2097            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2098            dest_scan ++;
2099            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2100            dest_scan ++;
2101            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2102            dest_scan ++;
2103            dest_scan ++;
2104        }
2105    } else
2106        for (int col = 0; col < width; col ++) {
2107            FX_ARGB argb = pPalette[*src_scan];
2108            int src_r = FXARGB_R(argb);
2109            int src_g = FXARGB_G(argb);
2110            int src_b = FXARGB_B(argb);
2111            if (clip_scan == NULL || clip_scan[col] == 255) {
2112                *dest_scan++ = src_b;
2113                *dest_scan++ = src_g;
2114                *dest_scan++ = src_r;
2115                *dest_scan++ = 255;
2116                src_scan ++;
2117                continue;
2118            }
2119            int src_alpha = clip_scan[col];
2120            if (src_alpha == 0) {
2121                dest_scan += 4;
2122                src_scan ++;
2123                continue;
2124            }
2125            int back_alpha = dest_scan[3];
2126            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2127            dest_scan[3] = dest_alpha;
2128            int alpha_ratio = src_alpha * 255 / dest_alpha;
2129            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2130            dest_scan ++;
2131            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2132            dest_scan ++;
2133            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2134            dest_scan ++;
2135            dest_scan ++;
2136            src_scan ++;
2137        }
2138}
2139void _CompositeRow_8bppRgb2Rgba_NoBlend(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width,
2140                                        FX_DWORD* pPalette, FX_LPCBYTE clip_scan,
2141                                        FX_LPBYTE dest_alpha_scan, FX_LPCBYTE src_alpha_scan)
2142{
2143    if (src_alpha_scan) {
2144        for (int col = 0; col < width; col ++) {
2145            FX_ARGB argb = pPalette[*src_scan];
2146            src_scan ++;
2147            int src_r = FXARGB_R(argb);
2148            int src_g = FXARGB_G(argb);
2149            int src_b = FXARGB_B(argb);
2150            FX_BYTE back_alpha = *dest_alpha_scan;
2151            if (back_alpha == 0) {
2152                if (clip_scan) {
2153                    int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255;
2154                    *dest_alpha_scan ++ = src_alpha;
2155                } else {
2156                    *dest_alpha_scan ++ = *src_alpha_scan;
2157                }
2158                *dest_scan ++ = src_b;
2159                *dest_scan ++ = src_g;
2160                *dest_scan ++ = src_r;
2161                src_alpha_scan ++;
2162                continue;
2163            }
2164            FX_BYTE src_alpha;
2165            if (clip_scan == NULL) {
2166                src_alpha = *src_alpha_scan++;
2167            } else {
2168                src_alpha = clip_scan[col] * (*src_alpha_scan++) / 255;
2169            }
2170            if (src_alpha == 0) {
2171                dest_scan += 3;
2172                dest_alpha_scan ++;
2173                continue;
2174            }
2175            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2176            *dest_alpha_scan ++ = dest_alpha;
2177            int alpha_ratio = src_alpha * 255 / dest_alpha;
2178            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2179            dest_scan ++;
2180            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2181            dest_scan ++;
2182            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2183            dest_scan ++;
2184        }
2185    } else
2186        for (int col = 0; col < width; col ++) {
2187            FX_ARGB argb = pPalette[*src_scan];
2188            int src_r = FXARGB_R(argb);
2189            int src_g = FXARGB_G(argb);
2190            int src_b = FXARGB_B(argb);
2191            if (clip_scan == NULL || clip_scan[col] == 255) {
2192                *dest_scan++ = src_b;
2193                *dest_scan++ = src_g;
2194                *dest_scan++ = src_r;
2195                *dest_alpha_scan++ = 255;
2196                src_scan ++;
2197                continue;
2198            }
2199            int src_alpha = clip_scan[col];
2200            if (src_alpha == 0) {
2201                dest_scan += 3;
2202                dest_alpha_scan ++;
2203                src_scan ++;
2204                continue;
2205            }
2206            int back_alpha = *dest_alpha_scan;
2207            FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2208            *dest_alpha_scan ++ = dest_alpha;
2209            int alpha_ratio = src_alpha * 255 / dest_alpha;
2210            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2211            dest_scan ++;
2212            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2213            dest_scan ++;
2214            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2215            dest_scan ++;
2216            src_scan ++;
2217        }
2218}
2219inline void _CompositeRow_1bppRgb2Argb_NoBlend(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width,
2220        FX_DWORD* pPalette, FX_LPCBYTE clip_scan)
2221{
2222    int reset_r, reset_g, reset_b;
2223    int set_r, set_g, set_b;
2224    reset_r = FXARGB_R(pPalette[0]);
2225    reset_g = FXARGB_G(pPalette[0]);
2226    reset_b = FXARGB_B(pPalette[0]);
2227    set_r = FXARGB_R(pPalette[1]);
2228    set_g = FXARGB_G(pPalette[1]);
2229    set_b = FXARGB_B(pPalette[1]);
2230    for (int col = 0; col < width; col ++) {
2231        int src_r, src_g, src_b;
2232        if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
2233            src_r = set_r;
2234            src_g = set_g;
2235            src_b = set_b;
2236        } else {
2237            src_r = reset_r;
2238            src_g = reset_g;
2239            src_b = reset_b;
2240        }
2241        if (clip_scan == NULL || clip_scan[col] == 255) {
2242            *dest_scan++ = src_b;
2243            *dest_scan++ = src_g;
2244            *dest_scan++ = src_r;
2245            *dest_scan++ = 255;
2246            continue;
2247        }
2248        int src_alpha = clip_scan[col];
2249        if (src_alpha == 0) {
2250            dest_scan += 4;
2251            continue;
2252        }
2253        int back_alpha = dest_scan[3];
2254        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2255        dest_scan[3] = dest_alpha;
2256        int alpha_ratio = src_alpha * 255 / dest_alpha;
2257        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2258        dest_scan ++;
2259        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2260        dest_scan ++;
2261        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2262        dest_scan ++;
2263        dest_scan ++;
2264    }
2265}
2266void _CompositeRow_1bppRgb2Rgba_NoBlend(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width,
2267                                        FX_DWORD* pPalette, FX_LPCBYTE clip_scan,
2268                                        FX_LPBYTE dest_alpha_scan)
2269{
2270    int reset_r, reset_g, reset_b;
2271    int set_r, set_g, set_b;
2272    reset_r = FXARGB_R(pPalette[0]);
2273    reset_g = FXARGB_G(pPalette[0]);
2274    reset_b = FXARGB_B(pPalette[0]);
2275    set_r = FXARGB_R(pPalette[1]);
2276    set_g = FXARGB_G(pPalette[1]);
2277    set_b = FXARGB_B(pPalette[1]);
2278    for (int col = 0; col < width; col ++) {
2279        int src_r, src_g, src_b;
2280        if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
2281            src_r = set_r;
2282            src_g = set_g;
2283            src_b = set_b;
2284        } else {
2285            src_r = reset_r;
2286            src_g = reset_g;
2287            src_b = reset_b;
2288        }
2289        if (clip_scan == NULL || clip_scan[col] == 255) {
2290            *dest_scan++ = src_b;
2291            *dest_scan++ = src_g;
2292            *dest_scan++ = src_r;
2293            *dest_alpha_scan++ = 255;
2294            continue;
2295        }
2296        int src_alpha = clip_scan[col];
2297        if (src_alpha == 0) {
2298            dest_scan += 3;
2299            dest_alpha_scan ++;
2300            continue;
2301        }
2302        int back_alpha = *dest_alpha_scan;
2303        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2304        *dest_alpha_scan ++ = dest_alpha;
2305        int alpha_ratio = src_alpha * 255 / dest_alpha;
2306        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2307        dest_scan ++;
2308        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2309        dest_scan ++;
2310        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2311        dest_scan ++;
2312    }
2313}
2314void _CompositeRow_ByteMask2Argb(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b, int pixel_count,
2315                                 int blend_type, FX_LPCBYTE clip_scan)
2316{
2317    for (int col = 0; col < pixel_count; col ++) {
2318        int src_alpha;
2319        if (clip_scan) {
2320            src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
2321        } else {
2322            src_alpha = mask_alpha * src_scan[col] / 255;
2323        }
2324        FX_BYTE back_alpha = dest_scan[3];
2325        if (back_alpha == 0) {
2326            FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
2327            dest_scan += 4;
2328            continue;
2329        }
2330        if (src_alpha == 0) {
2331            dest_scan += 4;
2332            continue;
2333        }
2334        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2335        dest_scan[3] = dest_alpha;
2336        int alpha_ratio = src_alpha * 255 / dest_alpha;
2337        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2338            int blended_colors[3];
2339            FX_BYTE src_scan[3];
2340            src_scan[0] = src_b;
2341            src_scan[1] = src_g;
2342            src_scan[2] = src_r;
2343            _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
2344            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio);
2345            dest_scan ++;
2346            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio);
2347            dest_scan ++;
2348            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio);
2349        } else if (blend_type) {
2350            int blended = _BLEND(blend_type, *dest_scan, src_b);
2351            blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
2352            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2353            dest_scan ++;
2354            blended = _BLEND(blend_type, *dest_scan, src_g);
2355            blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
2356            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2357            dest_scan ++;
2358            blended = _BLEND(blend_type, *dest_scan, src_r);
2359            blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
2360            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2361        } else {
2362            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2363            dest_scan ++;
2364            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2365            dest_scan ++;
2366            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2367        }
2368        dest_scan += 2;
2369    }
2370}
2371void _CompositeRow_ByteMask2Rgba(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b, int pixel_count,
2372                                 int blend_type, FX_LPCBYTE clip_scan,
2373                                 FX_LPBYTE dest_alpha_scan)
2374{
2375    for (int col = 0; col < pixel_count; col ++) {
2376        int src_alpha;
2377        if (clip_scan) {
2378            src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
2379        } else {
2380            src_alpha = mask_alpha * src_scan[col] / 255;
2381        }
2382        FX_BYTE back_alpha = *dest_alpha_scan;
2383        if (back_alpha == 0) {
2384            *dest_scan ++ = src_b;
2385            *dest_scan ++ = src_g;
2386            *dest_scan ++ = src_r;
2387            *dest_alpha_scan ++ = src_alpha;
2388            continue;
2389        }
2390        if (src_alpha == 0) {
2391            dest_scan += 3;
2392            dest_alpha_scan ++;
2393            continue;
2394        }
2395        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2396        *dest_alpha_scan ++ = dest_alpha;
2397        int alpha_ratio = src_alpha * 255 / dest_alpha;
2398        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2399            int blended_colors[3];
2400            FX_BYTE src_scan[3];
2401            src_scan[0] = src_b;
2402            src_scan[1] = src_g;
2403            src_scan[2] = src_r;
2404            _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
2405            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio);
2406            dest_scan ++;
2407            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio);
2408            dest_scan ++;
2409            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio);
2410            dest_scan ++;
2411        } else if (blend_type) {
2412            int blended = _BLEND(blend_type, *dest_scan, src_b);
2413            blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
2414            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2415            dest_scan ++;
2416            blended = _BLEND(blend_type, *dest_scan, src_g);
2417            blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
2418            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2419            dest_scan ++;
2420            blended = _BLEND(blend_type, *dest_scan, src_r);
2421            blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
2422            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2423            dest_scan ++;
2424        } else {
2425            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2426            dest_scan ++;
2427            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2428            dest_scan ++;
2429            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2430            dest_scan ++;
2431        }
2432    }
2433}
2434void _CompositeRow_ByteMask2Rgb(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b, int pixel_count,
2435                                int blend_type, int Bpp, FX_LPCBYTE clip_scan)
2436{
2437    for (int col = 0; col < pixel_count; col ++) {
2438        int src_alpha;
2439        if (clip_scan) {
2440            src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
2441        } else {
2442            src_alpha = mask_alpha * src_scan[col] / 255;
2443        }
2444        if (src_alpha == 0) {
2445            dest_scan += Bpp;
2446            continue;
2447        }
2448        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2449            int blended_colors[3];
2450            FX_BYTE src_scan[3];
2451            src_scan[0] = src_b;
2452            src_scan[1] = src_g;
2453            src_scan[2] = src_r;
2454            _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
2455            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], src_alpha);
2456            dest_scan ++;
2457            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], src_alpha);
2458            dest_scan ++;
2459            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], src_alpha);
2460        } else if (blend_type) {
2461            int blended = _BLEND(blend_type, *dest_scan, src_b);
2462            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
2463            dest_scan ++;
2464            blended = _BLEND(blend_type, *dest_scan, src_g);
2465            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
2466            dest_scan ++;
2467            blended = _BLEND(blend_type, *dest_scan, src_r);
2468            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
2469        } else {
2470            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha);
2471            dest_scan ++;
2472            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha);
2473            dest_scan ++;
2474            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha);
2475        }
2476        dest_scan += Bpp - 2;
2477    }
2478}
2479void _CompositeRow_ByteMask2Mask(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int pixel_count,
2480                                 FX_LPCBYTE clip_scan)
2481{
2482    for (int col = 0; col < pixel_count; col ++) {
2483        int src_alpha;
2484        if (clip_scan) {
2485            src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
2486        } else {
2487            src_alpha = mask_alpha * src_scan[col] / 255;
2488        }
2489        FX_BYTE back_alpha = *dest_scan;
2490        if (!back_alpha) {
2491            *dest_scan = src_alpha;
2492        } else if (src_alpha) {
2493            *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2494        }
2495        dest_scan ++;
2496    }
2497}
2498void _CompositeRow_ByteMask2Gray(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_gray,
2499                                 int pixel_count, FX_LPCBYTE clip_scan)
2500{
2501    for (int col = 0; col < pixel_count; col ++) {
2502        int src_alpha;
2503        if (clip_scan) {
2504            src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
2505        } else {
2506            src_alpha = mask_alpha * src_scan[col] / 255;
2507        }
2508        if (src_alpha) {
2509            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, src_alpha);
2510        }
2511        dest_scan ++;
2512    }
2513}
2514void _CompositeRow_ByteMask2Graya(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_gray,
2515                                  int pixel_count, FX_LPCBYTE clip_scan,
2516                                  FX_LPBYTE dest_alpha_scan)
2517{
2518    for (int col = 0; col < pixel_count; col ++) {
2519        int src_alpha;
2520        if (clip_scan) {
2521            src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
2522        } else {
2523            src_alpha = mask_alpha * src_scan[col] / 255;
2524        }
2525        FX_BYTE back_alpha = *dest_alpha_scan;
2526        if (back_alpha == 0) {
2527            *dest_scan ++ = src_gray;
2528            *dest_alpha_scan ++ = src_alpha;
2529            continue;
2530        }
2531        if (src_alpha == 0) {
2532            dest_scan ++;
2533            dest_alpha_scan ++;
2534            continue;
2535        }
2536        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2537        *dest_alpha_scan++ = dest_alpha;
2538        int alpha_ratio = src_alpha * 255 / dest_alpha;
2539        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, alpha_ratio);
2540        dest_scan ++;
2541    }
2542}
2543void _CompositeRow_BitMask2Argb(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b,
2544                                int src_left, int pixel_count, int blend_type, FX_LPCBYTE clip_scan)
2545{
2546    if (blend_type == FXDIB_BLEND_NORMAL && clip_scan == NULL && mask_alpha == 255) {
2547        FX_ARGB argb = FXARGB_MAKE(0xff, src_r, src_g, src_b);
2548        for (int col = 0; col < pixel_count; col ++) {
2549            if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
2550                FXARGB_SETDIB(dest_scan, argb);
2551            }
2552            dest_scan += 4;
2553        }
2554        return;
2555    }
2556    for (int col = 0; col < pixel_count; col ++) {
2557        if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
2558            dest_scan += 4;
2559            continue;
2560        }
2561        int src_alpha;
2562        if (clip_scan) {
2563            src_alpha = mask_alpha * clip_scan[col] / 255;
2564        } else {
2565            src_alpha = mask_alpha;
2566        }
2567        FX_BYTE back_alpha = dest_scan[3];
2568        if (back_alpha == 0) {
2569            FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
2570            dest_scan += 4;
2571            continue;
2572        }
2573        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2574        dest_scan[3] = dest_alpha;
2575        int alpha_ratio = src_alpha * 255 / dest_alpha;
2576        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2577            int blended_colors[3];
2578            FX_BYTE src_scan[3];
2579            src_scan[0] = src_b;
2580            src_scan[1] = src_g;
2581            src_scan[2] = src_r;
2582            _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
2583            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio);
2584            dest_scan ++;
2585            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio);
2586            dest_scan ++;
2587            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio);
2588        } else if (blend_type) {
2589            int blended = _BLEND(blend_type, *dest_scan, src_b);
2590            blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
2591            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2592            dest_scan ++;
2593            blended = _BLEND(blend_type, *dest_scan, src_g);
2594            blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
2595            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2596            dest_scan ++;
2597            blended = _BLEND(blend_type, *dest_scan, src_r);
2598            blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
2599            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2600        } else {
2601            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2602            dest_scan ++;
2603            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2604            dest_scan ++;
2605            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2606        }
2607        dest_scan += 2;
2608    }
2609}
2610void _CompositeRow_BitMask2Rgba(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b,
2611                                int src_left, int pixel_count, int blend_type, FX_LPCBYTE clip_scan,
2612                                FX_LPBYTE dest_alpha_scan)
2613{
2614    if (blend_type == FXDIB_BLEND_NORMAL && clip_scan == NULL && mask_alpha == 255) {
2615        for (int col = 0; col < pixel_count; col ++) {
2616            if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
2617                dest_scan[0] = src_b;
2618                dest_scan[1] = src_g;
2619                dest_scan[2] = src_r;
2620                *dest_alpha_scan = mask_alpha;
2621            }
2622            dest_scan += 3;
2623            dest_alpha_scan ++;
2624        }
2625        return;
2626    }
2627    for (int col = 0; col < pixel_count; col ++) {
2628        if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
2629            dest_scan += 3;
2630            dest_alpha_scan ++;
2631            continue;
2632        }
2633        int src_alpha;
2634        if (clip_scan) {
2635            src_alpha = mask_alpha * clip_scan[col] / 255;
2636        } else {
2637            src_alpha = mask_alpha;
2638        }
2639        FX_BYTE back_alpha = dest_scan[3];
2640        if (back_alpha == 0) {
2641            *dest_scan ++ = src_b;
2642            *dest_scan ++ = src_g;
2643            *dest_scan ++ = src_r;
2644            *dest_alpha_scan ++ = mask_alpha;
2645            continue;
2646        }
2647        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2648        *dest_alpha_scan ++ = dest_alpha;
2649        int alpha_ratio = src_alpha * 255 / dest_alpha;
2650        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2651            int blended_colors[3];
2652            FX_BYTE src_scan[3];
2653            src_scan[0] = src_b;
2654            src_scan[1] = src_g;
2655            src_scan[2] = src_r;
2656            _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
2657            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio);
2658            dest_scan ++;
2659            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio);
2660            dest_scan ++;
2661            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio);
2662            dest_scan ++;
2663        } else if (blend_type) {
2664            int blended = _BLEND(blend_type, *dest_scan, src_b);
2665            blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
2666            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2667            dest_scan ++;
2668            blended = _BLEND(blend_type, *dest_scan, src_g);
2669            blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
2670            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2671            dest_scan ++;
2672            blended = _BLEND(blend_type, *dest_scan, src_r);
2673            blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
2674            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
2675            dest_scan ++;
2676        } else {
2677            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
2678            dest_scan ++;
2679            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
2680            dest_scan ++;
2681            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
2682            dest_scan ++;
2683        }
2684    }
2685}
2686void _CompositeRow_BitMask2Rgb(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b,
2687                               int src_left, int pixel_count, int blend_type, int Bpp, FX_LPCBYTE clip_scan)
2688{
2689    if (blend_type == FXDIB_BLEND_NORMAL && clip_scan == NULL && mask_alpha == 255) {
2690        for (int col = 0; col < pixel_count; col ++) {
2691            if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
2692                dest_scan[2] = src_r;
2693                dest_scan[1] = src_g;
2694                dest_scan[0] = src_b;
2695            }
2696            dest_scan += Bpp;
2697        }
2698        return;
2699    }
2700    for (int col = 0; col < pixel_count; col ++) {
2701        if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
2702            dest_scan += Bpp;
2703            continue;
2704        }
2705        int src_alpha;
2706        if (clip_scan) {
2707            src_alpha = mask_alpha * clip_scan[col] / 255;
2708        } else {
2709            src_alpha = mask_alpha;
2710        }
2711        if (src_alpha == 0) {
2712            dest_scan += Bpp;
2713            continue;
2714        }
2715        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2716            int blended_colors[3];
2717            FX_BYTE src_scan[3];
2718            src_scan[0] = src_b;
2719            src_scan[1] = src_g;
2720            src_scan[2] = src_r;
2721            _RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
2722            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], src_alpha);
2723            dest_scan ++;
2724            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], src_alpha);
2725            dest_scan ++;
2726            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], src_alpha);
2727        } else if (blend_type) {
2728            int blended = _BLEND(blend_type, *dest_scan, src_b);
2729            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
2730            dest_scan++;
2731            blended = _BLEND(blend_type, *dest_scan, src_g);
2732            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
2733            dest_scan++;
2734            blended = _BLEND(blend_type, *dest_scan, src_r);
2735            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
2736        } else {
2737            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha);
2738            dest_scan ++;
2739            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha);
2740            dest_scan ++;
2741            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha);
2742        }
2743        dest_scan += Bpp - 2;
2744    }
2745}
2746void _CompositeRow_BitMask2Mask(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_left,
2747                                int pixel_count, FX_LPCBYTE clip_scan)
2748{
2749    for (int col = 0; col < pixel_count; col ++) {
2750        if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
2751            dest_scan ++;
2752            continue;
2753        }
2754        int src_alpha;
2755        if (clip_scan) {
2756            src_alpha = mask_alpha * clip_scan[col] / 255;
2757        } else {
2758            src_alpha = mask_alpha;
2759        }
2760        FX_BYTE back_alpha = *dest_scan;
2761        if (!back_alpha) {
2762            *dest_scan = src_alpha;
2763        } else if (src_alpha) {
2764            *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2765        }
2766        dest_scan ++;
2767    }
2768}
2769void _CompositeRow_BitMask2Gray(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_gray,
2770                                int src_left, int pixel_count, FX_LPCBYTE clip_scan)
2771{
2772    for (int col = 0; col < pixel_count; col ++) {
2773        if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
2774            dest_scan ++;
2775            continue;
2776        }
2777        int src_alpha;
2778        if (clip_scan) {
2779            src_alpha = mask_alpha * clip_scan[col] / 255;
2780        } else {
2781            src_alpha = mask_alpha;
2782        }
2783        if (src_alpha) {
2784            *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, src_alpha);
2785        }
2786        dest_scan ++;
2787    }
2788}
2789void _CompositeRow_BitMask2Graya(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_gray,
2790                                 int src_left, int pixel_count, FX_LPCBYTE clip_scan,
2791                                 FX_LPBYTE dest_alpha_scan)
2792{
2793    for (int col = 0; col < pixel_count; col ++) {
2794        if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
2795            dest_scan ++;
2796            dest_alpha_scan ++;
2797            continue;
2798        }
2799        int src_alpha;
2800        if (clip_scan) {
2801            src_alpha = mask_alpha * clip_scan[col] / 255;
2802        } else {
2803            src_alpha = mask_alpha;
2804        }
2805        FX_BYTE back_alpha = *dest_alpha_scan;
2806        if (back_alpha == 0) {
2807            *dest_scan ++ = src_gray;
2808            *dest_alpha_scan ++ = src_alpha;
2809            continue;
2810        }
2811        if (src_alpha == 0) {
2812            dest_scan ++;
2813            dest_alpha_scan ++;
2814            continue;
2815        }
2816        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2817        *dest_alpha_scan++ = dest_alpha;
2818        int alpha_ratio = src_alpha * 255 / dest_alpha;
2819        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, alpha_ratio);
2820        dest_scan ++;
2821    }
2822}
2823void _CompositeRow_Argb2Argb_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int pixel_count, int blend_type, FX_LPCBYTE clip_scan)
2824{
2825    int blended_colors[3];
2826    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2827    for (int col = 0; col < pixel_count; col ++) {
2828        FX_BYTE back_alpha = dest_scan[3];
2829        if (back_alpha == 0) {
2830            if (clip_scan) {
2831                int src_alpha = clip_scan[col] * src_scan[3] / 255;
2832                dest_scan[3] = src_alpha;
2833                dest_scan[0] = src_scan[2];
2834                dest_scan[1] = src_scan[1];
2835                dest_scan[2] = src_scan[0];
2836            } else {
2837                FXARGB_RGBORDERCOPY(dest_scan, src_scan);
2838            }
2839            dest_scan += 4;
2840            src_scan += 4;
2841            continue;
2842        }
2843        FX_BYTE src_alpha;
2844        if (clip_scan == NULL) {
2845            src_alpha = src_scan[3];
2846        } else {
2847            src_alpha = clip_scan[col] * src_scan[3] / 255;
2848        }
2849        if (src_alpha == 0) {
2850            dest_scan += 4;
2851            src_scan += 4;
2852            continue;
2853        }
2854        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2855        dest_scan[3] = dest_alpha;
2856        int alpha_ratio = src_alpha * 255 / dest_alpha;
2857        if (bNonseparableBlend) {
2858            FX_BYTE dest_scan_o[3];
2859            dest_scan_o[0] = dest_scan[2];
2860            dest_scan_o[1] = dest_scan[1];
2861            dest_scan_o[2] = dest_scan[0];
2862            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2863        }
2864        for (int color = 0; color < 3; color ++) {
2865            int index = 2 - color;
2866            if (blend_type) {
2867                int blended = bNonseparableBlend ? blended_colors[color] :
2868                              _BLEND(blend_type, dest_scan[index], *src_scan);
2869                blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha);
2870                dest_scan[index] = FXDIB_ALPHA_MERGE(dest_scan[index], blended, alpha_ratio);
2871            } else {
2872                dest_scan[index] = FXDIB_ALPHA_MERGE(dest_scan[index], *src_scan, alpha_ratio);
2873            }
2874            src_scan ++;
2875        }
2876        dest_scan += 4;
2877        src_scan++;
2878    }
2879}
2880void _CompositeRow_Rgb2Argb_Blend_NoClip_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int src_Bpp)
2881{
2882    int blended_colors[3];
2883    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2884    int src_gap = src_Bpp - 3;
2885    for (int col = 0; col < width; col ++) {
2886        FX_BYTE back_alpha = dest_scan[3];
2887        if (back_alpha == 0) {
2888            if (src_Bpp == 4) {
2889                FXARGB_SETRGBORDERDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan));
2890            } else {
2891                FXARGB_SETRGBORDERDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[2], src_scan[1], src_scan[0]));
2892            }
2893            dest_scan += 4;
2894            src_scan += src_Bpp;
2895            continue;
2896        }
2897        dest_scan[3] = 0xff;
2898        if (bNonseparableBlend)	{
2899            FX_BYTE dest_scan_o[3];
2900            dest_scan_o[0] = dest_scan[2];
2901            dest_scan_o[1] = dest_scan[1];
2902            dest_scan_o[2] = dest_scan[0];
2903            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2904        }
2905        for (int color = 0; color < 3; color ++) {
2906            int index = 2 - color;
2907            int src_color = FX_GAMMA(*src_scan);
2908            int blended = bNonseparableBlend ? blended_colors[color] :
2909                          _BLEND(blend_type, dest_scan[index], src_color);
2910            dest_scan[index] = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
2911            src_scan ++;
2912        }
2913        dest_scan += 4;
2914        src_scan += src_gap;
2915    }
2916}
2917inline void _CompositeRow_Argb2Rgb_Blend_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, FX_LPCBYTE clip_scan)
2918{
2919    int blended_colors[3];
2920    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2921    for (int col = 0; col < width; col ++) {
2922        FX_BYTE src_alpha;
2923        if (clip_scan) {
2924            src_alpha = src_scan[3] * (*clip_scan++) / 255;
2925        } else {
2926            src_alpha = src_scan[3];
2927        }
2928        if (src_alpha == 0) {
2929            dest_scan += dest_Bpp;
2930            src_scan += 4;
2931            continue;
2932        }
2933        if (bNonseparableBlend) {
2934            FX_BYTE dest_scan_o[3];
2935            dest_scan_o[0] = dest_scan[2];
2936            dest_scan_o[1] = dest_scan[1];
2937            dest_scan_o[2] = dest_scan[0];
2938            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2939        }
2940        for (int color = 0; color < 3; color ++) {
2941            int index = 2 - color;
2942            int back_color = FX_GAMMA(dest_scan[index]);
2943            int blended = bNonseparableBlend ? blended_colors[color] :
2944                          _BLEND(blend_type, back_color, *src_scan);
2945            dest_scan[index] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha));
2946            src_scan ++;
2947        }
2948        dest_scan += dest_Bpp;
2949        src_scan ++;
2950    }
2951}
2952inline void _CompositeRow_Rgb2Argb_NoBlend_NoClip_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int src_Bpp)
2953{
2954    int src_gap = src_Bpp - 3;
2955    for (int col = 0; col < width; col ++) {
2956        if (src_Bpp == 4) {
2957            FXARGB_SETRGBORDERDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan));
2958        } else {
2959            FXARGB_SETRGBORDERDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[2], src_scan[1], src_scan[0]));
2960        }
2961        dest_scan += 4;
2962        src_scan += src_Bpp;
2963    }
2964}
2965inline void _CompositeRow_Rgb2Rgb_Blend_NoClip_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, int src_Bpp)
2966{
2967    int blended_colors[3];
2968    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2969    int src_gap = src_Bpp - 3;
2970    for (int col = 0; col < width; col ++) {
2971        if (bNonseparableBlend) {
2972            FX_BYTE dest_scan_o[3];
2973            dest_scan_o[0] = dest_scan[2];
2974            dest_scan_o[1] = dest_scan[1];
2975            dest_scan_o[2] = dest_scan[0];
2976            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2977        }
2978        for (int color = 0; color < 3; color ++) {
2979            int index = 2 - color;
2980            int back_color = FX_GAMMA(dest_scan[index]);
2981            int src_color = FX_GAMMA(*src_scan);
2982            int blended = bNonseparableBlend ? blended_colors[color] :
2983                          _BLEND(blend_type, back_color, src_color);
2984            dest_scan[index] = FX_GAMMA_INVERSE(blended);
2985            src_scan ++;
2986        }
2987        dest_scan += dest_Bpp;
2988        src_scan += src_gap;
2989    }
2990}
2991inline void _CompositeRow_Argb2Rgb_NoBlend_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, FX_LPCBYTE clip_scan)
2992{
2993    for (int col = 0; col < width; col ++) {
2994        FX_BYTE src_alpha;
2995        if (clip_scan) {
2996            src_alpha = src_scan[3] * (*clip_scan++) / 255;
2997        } else {
2998            src_alpha = src_scan[3];
2999        }
3000        if (src_alpha == 255) {
3001            dest_scan[2] = FX_GAMMA_INVERSE(*src_scan++);
3002            dest_scan[1] = FX_GAMMA_INVERSE(*src_scan++);
3003            dest_scan[0] = FX_GAMMA_INVERSE(*src_scan++);
3004            dest_scan += dest_Bpp;
3005            src_scan ++;
3006            continue;
3007        }
3008        if (src_alpha == 0) {
3009            dest_scan += dest_Bpp;
3010            src_scan += 4;
3011            continue;
3012        }
3013        for (int color = 0; color < 3; color ++) {
3014            int index = 2 - color;
3015            dest_scan[index] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[index]), *src_scan, src_alpha));
3016            src_scan ++;
3017        }
3018        dest_scan += dest_Bpp;
3019        src_scan ++;
3020    }
3021}
3022inline void _CompositeRow_Rgb2Rgb_NoBlend_NoClip_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, int src_Bpp)
3023{
3024    for (int col = 0; col < width; col ++) {
3025        dest_scan[2] = src_scan[0];
3026        dest_scan[1] = src_scan[1];
3027        dest_scan[0] = src_scan[2];
3028        dest_scan += dest_Bpp;
3029        src_scan += src_Bpp;
3030    }
3031}
3032inline void _CompositeRow_Rgb2Argb_Blend_Clip_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int src_Bpp, FX_LPCBYTE clip_scan)
3033{
3034    int blended_colors[3];
3035    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
3036    int src_gap = src_Bpp - 3;
3037    for (int col = 0; col < width; col ++) {
3038        int src_alpha = *clip_scan ++;
3039        FX_BYTE back_alpha = dest_scan[3];
3040        if (back_alpha == 0) {
3041            dest_scan[2] = FX_GAMMA(*src_scan++);
3042            dest_scan[1] = FX_GAMMA(*src_scan++);
3043            dest_scan[0] = FX_GAMMA(*src_scan++);
3044            src_scan += src_gap;
3045            dest_scan += 4;
3046            continue;
3047        }
3048        if (src_alpha == 0) {
3049            dest_scan += 4;
3050            src_scan += src_Bpp;
3051            continue;
3052        }
3053        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
3054        dest_scan[3] = dest_alpha;
3055        int alpha_ratio = src_alpha * 255 / dest_alpha;
3056        if (bNonseparableBlend) {
3057            FX_BYTE dest_scan_o[3];
3058            dest_scan_o[0] = dest_scan[2];
3059            dest_scan_o[1] = dest_scan[1];
3060            dest_scan_o[2] = dest_scan[0];
3061            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
3062        }
3063        for (int color = 0; color < 3; color ++) {
3064            int index = 2 - color;
3065            int src_color = FX_GAMMA(*src_scan);
3066            int blended = bNonseparableBlend ? blended_colors[color] :
3067                          _BLEND(blend_type, dest_scan[index], src_color);
3068            blended = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
3069            dest_scan[index] = FXDIB_ALPHA_MERGE(dest_scan[index], blended, alpha_ratio);
3070            src_scan ++;
3071        }
3072        dest_scan += 4;
3073        src_scan += src_gap;
3074    }
3075}
3076inline void _CompositeRow_Rgb2Rgb_Blend_Clip_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int blend_type, int dest_Bpp, int src_Bpp, FX_LPCBYTE clip_scan)
3077{
3078    int blended_colors[3];
3079    FX_BOOL bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
3080    int src_gap = src_Bpp - 3;
3081    for (int col = 0; col < width; col ++) {
3082        FX_BYTE src_alpha = *clip_scan ++;
3083        if (src_alpha == 0) {
3084            dest_scan += dest_Bpp;
3085            src_scan += src_Bpp;
3086            continue;
3087        }
3088        if (bNonseparableBlend) {
3089            FX_BYTE dest_scan_o[3];
3090            dest_scan_o[0] = dest_scan[2];
3091            dest_scan_o[1] = dest_scan[1];
3092            dest_scan_o[2] = dest_scan[0];
3093            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
3094        }
3095        for (int color = 0; color < 3; color ++) {
3096            int index = 2 - color;
3097            int src_color = FX_GAMMA(*src_scan);
3098            int back_color = FX_GAMMA(dest_scan[index]);
3099            int blended = bNonseparableBlend ? blended_colors[color] :
3100                          _BLEND(blend_type, back_color, src_color);
3101            dest_scan[index] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha));
3102            src_scan ++;
3103        }
3104        dest_scan += dest_Bpp;
3105        src_scan += src_gap;
3106    }
3107}
3108inline void _CompositeRow_Rgb2Argb_NoBlend_Clip_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int src_Bpp, FX_LPCBYTE clip_scan)
3109{
3110    int src_gap = src_Bpp - 3;
3111    for (int col = 0; col < width; col ++) {
3112        int src_alpha = clip_scan[col];
3113        if (src_alpha == 255) {
3114            dest_scan[2] = FX_GAMMA(*src_scan++);
3115            dest_scan[1] = FX_GAMMA(*src_scan++);
3116            dest_scan[0] = FX_GAMMA(*src_scan++);
3117            dest_scan[3] = 255;
3118            dest_scan += 4;
3119            src_scan  += src_gap;
3120            continue;
3121        }
3122        if (src_alpha == 0) {
3123            dest_scan += 4;
3124            src_scan += src_Bpp;
3125            continue;
3126        }
3127        int back_alpha = dest_scan[3];
3128        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
3129        dest_scan[3] = dest_alpha;
3130        int alpha_ratio = src_alpha * 255 / dest_alpha;
3131        for (int color = 0; color < 3; color ++) {
3132            int index = 2 - color;
3133            dest_scan[index] = FXDIB_ALPHA_MERGE(dest_scan[index], FX_GAMMA(*src_scan), alpha_ratio);
3134            src_scan ++;
3135        }
3136        dest_scan += 4;
3137        src_scan += src_gap;
3138    }
3139}
3140inline void _CompositeRow_Rgb2Rgb_NoBlend_Clip_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, int dest_Bpp, int src_Bpp, FX_LPCBYTE clip_scan)
3141{
3142    for (int col = 0; col < width; col ++) {
3143        int src_alpha = clip_scan[col];
3144        if (src_alpha == 255) {
3145            dest_scan[2] = src_scan[0];
3146            dest_scan[1] = src_scan[1];
3147            dest_scan[0] = src_scan[2];
3148        } else if (src_alpha) {
3149            dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), FX_GAMMA(*src_scan), src_alpha));
3150            src_scan ++;
3151            dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), FX_GAMMA(*src_scan), src_alpha));
3152            src_scan ++;
3153            dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), FX_GAMMA(*src_scan), src_alpha));
3154            dest_scan += dest_Bpp;
3155            src_scan += src_Bpp - 2;
3156            continue;
3157        }
3158        dest_scan += dest_Bpp;
3159        src_scan += src_Bpp;
3160    }
3161}
3162inline void _CompositeRow_8bppRgb2Rgb_NoBlend_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, FX_ARGB* pPalette, int pixel_count,
3163        int DestBpp, FX_LPCBYTE clip_scan)
3164{
3165    for (int col = 0; col < pixel_count; col ++) {
3166        FX_ARGB argb = pPalette ? pPalette[*src_scan] : (*src_scan) * 0x010101;
3167        int src_r = FXARGB_R(argb);
3168        int src_g = FXARGB_G(argb);
3169        int src_b = FXARGB_B(argb);
3170        if (clip_scan && clip_scan[col] < 255) {
3171            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, clip_scan[col]);
3172            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, clip_scan[col]);
3173            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, clip_scan[col]);
3174        } else {
3175            dest_scan[2] = src_b;
3176            dest_scan[1] = src_g;
3177            dest_scan[0] = src_r;
3178        }
3179        dest_scan += DestBpp;
3180        src_scan ++;
3181    }
3182}
3183inline void _CompositeRow_1bppRgb2Rgb_NoBlend_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left,
3184        FX_ARGB* pPalette, int pixel_count, int DestBpp, FX_LPCBYTE clip_scan)
3185{
3186    int reset_r, reset_g, reset_b;
3187    int set_r, set_g, set_b;
3188    if (pPalette) {
3189        reset_r = FXARGB_R(pPalette[0]);
3190        reset_g = FXARGB_G(pPalette[0]);
3191        reset_b = FXARGB_B(pPalette[0]);
3192        set_r = FXARGB_R(pPalette[1]);
3193        set_g = FXARGB_G(pPalette[1]);
3194        set_b = FXARGB_B(pPalette[1]);
3195    } else {
3196        reset_r = reset_g = reset_b = 0;
3197        set_r = set_g = set_b = 255;
3198    }
3199    for (int col = 0; col < pixel_count; col ++) {
3200        int src_r, src_g, src_b;
3201        if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
3202            src_r = set_r;
3203            src_g = set_g;
3204            src_b = set_b;
3205        } else {
3206            src_r = reset_r;
3207            src_g = reset_g;
3208            src_b = reset_b;
3209        }
3210        if (clip_scan && clip_scan[col] < 255) {
3211            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, clip_scan[col]);
3212            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, clip_scan[col]);
3213            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, clip_scan[col]);
3214        } else {
3215            dest_scan[2] = src_b;
3216            dest_scan[1] = src_g;
3217            dest_scan[0] = src_r;
3218        }
3219        dest_scan += DestBpp;
3220    }
3221}
3222inline void _CompositeRow_8bppRgb2Argb_NoBlend_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width,
3223        FX_ARGB* pPalette, FX_LPCBYTE clip_scan)
3224{
3225    for (int col = 0; col < width; col ++) {
3226        int src_r, src_g, src_b;
3227        if (pPalette) {
3228            FX_ARGB argb = pPalette[*src_scan];
3229            src_r = FXARGB_R(argb);
3230            src_g = FXARGB_G(argb);
3231            src_b = FXARGB_B(argb);
3232        } else {
3233            src_r = src_g = src_b = *src_scan;
3234        }
3235        if (clip_scan == NULL || clip_scan[col] == 255) {
3236            dest_scan[2] = FX_GAMMA(src_b);
3237            dest_scan[1] = FX_GAMMA(src_g);
3238            dest_scan[0] = FX_GAMMA(src_r);
3239            dest_scan[3] = 255;
3240            src_scan ++;
3241            dest_scan += 4;
3242            continue;
3243        }
3244        int src_alpha = clip_scan[col];
3245        if (src_alpha == 0) {
3246            dest_scan += 4;
3247            src_scan ++;
3248            continue;
3249        }
3250        int back_alpha = dest_scan[3];
3251        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
3252        dest_scan[3] = dest_alpha;
3253        int alpha_ratio = src_alpha * 255 / dest_alpha;
3254        dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], FX_GAMMA(src_b), alpha_ratio);
3255        dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], FX_GAMMA(src_g), alpha_ratio);
3256        dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], FX_GAMMA(src_r), alpha_ratio);
3257        dest_scan += 4;
3258        src_scan ++;
3259    }
3260}
3261inline void _CompositeRow_1bppRgb2Argb_NoBlend_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width,
3262        FX_ARGB* pPalette, FX_LPCBYTE clip_scan)
3263{
3264    int reset_r, reset_g, reset_b;
3265    int set_r, set_g, set_b;
3266    if (pPalette) {
3267        reset_r = FXARGB_R(pPalette[0]);
3268        reset_g = FXARGB_G(pPalette[0]);
3269        reset_b = FXARGB_B(pPalette[0]);
3270        set_r = FXARGB_R(pPalette[1]);
3271        set_g = FXARGB_G(pPalette[1]);
3272        set_b = FXARGB_B(pPalette[1]);
3273    } else {
3274        reset_r = reset_g = reset_b = 0;
3275        set_r = set_g = set_b = 255;
3276    }
3277    for (int col = 0; col < width; col ++) {
3278        int src_r, src_g, src_b;
3279        if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
3280            src_r = set_r;
3281            src_g = set_g;
3282            src_b = set_b;
3283        } else {
3284            src_r = reset_r;
3285            src_g = reset_g;
3286            src_b = reset_b;
3287        }
3288        if (clip_scan == NULL || clip_scan[col] == 255) {
3289            dest_scan[2] = FX_GAMMA(src_b);
3290            dest_scan[1] = FX_GAMMA(src_g);
3291            dest_scan[0] = FX_GAMMA(src_r);
3292            dest_scan[3] = 255;
3293            dest_scan += 4;
3294            continue;
3295        }
3296        int src_alpha = clip_scan[col];
3297        if (src_alpha == 0) {
3298            dest_scan += 4;
3299            continue;
3300        }
3301        int back_alpha = dest_scan[3];
3302        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
3303        dest_scan[3] = dest_alpha;
3304        int alpha_ratio = src_alpha * 255 / dest_alpha;
3305        dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], FX_GAMMA(src_b), alpha_ratio);
3306        dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], FX_GAMMA(src_g), alpha_ratio);
3307        dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], FX_GAMMA(src_r), alpha_ratio);
3308        dest_scan += 4;
3309    }
3310}
3311void _CompositeRow_ByteMask2Argb_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b, int pixel_count,
3312        int blend_type, FX_LPCBYTE clip_scan)
3313{
3314    for (int col = 0; col < pixel_count; col ++) {
3315        int src_alpha;
3316        if (clip_scan) {
3317            src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
3318        } else {
3319            src_alpha = mask_alpha * src_scan[col] / 255;
3320        }
3321        FX_BYTE back_alpha = dest_scan[3];
3322        if (back_alpha == 0) {
3323            FXARGB_SETRGBORDERDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
3324            dest_scan += 4;
3325            continue;
3326        }
3327        if (src_alpha == 0) {
3328            dest_scan += 4;
3329            continue;
3330        }
3331        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
3332        dest_scan[3] = dest_alpha;
3333        int alpha_ratio = src_alpha * 255 / dest_alpha;
3334        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
3335            int blended_colors[3];
3336            FX_BYTE src_scan[3];
3337            FX_BYTE dest_scan_o[3];
3338            src_scan[0] = src_b;
3339            src_scan[1] = src_g;
3340            src_scan[2] = src_r;
3341            dest_scan_o[0] = dest_scan[2];
3342            dest_scan_o[1] = dest_scan[1];
3343            dest_scan_o[2] = dest_scan[0];
3344            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
3345            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], alpha_ratio);
3346            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], alpha_ratio);
3347            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], alpha_ratio);
3348        } else if (blend_type) {
3349            int blended = _BLEND(blend_type, dest_scan[2], src_b);
3350            blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
3351            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, alpha_ratio);
3352            blended = _BLEND(blend_type, dest_scan[1], src_g);
3353            blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
3354            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, alpha_ratio);
3355            blended = _BLEND(blend_type, dest_scan[0], src_r);
3356            blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
3357            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, alpha_ratio);
3358        } else {
3359            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, alpha_ratio);
3360            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, alpha_ratio);
3361            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, alpha_ratio);
3362        }
3363        dest_scan += 4;
3364    }
3365}
3366void _CompositeRow_ByteMask2Rgb_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b, int pixel_count,
3367        int blend_type, int Bpp, FX_LPCBYTE clip_scan)
3368{
3369    for (int col = 0; col < pixel_count; col ++) {
3370        int src_alpha;
3371        if (clip_scan) {
3372            src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
3373        } else {
3374            src_alpha = mask_alpha * src_scan[col] / 255;
3375        }
3376        if (src_alpha == 0) {
3377            dest_scan += Bpp;
3378            continue;
3379        }
3380        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
3381            int blended_colors[3];
3382            FX_BYTE src_scan[3];
3383            FX_BYTE dest_scan_o[3];
3384            src_scan[0] = src_b;
3385            src_scan[1] = src_g;
3386            src_scan[2] = src_r;
3387            dest_scan_o[0] = dest_scan[2];
3388            dest_scan_o[1] = dest_scan[1];
3389            dest_scan_o[2] = dest_scan[0];
3390            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
3391            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], src_alpha);
3392            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], src_alpha);
3393            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], src_alpha);
3394        } else if (blend_type) {
3395            int blended = _BLEND(blend_type, dest_scan[2], src_b);
3396            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, src_alpha);
3397            blended = _BLEND(blend_type, dest_scan[1], src_g);
3398            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, src_alpha);
3399            blended = _BLEND(blend_type, dest_scan[0], src_r);
3400            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, src_alpha);
3401        } else {
3402            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, src_alpha);
3403            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, src_alpha);
3404            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, src_alpha);
3405        }
3406        dest_scan += Bpp;
3407    }
3408}
3409void _CompositeRow_BitMask2Argb_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b,
3410        int src_left, int pixel_count, int blend_type, FX_LPCBYTE clip_scan)
3411{
3412    if (blend_type == FXDIB_BLEND_NORMAL && clip_scan == NULL && mask_alpha == 255) {
3413        FX_ARGB argb = FXARGB_MAKE(0xff, src_r, src_g, src_b);
3414        for (int col = 0; col < pixel_count; col ++) {
3415            if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
3416                FXARGB_SETRGBORDERDIB(dest_scan, argb);
3417            }
3418            dest_scan += 4;
3419        }
3420        return;
3421    }
3422    for (int col = 0; col < pixel_count; col ++) {
3423        if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
3424            dest_scan += 4;
3425            continue;
3426        }
3427        int src_alpha;
3428        if (clip_scan) {
3429            src_alpha = mask_alpha * clip_scan[col] / 255;
3430        } else {
3431            src_alpha = mask_alpha;
3432        }
3433        FX_BYTE back_alpha = dest_scan[3];
3434        if (back_alpha == 0) {
3435            FXARGB_SETRGBORDERDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
3436            dest_scan += 4;
3437            continue;
3438        }
3439        FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
3440        dest_scan[3] = dest_alpha;
3441        int alpha_ratio = src_alpha * 255 / dest_alpha;
3442        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
3443            int blended_colors[3];
3444            FX_BYTE src_scan[3];
3445            FX_BYTE dest_scan_o[3];
3446            src_scan[0] = src_b;
3447            src_scan[1] = src_g;
3448            src_scan[2] = src_r;
3449            dest_scan_o[0] = dest_scan[2];
3450            dest_scan_o[1] = dest_scan[1];
3451            dest_scan_o[2] = dest_scan[0];
3452            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
3453            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], alpha_ratio);
3454            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], alpha_ratio);
3455            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], alpha_ratio);
3456        } else if (blend_type) {
3457            int blended = _BLEND(blend_type, dest_scan[2], src_b);
3458            blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
3459            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, alpha_ratio);
3460            blended = _BLEND(blend_type, dest_scan[1], src_g);
3461            blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
3462            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, alpha_ratio);
3463            blended = _BLEND(blend_type, dest_scan[0], src_r);
3464            blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
3465            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, alpha_ratio);
3466        } else {
3467            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, alpha_ratio);
3468            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, alpha_ratio);
3469            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, alpha_ratio);
3470        }
3471        dest_scan += 4;
3472    }
3473}
3474void _CompositeRow_BitMask2Rgb_RgbByteOrder(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int mask_alpha, int src_r, int src_g, int src_b,
3475        int src_left, int pixel_count, int blend_type, int Bpp, FX_LPCBYTE clip_scan)
3476{
3477    if (blend_type == FXDIB_BLEND_NORMAL && clip_scan == NULL && mask_alpha == 255) {
3478        for (int col = 0; col < pixel_count; col ++) {
3479            if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
3480                dest_scan[2] = src_b;
3481                dest_scan[1] = src_g;
3482                dest_scan[0] = src_r;
3483            }
3484            dest_scan += Bpp;
3485        }
3486        return;
3487    }
3488    for (int col = 0; col < pixel_count; col ++) {
3489        if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
3490            dest_scan += Bpp;
3491            continue;
3492        }
3493        int src_alpha;
3494        if (clip_scan) {
3495            src_alpha = mask_alpha * clip_scan[col] / 255;
3496        } else {
3497            src_alpha = mask_alpha;
3498        }
3499        if (src_alpha == 0) {
3500            dest_scan += Bpp;
3501            continue;
3502        }
3503        if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
3504            int blended_colors[3];
3505            FX_BYTE src_scan[3];
3506            FX_BYTE dest_scan_o[3];
3507            src_scan[0] = src_b;
3508            src_scan[1] = src_g;
3509            src_scan[2] = src_r;
3510            dest_scan_o[0] = dest_scan[2];
3511            dest_scan_o[1] = dest_scan[1];
3512            dest_scan_o[2] = dest_scan[0];
3513            _RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
3514            dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], src_alpha);
3515            dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], src_alpha);
3516            dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], src_alpha);
3517        } else if (blend_type) {
3518            int back_color = FX_GAMMA(dest_scan[2]);
3519            int blended = _BLEND(blend_type, back_color, src_b);
3520            dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha));
3521            back_color = FX_GAMMA(dest_scan[1]);
3522            blended = _BLEND(blend_type, back_color, src_g);
3523            dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha));
3524            back_color = FX_GAMMA(dest_scan[0]);
3525            blended = _BLEND(blend_type, back_color, src_r);
3526            dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(back_color, blended, src_alpha));
3527        } else {
3528            dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), src_b, src_alpha));
3529            dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), src_g, src_alpha));
3530            dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), src_r, src_alpha));
3531        }
3532        dest_scan += Bpp;
3533    }
3534}
3535inline FX_BOOL _ScanlineCompositor_InitSourceMask(FXDIB_Format dest_format, int alpha_flag, FX_DWORD mask_color, int& mask_alpha,
3536        int& mask_red, int& mask_green, int& mask_blue, int& mask_black,
3537        void* icc_module, void* pIccTransform)
3538{
3539    ICodec_IccModule* pIccModule = (ICodec_IccModule*)icc_module;
3540    if (alpha_flag >> 8) {
3541        mask_alpha = alpha_flag & 0xff;
3542        mask_red = FXSYS_GetCValue(mask_color);
3543        mask_green = FXSYS_GetMValue(mask_color);
3544        mask_blue = FXSYS_GetYValue(mask_color);
3545        mask_black = FXSYS_GetKValue(mask_color);
3546    } else {
3547        mask_alpha = FXARGB_A(mask_color);
3548        mask_red = FXARGB_R(mask_color);
3549        mask_green = FXARGB_G(mask_color);
3550        mask_blue = FXARGB_B(mask_color);
3551    }
3552    if (dest_format == FXDIB_8bppMask) {
3553        return TRUE;
3554    }
3555    if ((dest_format & 0xff) == 8) {
3556        if (pIccTransform) {
3557            mask_color = (alpha_flag >> 8) ? FXCMYK_TODIB(mask_color) : FXARGB_TODIB(mask_color);
3558            FX_LPBYTE gray_p = (FX_LPBYTE)&mask_color;
3559            pIccModule->TranslateScanline(pIccTransform, gray_p, gray_p, 1);
3560            mask_red = dest_format & 0x0400 ? FX_CCOLOR(gray_p[0]) : gray_p[0];
3561        } else {
3562            if (alpha_flag >> 8) {
3563                FX_BYTE r, g, b;
3564                AdobeCMYK_to_sRGB1(mask_red, mask_green, mask_blue, mask_black,
3565                                   r, g, b);
3566                mask_red = FXRGB2GRAY(r, g, b);
3567            } else {
3568                mask_red = FXRGB2GRAY(mask_red, mask_green, mask_blue);
3569            }
3570            if (dest_format & 0x0400) {
3571                mask_red = FX_CCOLOR(mask_red);
3572            }
3573        }
3574    } else {
3575        FX_LPBYTE mask_color_p = (FX_LPBYTE)&mask_color;
3576        mask_color = (alpha_flag >> 8) ? FXCMYK_TODIB(mask_color) : FXARGB_TODIB(mask_color);
3577        if (pIccTransform) {
3578            pIccModule->TranslateScanline(pIccTransform, mask_color_p, mask_color_p, 1);
3579            mask_red = mask_color_p[2];
3580            mask_green = mask_color_p[1];
3581            mask_blue = mask_color_p[0];
3582        } else if (alpha_flag >> 8) {
3583            AdobeCMYK_to_sRGB1(mask_color_p[0], mask_color_p[1], mask_color_p[2], mask_color_p[3],
3584                               mask_color_p[2], mask_color_p[1], mask_color_p[0]);
3585            mask_red = mask_color_p[2];
3586            mask_green = mask_color_p[1];
3587            mask_blue = mask_color_p[0];
3588        }
3589    }
3590    return TRUE;
3591}
3592inline void _ScanlineCompositor_InitSourcePalette(FXDIB_Format src_format, FXDIB_Format dest_format,
3593        FX_DWORD*& pDestPalette, FX_DWORD* pSrcPalette,
3594        void* icc_module, void* pIccTransform)
3595{
3596    ICodec_IccModule* pIccModule = (ICodec_IccModule*)icc_module;
3597    FX_BOOL isSrcCmyk = src_format & 0x0400 ? TRUE : FALSE;
3598    FX_BOOL isDstCmyk = dest_format & 0x0400 ? TRUE : FALSE;
3599    pDestPalette = NULL;
3600    if (pIccTransform) {
3601        if (pSrcPalette) {
3602            if ((dest_format & 0xff) == 8) {
3603                int pal_count = 1 << (src_format & 0xff);
3604                FX_LPBYTE gray_pal = FX_Alloc(FX_BYTE, pal_count);
3605                if (!gray_pal) {
3606                    return;
3607                }
3608                pDestPalette = (FX_DWORD*)gray_pal;
3609                for (int i = 0; i < pal_count; i ++) {
3610                    FX_DWORD color = isSrcCmyk ? FXCMYK_TODIB(pSrcPalette[i]) : FXARGB_TODIB(pSrcPalette[i]);
3611                    pIccModule->TranslateScanline(pIccTransform, gray_pal, (FX_LPCBYTE)&color, 1);
3612                    gray_pal ++;
3613                }
3614            } else {
3615                int palsize = 1 << (src_format & 0xff);
3616                pDestPalette = FX_Alloc(FX_DWORD, palsize);
3617                if (!pDestPalette) {
3618                    return;
3619                }
3620                for (int i = 0; i < palsize; i ++) {
3621                    FX_DWORD color = isSrcCmyk ? FXCMYK_TODIB(pSrcPalette[i]) : FXARGB_TODIB(pSrcPalette[i]);
3622                    pIccModule->TranslateScanline(pIccTransform, (FX_LPBYTE)&color, (FX_LPCBYTE)&color, 1);
3623                    pDestPalette[i] = isDstCmyk ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
3624                }
3625            }
3626        } else {
3627            int pal_count = 1 << (src_format & 0xff);
3628            FX_LPBYTE gray_pal = FX_Alloc(FX_BYTE, pal_count);
3629            if (!gray_pal) {
3630                return;
3631            }
3632            if (pal_count == 2) {
3633                gray_pal[0] = 0;
3634                gray_pal[1] = 255;
3635            } else {
3636                for (int i = 0; i < pal_count; i++) {
3637                    gray_pal[i] = i;
3638                }
3639            }
3640            if ((dest_format & 0xff) == 8) {
3641                pIccModule->TranslateScanline(pIccTransform, gray_pal, gray_pal, pal_count);
3642                pDestPalette = (FX_DWORD*)gray_pal;
3643            } else {
3644                pDestPalette = FX_Alloc(FX_DWORD, pal_count);
3645                if (!pDestPalette) {
3646                    FX_Free(gray_pal);
3647                    return;
3648                }
3649                for (int i = 0; i < pal_count; i ++) {
3650                    pIccModule->TranslateScanline(pIccTransform, (FX_LPBYTE)&pDestPalette[i], &gray_pal[i], 1);
3651                    pDestPalette[i] = isDstCmyk ? FXCMYK_TODIB(pDestPalette[i]) : FXARGB_TODIB(pDestPalette[i]);
3652                }
3653                FX_Free(gray_pal);
3654            }
3655        }
3656    } else {
3657        if (pSrcPalette) {
3658            if ((dest_format & 0xff) == 8) {
3659                int pal_count = 1 << (src_format & 0xff);
3660                FX_LPBYTE gray_pal = FX_Alloc(FX_BYTE, pal_count);
3661                if (!gray_pal) {
3662                    return;
3663                }
3664                pDestPalette = (FX_DWORD*)gray_pal;
3665                if (isSrcCmyk) {
3666                    for (int i = 0; i < pal_count; i ++) {
3667                        FX_CMYK cmyk = pSrcPalette[i];
3668                        FX_BYTE r, g, b;
3669                        AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk), FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk),
3670                                           r, g, b);
3671                        *gray_pal ++ = FXRGB2GRAY(r, g, b);
3672                    }
3673                } else
3674                    for (int i = 0; i < pal_count; i ++) {
3675                        FX_ARGB argb = pSrcPalette[i];
3676                        *gray_pal ++ = FXRGB2GRAY(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb));
3677                    }
3678            } else {
3679                int palsize = 1 << (src_format & 0xff);
3680                pDestPalette = FX_Alloc(FX_DWORD, palsize);
3681                if (!pDestPalette) {
3682                    return;
3683                }
3684                if (isDstCmyk == isSrcCmyk) {
3685                    FXSYS_memcpy32(pDestPalette, pSrcPalette, palsize * sizeof(FX_DWORD));
3686                } else {
3687                    for (int i = 0; i < palsize; i ++) {
3688                        FX_CMYK cmyk = pSrcPalette[i];
3689                        FX_BYTE r, g, b;
3690                        AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk), FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk),
3691                                           r, g, b);
3692                        pDestPalette[i] = FXARGB_MAKE(0xff, r, g, b);
3693                    }
3694                }
3695            }
3696        } else {
3697            if ((dest_format & 0xff) == 8) {
3698                int pal_count = 1 << (src_format & 0xff);
3699                FX_LPBYTE gray_pal = FX_Alloc(FX_BYTE, pal_count);
3700                if (!gray_pal) {
3701                    return;
3702                }
3703                if (pal_count == 2) {
3704                    gray_pal[0] = 0;
3705                    gray_pal[1] = 255;
3706                } else {
3707                    for (int i = 0; i < pal_count; i++) {
3708                        gray_pal[i] = i;
3709                    }
3710                }
3711                pDestPalette = (FX_DWORD*)gray_pal;
3712            } else {
3713                int palsize = 1 << (src_format & 0xff);
3714                pDestPalette = FX_Alloc(FX_DWORD, palsize);
3715                if (!pDestPalette) {
3716                    return;
3717                }
3718                if (palsize == 2) {
3719                    pDestPalette[0] = isSrcCmyk ? 255 : 0xff000000;
3720                    pDestPalette[1] = isSrcCmyk ? 0 : 0xffffffff;
3721                } else {
3722                    for (int i = 0; i < palsize; i++) {
3723                        pDestPalette[i] = isSrcCmyk ? FX_CCOLOR(i) : (i * 0x10101);
3724                    }
3725                }
3726                if (isSrcCmyk != isDstCmyk) {
3727                    for (int i = 0; i < palsize; i ++) {
3728                        FX_CMYK cmyk = pDestPalette[i];
3729                        FX_BYTE r, g, b;
3730                        AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk), FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk),
3731                                           r, g, b);
3732                        pDestPalette[i] = FXARGB_MAKE(0xff, r, g, b);
3733                    }
3734                }
3735            }
3736        }
3737    }
3738}
3739CFX_ScanlineCompositor::CFX_ScanlineCompositor()
3740{
3741    m_pSrcPalette = NULL;
3742    m_pCacheScanline = NULL;
3743    m_CacheSize = 0;
3744    m_bRgbByteOrder = FALSE;
3745    m_BlendType = FXDIB_BLEND_NORMAL;
3746}
3747CFX_ScanlineCompositor::~CFX_ScanlineCompositor()
3748{
3749    if (m_pSrcPalette) {
3750        FX_Free(m_pSrcPalette);
3751    }
3752    if (m_pCacheScanline) {
3753        FX_Free(m_pCacheScanline);
3754    }
3755}
3756FX_BOOL CFX_ScanlineCompositor::Init(FXDIB_Format dest_format, FXDIB_Format src_format, FX_INT32 width, FX_DWORD* pSrcPalette,
3757                                     FX_DWORD mask_color, int blend_type, FX_BOOL bClip, FX_BOOL bRgbByteOrder, int alpha_flag, void* pIccTransform)
3758{
3759    m_SrcFormat = src_format;
3760    m_DestFormat = dest_format;
3761    m_BlendType = blend_type;
3762    m_bRgbByteOrder = bRgbByteOrder;
3763    ICodec_IccModule* pIccModule = NULL;
3764    if (CFX_GEModule::Get()->GetCodecModule()) {
3765        pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
3766    }
3767    if (pIccModule == NULL) {
3768        pIccTransform = NULL;
3769    }
3770    m_pIccTransform = pIccTransform;
3771    if ((dest_format & 0xff) == 1) {
3772        return FALSE;
3773    }
3774    if (m_SrcFormat == FXDIB_1bppMask || m_SrcFormat == FXDIB_8bppMask) {
3775        return _ScanlineCompositor_InitSourceMask(dest_format, alpha_flag, mask_color,
3776                m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue, m_MaskBlack,
3777                pIccModule, pIccTransform);
3778    }
3779    if (pIccTransform == NULL && (~src_format & 0x0400) && (dest_format & 0x0400)) {
3780        return FALSE;
3781    }
3782    if ((m_SrcFormat & 0xff) <= 8) {
3783        if (dest_format == FXDIB_8bppMask) {
3784            return TRUE;
3785        }
3786        _ScanlineCompositor_InitSourcePalette(src_format, dest_format, m_pSrcPalette, pSrcPalette,
3787                                              pIccModule, pIccTransform);
3788        m_Transparency = (dest_format == FXDIB_Argb ? 1 : 0)
3789                         + (dest_format & 0x0200 ? 2 : 0)
3790                         + (dest_format & 0x0400 ? 4 : 0)
3791                         + ((src_format & 0xff) == 1 ? 8 : 0);
3792        return TRUE;
3793    }
3794    m_Transparency = (src_format & 0x0200 ? 0 : 1)
3795                     + (dest_format & 0x0200 ? 0 : 2)
3796                     + (blend_type == FXDIB_BLEND_NORMAL ? 4 : 0)
3797                     + (bClip ? 8 : 0)
3798                     + (src_format & 0x0400 ? 16 : 0)
3799                     + (dest_format & 0x0400 ? 32 : 0)
3800                     + (pIccTransform ? 64 : 0);
3801    return TRUE;
3802}
3803void CFX_ScanlineCompositor::CompositeRgbBitmapLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan,
3804        FX_LPCBYTE src_extra_alpha, FX_LPBYTE dst_extra_alpha)
3805{
3806    int src_Bpp = (m_SrcFormat & 0xff) >> 3;
3807    int dest_Bpp = (m_DestFormat & 0xff) >> 3;
3808    int dest_Size = width * dest_Bpp + 4;
3809    if (m_bRgbByteOrder) {
3810        switch (m_Transparency) {
3811            case 0:
3812            case 4:
3813            case 8:
3814            case 12:
3815                _CompositeRow_Argb2Argb_RgbByteOrder(dest_scan, src_scan, width, m_BlendType, clip_scan);
3816                break;
3817            case 1:
3818                _CompositeRow_Rgb2Argb_Blend_NoClip_RgbByteOrder(dest_scan, src_scan, width, m_BlendType, src_Bpp);
3819                break;
3820            case 2:
3821            case 10:
3822                _CompositeRow_Argb2Rgb_Blend_RgbByteOrder(dest_scan, src_scan, width, m_BlendType, dest_Bpp, clip_scan);
3823                break;
3824            case 3:
3825                _CompositeRow_Rgb2Rgb_Blend_NoClip_RgbByteOrder(dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp);
3826                break;
3827            case 5:
3828                _CompositeRow_Rgb2Argb_NoBlend_NoClip_RgbByteOrder(dest_scan, src_scan, width, src_Bpp);
3829                break;
3830            case 6:
3831            case 14:
3832                _CompositeRow_Argb2Rgb_NoBlend_RgbByteOrder(dest_scan, src_scan, width, dest_Bpp, clip_scan);
3833                break;
3834            case 7:
3835                _CompositeRow_Rgb2Rgb_NoBlend_NoClip_RgbByteOrder(dest_scan, src_scan, width, dest_Bpp, src_Bpp);
3836                break;
3837            case 9:
3838                _CompositeRow_Rgb2Argb_Blend_Clip_RgbByteOrder(dest_scan, src_scan, width, m_BlendType, src_Bpp, clip_scan);
3839                break;
3840            case 11:
3841                _CompositeRow_Rgb2Rgb_Blend_Clip_RgbByteOrder(dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp, clip_scan);
3842                break;
3843            case 13:
3844                _CompositeRow_Rgb2Argb_NoBlend_Clip_RgbByteOrder(dest_scan, src_scan, width, src_Bpp, clip_scan);
3845                break;
3846            case 15:
3847                _CompositeRow_Rgb2Rgb_NoBlend_Clip_RgbByteOrder(dest_scan, src_scan, width, dest_Bpp, src_Bpp, clip_scan);
3848                break;
3849        }
3850        return;
3851    }
3852    if (m_DestFormat == FXDIB_8bppMask) {
3853        if (m_SrcFormat & 0x0200) {
3854            if (m_SrcFormat == FXDIB_Argb) {
3855                _CompositeRow_Argb2Mask(dest_scan, src_scan, width, clip_scan);
3856            } else {
3857                _CompositeRow_Rgba2Mask(dest_scan, src_extra_alpha, width, clip_scan);
3858            }
3859        } else {
3860            _CompositeRow_Rgb2Mask(dest_scan, src_scan, width, clip_scan);
3861        }
3862    } else if ((m_DestFormat & 0xff) == 8) {
3863        if (m_DestFormat & 0x0400) {
3864            for (int i = 0; i < width; i ++) {
3865                *dest_scan = ~*dest_scan;
3866                dest_scan++;
3867            }
3868        }
3869        if (m_SrcFormat & 0x0200) {
3870            if (m_DestFormat & 0x0200) {
3871                _CompositeRow_Argb2Graya(dest_scan, src_scan, width, m_BlendType, clip_scan, src_extra_alpha, dst_extra_alpha, m_pIccTransform);
3872            } else {
3873                _CompositeRow_Argb2Gray(dest_scan, src_scan, width, m_BlendType, clip_scan, src_extra_alpha, m_pIccTransform);
3874            }
3875        } else {
3876            if (m_DestFormat & 0x0200) {
3877                _CompositeRow_Rgb2Graya(dest_scan, src_scan, src_Bpp, width, m_BlendType, clip_scan, dst_extra_alpha, m_pIccTransform);
3878            } else {
3879                _CompositeRow_Rgb2Gray(dest_scan, src_scan, src_Bpp, width, m_BlendType, clip_scan, m_pIccTransform);
3880            }
3881        }
3882        if (m_DestFormat & 0x0400) {
3883            for (int i = 0; i < width; i ++) {
3884                *dest_scan = ~*dest_scan;
3885                dest_scan++;
3886            }
3887        }
3888    } else {
3889        if (dest_Size > m_CacheSize) {
3890            m_pCacheScanline = FX_Realloc(FX_BYTE, m_pCacheScanline, dest_Size);
3891            if (!m_pCacheScanline) {
3892                return;
3893            }
3894            m_CacheSize = dest_Size;
3895        }
3896        switch (m_Transparency) {
3897            case 0:
3898            case 4:
3899            case 8:
3900            case 4+8: {
3901                    _CompositeRow_Argb2Argb(dest_scan, src_scan, width, m_BlendType, clip_scan,
3902                                            dst_extra_alpha, src_extra_alpha);
3903                }
3904                break;
3905            case 64:
3906            case 4+64:
3907            case 8+64:
3908            case 4+8+64: {
3909                    _CompositeRow_Argb2Argb_Transform(dest_scan, src_scan, width, m_BlendType, clip_scan,
3910                                                      dst_extra_alpha, src_extra_alpha, m_pCacheScanline, m_pIccTransform);
3911                }
3912                break;
3913            case 1:
3914                _CompositeRow_Rgb2Argb_Blend_NoClip(dest_scan, src_scan, width, m_BlendType, src_Bpp,
3915                                                    dst_extra_alpha);
3916                break;
3917            case 1+64:
3918                _CompositeRow_Rgb2Argb_Blend_NoClip_Transform(dest_scan, src_scan, width, m_BlendType, src_Bpp,
3919                        dst_extra_alpha, m_pCacheScanline, m_pIccTransform);
3920                break;
3921            case 1+8:
3922                _CompositeRow_Rgb2Argb_Blend_Clip(dest_scan, src_scan, width, m_BlendType, src_Bpp, clip_scan,
3923                                                  dst_extra_alpha);
3924                break;
3925            case 1+8+64:
3926                _CompositeRow_Rgb2Argb_Blend_Clip_Transform(dest_scan, src_scan, width, m_BlendType, src_Bpp, clip_scan,
3927                        dst_extra_alpha, m_pCacheScanline, m_pIccTransform);
3928                break;
3929            case 1+4:
3930                _CompositeRow_Rgb2Argb_NoBlend_NoClip(dest_scan, src_scan, width, src_Bpp,
3931                                                      dst_extra_alpha);
3932                break;
3933            case 1+4+64:
3934                _CompositeRow_Rgb2Argb_NoBlend_NoClip_Transform(dest_scan, src_scan, width, src_Bpp,
3935                        dst_extra_alpha, m_pCacheScanline, m_pIccTransform);
3936                break;
3937            case 1+4+8:
3938                _CompositeRow_Rgb2Argb_NoBlend_Clip(dest_scan, src_scan, width, src_Bpp, clip_scan,
3939                                                    dst_extra_alpha);
3940                break;
3941            case 1+4+8+64:
3942                _CompositeRow_Rgb2Argb_NoBlend_Clip_Transform(dest_scan, src_scan, width, src_Bpp, clip_scan,
3943                        dst_extra_alpha, m_pCacheScanline, m_pIccTransform);
3944                break;
3945            case 2:
3946            case 2+8:
3947                _CompositeRow_Argb2Rgb_Blend(dest_scan, src_scan, width, m_BlendType, dest_Bpp, clip_scan,
3948                                             src_extra_alpha);
3949                break;
3950            case 2+64:
3951            case 2+8+64:
3952                _CompositeRow_Argb2Rgb_Blend_Transform(dest_scan, src_scan, width, m_BlendType, dest_Bpp, clip_scan,
3953                                                       src_extra_alpha, m_pCacheScanline, m_pIccTransform);
3954                break;
3955            case 2+4:
3956            case 2+4+8:
3957                _CompositeRow_Argb2Rgb_NoBlend(dest_scan, src_scan, width, dest_Bpp, clip_scan,
3958                                               src_extra_alpha);
3959                break;
3960            case 2+4+64:
3961            case 2+4+8+64:
3962                _CompositeRow_Argb2Rgb_NoBlend_Transform(dest_scan, src_scan, width, dest_Bpp, clip_scan,
3963                        src_extra_alpha, m_pCacheScanline, m_pIccTransform);
3964                break;
3965            case 1+2:
3966                _CompositeRow_Rgb2Rgb_Blend_NoClip(dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp);
3967                break;
3968            case 1+2+64:
3969                _CompositeRow_Rgb2Rgb_Blend_NoClip_Transform(dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp,
3970                        m_pCacheScanline, m_pIccTransform);
3971                break;
3972            case 1+2+8:
3973                _CompositeRow_Rgb2Rgb_Blend_Clip(dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp, clip_scan);
3974                break;
3975            case 1+2+8+64:
3976                _CompositeRow_Rgb2Rgb_Blend_Clip_Transform(dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp, clip_scan,
3977                        m_pCacheScanline, m_pIccTransform);
3978                break;
3979            case 1+2+4:
3980                _CompositeRow_Rgb2Rgb_NoBlend_NoClip(dest_scan, src_scan, width, dest_Bpp, src_Bpp);
3981                break;
3982            case 1+2+4+64:
3983                _CompositeRow_Rgb2Rgb_NoBlend_NoClip_Transform(dest_scan, src_scan, width, dest_Bpp, src_Bpp,
3984                        m_pCacheScanline, m_pIccTransform);
3985                break;
3986            case 1+2+4+8:
3987                _CompositeRow_Rgb2Rgb_NoBlend_Clip(dest_scan, src_scan, width, dest_Bpp, src_Bpp, clip_scan);
3988                break;
3989            case 1+2+4+8+64:
3990                _CompositeRow_Rgb2Rgb_NoBlend_Clip_Transform(dest_scan, src_scan, width, dest_Bpp, src_Bpp, clip_scan,
3991                        m_pCacheScanline, m_pIccTransform);
3992                break;
3993        }
3994    }
3995}
3996void CFX_ScanlineCompositor::CompositePalBitmapLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width, FX_LPCBYTE clip_scan,
3997        FX_LPCBYTE src_extra_alpha, FX_LPBYTE dst_extra_alpha)
3998{
3999    if (m_bRgbByteOrder) {
4000        if (m_SrcFormat == FXDIB_1bppRgb) {
4001            if (m_DestFormat == FXDIB_8bppRgb) {
4002                return;
4003            } else if(m_DestFormat == FXDIB_Argb) {
4004                _CompositeRow_1bppRgb2Argb_NoBlend_RgbByteOrder(dest_scan, src_scan, src_left, width, m_pSrcPalette, clip_scan);
4005            } else {
4006                _CompositeRow_1bppRgb2Rgb_NoBlend_RgbByteOrder(dest_scan, src_scan, src_left, m_pSrcPalette, width, (m_DestFormat & 0xff) >> 3, clip_scan);
4007            }
4008        } else {
4009            if (m_DestFormat == FXDIB_8bppRgb) {
4010                return;
4011            } else if (m_DestFormat == FXDIB_Argb) {
4012                _CompositeRow_8bppRgb2Argb_NoBlend_RgbByteOrder(dest_scan, src_scan, width, m_pSrcPalette, clip_scan);
4013            } else {
4014                _CompositeRow_8bppRgb2Rgb_NoBlend_RgbByteOrder(dest_scan, src_scan, m_pSrcPalette, width, (m_DestFormat & 0xff) >> 3, clip_scan);
4015            }
4016        }
4017        return;
4018    }
4019    if (m_DestFormat == FXDIB_8bppMask) {
4020        _CompositeRow_Rgb2Mask(dest_scan, src_scan, width, clip_scan);
4021        return;
4022    } else if ((m_DestFormat & 0xff) == 8) {
4023        if (m_Transparency & 8) {
4024            if (m_DestFormat & 0x0200) {
4025                _CompositeRow_1bppPal2Graya(dest_scan, src_scan, src_left, (FX_LPCBYTE)m_pSrcPalette, width, m_BlendType, clip_scan, dst_extra_alpha);
4026            } else {
4027                _CompositeRow_1bppPal2Gray(dest_scan, src_scan, src_left, (FX_LPCBYTE)m_pSrcPalette, width, m_BlendType, clip_scan);
4028            }
4029        } else {
4030            if (m_DestFormat & 0x0200)
4031                _CompositeRow_8bppPal2Graya(dest_scan, src_scan, (FX_LPCBYTE)m_pSrcPalette, width, m_BlendType, clip_scan,
4032                                            dst_extra_alpha, src_extra_alpha);
4033            else
4034                _CompositeRow_8bppPal2Gray(dest_scan, src_scan, (FX_LPCBYTE)m_pSrcPalette, width, m_BlendType, clip_scan,
4035                                           src_extra_alpha);
4036        }
4037    } else {
4038        switch (m_Transparency) {
4039            case 1+2:
4040                _CompositeRow_8bppRgb2Argb_NoBlend(dest_scan, src_scan, width, m_pSrcPalette, clip_scan,
4041                                                   src_extra_alpha);
4042                break;
4043            case 1+2+8:
4044                _CompositeRow_1bppRgb2Argb_NoBlend(dest_scan, src_scan, src_left, width, m_pSrcPalette, clip_scan);
4045                break;
4046            case 0:
4047                _CompositeRow_8bppRgb2Rgb_NoBlend(dest_scan, src_scan, m_pSrcPalette, width, (m_DestFormat & 0xff) >> 3, clip_scan,
4048                                                  src_extra_alpha);
4049                break;
4050            case 0+8:
4051                _CompositeRow_1bppRgb2Rgb_NoBlend(dest_scan, src_scan, src_left, m_pSrcPalette, width, (m_DestFormat & 0xff) >> 3, clip_scan);
4052                break;
4053            case 0+2:
4054                _CompositeRow_8bppRgb2Rgb_NoBlend(dest_scan, src_scan, m_pSrcPalette, width, (m_DestFormat & 0xff) >> 3, clip_scan,
4055                                                  src_extra_alpha);
4056                break;
4057            case 0+2+8:
4058                _CompositeRow_1bppRgb2Rgba_NoBlend(dest_scan, src_scan, src_left, width, m_pSrcPalette, clip_scan,
4059                                                   dst_extra_alpha);
4060                break;
4061                break;
4062        }
4063    }
4064}
4065void CFX_ScanlineCompositor::CompositeByteMaskLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan,
4066        FX_LPBYTE dst_extra_alpha)
4067{
4068    if (m_DestFormat == FXDIB_8bppMask) {
4069        _CompositeRow_ByteMask2Mask(dest_scan, src_scan, m_MaskAlpha, width, clip_scan);
4070    } else if ((m_DestFormat & 0xff) == 8) {
4071        if (m_DestFormat & 0x0200) {
4072            _CompositeRow_ByteMask2Graya(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, width, clip_scan, dst_extra_alpha);
4073        } else {
4074            _CompositeRow_ByteMask2Gray(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, width, clip_scan);
4075        }
4076    } else if (m_bRgbByteOrder) {
4077        if (m_DestFormat == FXDIB_Argb)
4078            _CompositeRow_ByteMask2Argb_RgbByteOrder(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4079                    width, m_BlendType, clip_scan);
4080        else
4081            _CompositeRow_ByteMask2Rgb_RgbByteOrder(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4082                                                    width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan);
4083        return;
4084    } else if (m_DestFormat == FXDIB_Argb)
4085        _CompositeRow_ByteMask2Argb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4086                                    width, m_BlendType, clip_scan);
4087    else if (m_DestFormat == FXDIB_Rgb || m_DestFormat == FXDIB_Rgb32)
4088        _CompositeRow_ByteMask2Rgb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4089                                   width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan);
4090    else if (m_DestFormat == FXDIB_Rgba)
4091        _CompositeRow_ByteMask2Rgba(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4092                                    width, m_BlendType, clip_scan, dst_extra_alpha);
4093}
4094void CFX_ScanlineCompositor::CompositeBitMaskLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width, FX_LPCBYTE clip_scan,
4095        FX_LPBYTE dst_extra_alpha)
4096{
4097    if (m_DestFormat == FXDIB_8bppMask) {
4098        _CompositeRow_BitMask2Mask(dest_scan, src_scan, m_MaskAlpha, src_left, width, clip_scan);
4099    } else if ((m_DestFormat & 0xff) == 8) {
4100        if (m_DestFormat & 0x0200)
4101            _CompositeRow_BitMask2Graya(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, src_left, width, clip_scan,
4102                                        dst_extra_alpha);
4103        else {
4104            _CompositeRow_BitMask2Gray(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, src_left, width, clip_scan);
4105        }
4106    } else if (m_bRgbByteOrder) {
4107        if (m_DestFormat == FXDIB_Argb)
4108            _CompositeRow_BitMask2Argb_RgbByteOrder(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4109                                                    src_left, width, m_BlendType, clip_scan);
4110        else
4111            _CompositeRow_BitMask2Rgb_RgbByteOrder(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4112                                                   src_left, width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan);
4113        return;
4114    } else if (m_DestFormat == FXDIB_Argb)
4115        _CompositeRow_BitMask2Argb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4116                                   src_left, width, m_BlendType, clip_scan);
4117    else if (m_DestFormat == FXDIB_Rgb || m_DestFormat == FXDIB_Rgb32)
4118        _CompositeRow_BitMask2Rgb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
4119                                  src_left, width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan);
4120}
4121FX_BOOL CFX_DIBitmap::CompositeBitmap(int dest_left, int dest_top, int width, int height,
4122                                      const CFX_DIBSource* pSrcBitmap, int src_left, int src_top,
4123                                      int blend_type, const CFX_ClipRgn* pClipRgn, FX_BOOL bRgbByteOrder, void* pIccTransform)
4124{
4125    if (m_pBuffer == NULL) {
4126        return FALSE;
4127    }
4128    ASSERT(!pSrcBitmap->IsAlphaMask());
4129    ASSERT(m_bpp >= 8);
4130    if (pSrcBitmap->IsAlphaMask() || m_bpp < 8) {
4131        return FALSE;
4132    }
4133    GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(),
4134                   src_left, src_top, pClipRgn);
4135    if (width == 0 || height == 0) {
4136        return TRUE;
4137    }
4138    const CFX_DIBitmap* pClipMask = NULL;
4139    FX_RECT clip_box;
4140    if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
4141        ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF);
4142        pClipMask = pClipRgn->GetMask();
4143        clip_box = pClipRgn->GetBox();
4144    }
4145    CFX_ScanlineCompositor compositor;
4146    if (!compositor.Init(GetFormat(), pSrcBitmap->GetFormat(), width, pSrcBitmap->GetPalette(), 0, blend_type,
4147                         pClipMask != NULL, bRgbByteOrder, 0, pIccTransform)) {
4148        return FALSE;
4149    }
4150    int dest_Bpp = m_bpp / 8;
4151    int src_Bpp = pSrcBitmap->GetBPP() / 8;
4152    FX_BOOL bRgb = FALSE;
4153    FX_BOOL bCmyk = FALSE;
4154    if (src_Bpp > 1) {
4155        if (pSrcBitmap->IsCmykImage()) {
4156            bCmyk = TRUE;
4157        } else {
4158            bRgb = TRUE;
4159        }
4160    }
4161    CFX_DIBitmap* pSrcAlphaMask = pSrcBitmap->m_pAlphaMask;
4162    for (int row = 0; row < height; row ++) {
4163        FX_LPBYTE dest_scan = m_pBuffer + (dest_top + row) * m_Pitch + dest_left * dest_Bpp;
4164        FX_LPCBYTE src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left * src_Bpp;
4165        FX_LPCBYTE src_scan_extra_alpha = pSrcAlphaMask ? pSrcAlphaMask->GetScanline(src_top + row) + src_left : NULL;
4166        FX_LPBYTE dst_scan_extra_alpha = m_pAlphaMask ? (FX_LPBYTE)m_pAlphaMask->GetScanline(dest_top + row) + dest_left : NULL;
4167        FX_LPCBYTE clip_scan = NULL;
4168        if (pClipMask) {
4169            clip_scan = pClipMask->m_pBuffer + (dest_top + row - clip_box.top) * pClipMask->m_Pitch + (dest_left - clip_box.left);
4170        }
4171        if (bRgb) {
4172            compositor.CompositeRgbBitmapLine(dest_scan, src_scan, width, clip_scan, src_scan_extra_alpha, dst_scan_extra_alpha);
4173        } else {
4174            compositor.CompositePalBitmapLine(dest_scan, src_scan, src_left, width, clip_scan, src_scan_extra_alpha, dst_scan_extra_alpha);
4175        }
4176    }
4177    return TRUE;
4178}
4179FX_BOOL CFX_DIBitmap::CompositeMask(int dest_left, int dest_top, int width, int height,
4180                                    const CFX_DIBSource* pMask, FX_DWORD color, int src_left, int src_top,
4181                                    int blend_type, const CFX_ClipRgn* pClipRgn, FX_BOOL bRgbByteOrder, int alpha_flag, void* pIccTransform)
4182{
4183    if (m_pBuffer == NULL) {
4184        return FALSE;
4185    }
4186    ASSERT(pMask->IsAlphaMask());
4187    ASSERT(m_bpp >= 8);
4188    if (!pMask->IsAlphaMask() || m_bpp < 8) {
4189        return FALSE;
4190    }
4191    GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(), pMask->GetHeight(), src_left, src_top, pClipRgn);
4192    if (width == 0 || height == 0) {
4193        return TRUE;
4194    }
4195    int src_alpha = (FX_BYTE)(alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color);
4196    if (src_alpha == 0) {
4197        return TRUE;
4198    }
4199    const CFX_DIBitmap* pClipMask = NULL;
4200    FX_RECT clip_box;
4201    if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
4202        ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF);
4203        pClipMask = pClipRgn->GetMask();
4204        clip_box = pClipRgn->GetBox();
4205    }
4206    int src_bpp = pMask->GetBPP();
4207    int Bpp = GetBPP() / 8;
4208    CFX_ScanlineCompositor compositor;
4209    if (!compositor.Init(GetFormat(), pMask->GetFormat(), width, NULL, color, blend_type, pClipMask != NULL, bRgbByteOrder, alpha_flag, pIccTransform)) {
4210        return FALSE;
4211    }
4212    for (int row = 0; row < height; row ++) {
4213        FX_LPBYTE dest_scan = m_pBuffer + (dest_top + row) * m_Pitch + dest_left * Bpp;
4214        FX_LPCBYTE src_scan = pMask->GetScanline(src_top + row);
4215        FX_LPBYTE dst_scan_extra_alpha = m_pAlphaMask ? (FX_LPBYTE)m_pAlphaMask->GetScanline(dest_top + row) + dest_left : NULL;
4216        FX_LPCBYTE clip_scan = NULL;
4217        if (pClipMask) {
4218            clip_scan = pClipMask->m_pBuffer + (dest_top + row - clip_box.top) * pClipMask->m_Pitch + (dest_left - clip_box.left);
4219        }
4220        if (src_bpp == 1) {
4221            compositor.CompositeBitMaskLine(dest_scan, src_scan, src_left, width, clip_scan, dst_scan_extra_alpha);
4222        } else {
4223            compositor.CompositeByteMaskLine(dest_scan, src_scan + src_left, width, clip_scan, dst_scan_extra_alpha);
4224        }
4225    }
4226    return TRUE;
4227}
4228FX_BOOL CFX_DIBitmap::CompositeRect(int left, int top, int width, int height, FX_DWORD color, int alpha_flag, void* pIccTransform)
4229{
4230    if (m_pBuffer == NULL) {
4231        return FALSE;
4232    }
4233    int src_alpha = (alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color);
4234    if (src_alpha == 0) {
4235        return TRUE;
4236    }
4237    FX_RECT rect(left, top, left + width, top + height);
4238    rect.Intersect(0, 0, m_Width, m_Height);
4239    if (rect.IsEmpty()) {
4240        return TRUE;
4241    }
4242    width = rect.Width();
4243    FX_DWORD dst_color;
4244    if (alpha_flag >> 8) {
4245        dst_color = FXCMYK_TODIB(color);
4246    } else {
4247        dst_color = FXARGB_TODIB(color);
4248    }
4249    FX_LPBYTE color_p = (FX_LPBYTE)&dst_color;
4250    if (m_bpp == 8) {
4251        FX_BYTE gray = 255;
4252        if (!IsAlphaMask()) {
4253            if (pIccTransform && CFX_GEModule::Get()->GetCodecModule() && CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) {
4254                ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
4255                pIccModule->TranslateScanline(pIccTransform, &gray, color_p, 1);
4256            } else {
4257                if (alpha_flag >> 8) {
4258                    FX_BYTE r, g, b;
4259                    AdobeCMYK_to_sRGB1(color_p[0], color_p[1], color_p[2], color_p[3],
4260                                       r, g, b);
4261                    gray = FXRGB2GRAY(r, g, b);
4262                } else {
4263                    gray = (FX_BYTE)FXRGB2GRAY((int)color_p[2], color_p[1], color_p[0]);
4264                }
4265            }
4266            if (IsCmykImage()) {
4267                gray = ~gray;
4268            }
4269        }
4270        for (int row = rect.top; row < rect.bottom; row ++) {
4271            FX_LPBYTE dest_scan = m_pBuffer + row * m_Pitch + rect.left;
4272            if (src_alpha == 255) {
4273                FXSYS_memset8(dest_scan, gray, width);
4274            } else
4275                for (int col = 0; col < width; col ++) {
4276                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
4277                    dest_scan ++;
4278                }
4279        }
4280        return TRUE;
4281    } else if (m_bpp == 1) {
4282        ASSERT(!IsCmykImage() && (FX_BYTE)(alpha_flag >> 8) == 0);
4283        int left_shift = rect.left % 8;
4284        int right_shift = rect.right % 8;
4285        int width = rect.right / 8 - rect.left / 8;
4286        int index = 0;
4287        if (m_pPalette == NULL) {
4288            index = ((FX_BYTE)color == 0xff) ? 1 : 0;
4289        } else {
4290            for (int i = 0; i < 2; i ++)
4291                if (m_pPalette[i] == color) {
4292                    index = i;
4293                }
4294        }
4295        for (int row = rect.top; row < rect.bottom; row ++) {
4296            FX_BYTE* dest_scan_top = (FX_BYTE*)GetScanline(row) + rect.left / 8;
4297            FX_BYTE* dest_scan_top_r = (FX_BYTE*)GetScanline(row) + rect.right / 8;
4298            FX_BYTE left_flag =  *dest_scan_top & (255 << (8 - left_shift));
4299            FX_BYTE right_flag = *dest_scan_top_r & (255 >> right_shift);
4300            if (width) {
4301                FXSYS_memset8(dest_scan_top + 1, index ? 255 : 0, width - 1);
4302                if (!index) {
4303                    *dest_scan_top &= left_flag;
4304                    *dest_scan_top_r &= right_flag;
4305                } else {
4306                    *dest_scan_top |= ~left_flag;
4307                    *dest_scan_top_r |= ~right_flag;
4308                }
4309            } else {
4310                if (!index) {
4311                    *dest_scan_top &= left_flag | right_flag;
4312                } else {
4313                    *dest_scan_top |= ~(left_flag | right_flag);
4314                }
4315            }
4316        }
4317        return TRUE;
4318    }
4319    ASSERT(m_bpp >= 24);
4320    if (m_bpp < 24) {
4321        return FALSE;
4322    }
4323    if (pIccTransform && CFX_GEModule::Get()->GetCodecModule()) {
4324        ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
4325        pIccModule->TranslateScanline(pIccTransform, color_p, color_p, 1);
4326    } else {
4327        if (alpha_flag >> 8 && !IsCmykImage())
4328            AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color), FXSYS_GetYValue(color), FXSYS_GetKValue(color),
4329                               color_p[2], color_p[1], color_p[0]);
4330        else if (!(alpha_flag >> 8) && IsCmykImage()) {
4331            return FALSE;
4332        }
4333    }
4334    if(!IsCmykImage()) {
4335        color_p[3] = (FX_BYTE)src_alpha;
4336    }
4337    int Bpp = m_bpp / 8;
4338    FX_BOOL bAlpha = HasAlpha();
4339    FX_BOOL bArgb = GetFormat() == FXDIB_Argb ? TRUE : FALSE;
4340    if (src_alpha == 255) {
4341        for (int row = rect.top; row < rect.bottom; row ++) {
4342            FX_LPBYTE dest_scan = m_pBuffer + row * m_Pitch + rect.left * Bpp;
4343            FX_LPBYTE dest_scan_alpha = m_pAlphaMask ? (FX_LPBYTE)m_pAlphaMask->GetScanline(row) + rect.left : NULL;
4344            if (dest_scan_alpha) {
4345                FXSYS_memset8(dest_scan_alpha, 0xff, width);
4346            }
4347            if (Bpp == 4) {
4348                FX_DWORD* scan = (FX_DWORD*)dest_scan;
4349                for (int col = 0; col < width; col ++) {
4350                    *scan ++ = dst_color;
4351                }
4352            } else {
4353                for (int col = 0; col < width; col ++) {
4354                    *dest_scan ++ = color_p[0];
4355                    *dest_scan ++ = color_p[1];
4356                    *dest_scan ++ = color_p[2];
4357                }
4358            }
4359        }
4360        return TRUE;
4361    }
4362    for (int row = rect.top; row < rect.bottom; row ++) {
4363        FX_LPBYTE dest_scan = m_pBuffer + row * m_Pitch + rect.left * Bpp;
4364        if (bAlpha) {
4365            if (bArgb) {
4366                for (int col = 0; col < width; col ++) {
4367                    FX_BYTE back_alpha = dest_scan[3];
4368                    if (back_alpha == 0) {
4369                        FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, color_p[2], color_p[1], color_p[0]));
4370                        dest_scan += 4;
4371                        continue;
4372                    }
4373                    FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
4374                    int alpha_ratio = src_alpha * 255 / dest_alpha;
4375                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[0], alpha_ratio);
4376                    dest_scan ++;
4377                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[1], alpha_ratio);
4378                    dest_scan ++;
4379                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[2], alpha_ratio);
4380                    dest_scan ++;
4381                    *dest_scan++ = dest_alpha;
4382                }
4383            } else {
4384                FX_LPBYTE dest_scan_alpha = (FX_LPBYTE)m_pAlphaMask->GetScanline(row) + rect.left;
4385                for (int col = 0; col < width; col ++) {
4386                    FX_BYTE back_alpha = *dest_scan_alpha;
4387                    if (back_alpha == 0) {
4388                        *dest_scan_alpha++ = src_alpha;
4389                        FXSYS_memcpy32(dest_scan, color_p, Bpp);
4390                        dest_scan += Bpp;
4391                        continue;
4392                    }
4393                    FX_BYTE dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
4394                    *dest_scan_alpha ++ = dest_alpha;
4395                    int alpha_ratio = src_alpha * 255 / dest_alpha;
4396                    for(int comps = 0; comps < Bpp; comps ++) {
4397                        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], alpha_ratio);
4398                        dest_scan ++;
4399                    }
4400                }
4401            }
4402        } else {
4403            for (int col = 0; col < width; col ++) {
4404                for(int comps = 0; comps < Bpp; comps ++) {
4405                    if (comps == 3) {
4406                        *dest_scan ++ = 255;
4407                        continue;
4408                    }
4409                    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], src_alpha);
4410                    dest_scan ++;
4411                }
4412            }
4413        }
4414    }
4415    return TRUE;
4416}
4417CFX_BitmapComposer::CFX_BitmapComposer()
4418{
4419    m_pScanlineV = NULL;
4420    m_pScanlineAlphaV = NULL;
4421    m_pClipScanV = NULL;
4422    m_pAddClipScan = NULL;
4423    m_bRgbByteOrder = FALSE;
4424    m_BlendType = FXDIB_BLEND_NORMAL;
4425}
4426CFX_BitmapComposer::~CFX_BitmapComposer()
4427{
4428    if (m_pScanlineV) {
4429        FX_Free(m_pScanlineV);
4430    }
4431    if (m_pScanlineAlphaV) {
4432        FX_Free(m_pScanlineAlphaV);
4433    }
4434    if (m_pClipScanV) {
4435        FX_Free(m_pClipScanV);
4436    }
4437    if (m_pAddClipScan) {
4438        FX_Free(m_pAddClipScan);
4439    }
4440}
4441void CFX_BitmapComposer::Compose(CFX_DIBitmap* pDest, const CFX_ClipRgn* pClipRgn, int bitmap_alpha,
4442                                 FX_DWORD mask_color, FX_RECT& dest_rect, FX_BOOL bVertical,
4443                                 FX_BOOL bFlipX, FX_BOOL bFlipY, FX_BOOL bRgbByteOrder,
4444                                 int alpha_flag, void* pIccTransform, int blend_type)
4445{
4446    m_pBitmap = pDest;
4447    m_pClipRgn = pClipRgn;
4448    m_DestLeft = dest_rect.left;
4449    m_DestTop = dest_rect.top;
4450    m_DestWidth = dest_rect.Width();
4451    m_DestHeight = dest_rect.Height();
4452    m_BitmapAlpha = bitmap_alpha;
4453    m_MaskColor = mask_color;
4454    m_pClipMask = NULL;
4455    if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
4456        m_pClipMask = pClipRgn->GetMask();
4457    }
4458    m_bVertical = bVertical;
4459    m_bFlipX = bFlipX;
4460    m_bFlipY = bFlipY;
4461    m_AlphaFlag = alpha_flag;
4462    m_pIccTransform = pIccTransform;
4463    m_bRgbByteOrder = bRgbByteOrder;
4464    m_BlendType = blend_type;
4465}
4466FX_BOOL CFX_BitmapComposer::SetInfo(int width, int height, FXDIB_Format src_format, FX_DWORD* pSrcPalette)
4467{
4468    m_SrcFormat = src_format;
4469    if (!m_Compositor.Init(m_pBitmap->GetFormat(), src_format, width, pSrcPalette, m_MaskColor, FXDIB_BLEND_NORMAL,
4470                           m_pClipMask != NULL || (m_BitmapAlpha < 255), m_bRgbByteOrder, m_AlphaFlag, m_pIccTransform)) {
4471        return FALSE;
4472    }
4473    if (m_bVertical) {
4474        m_pScanlineV = FX_Alloc(FX_BYTE, m_pBitmap->GetBPP() / 8 * width + 4);
4475        if (!m_pScanlineV) {
4476            return FALSE;
4477        }
4478        m_pClipScanV = FX_Alloc(FX_BYTE, m_pBitmap->GetHeight());
4479        if (!m_pClipScanV) {
4480            return FALSE;
4481        }
4482        if (m_pBitmap->m_pAlphaMask) {
4483            m_pScanlineAlphaV = FX_Alloc(FX_BYTE, width + 4);
4484            if (!m_pScanlineAlphaV) {
4485                return FALSE;
4486            }
4487        }
4488    }
4489    if (m_BitmapAlpha < 255) {
4490        m_pAddClipScan = FX_Alloc(FX_BYTE, m_bVertical ? m_pBitmap->GetHeight() : m_pBitmap->GetWidth());
4491        if (!m_pAddClipScan) {
4492            return FALSE;
4493        }
4494    }
4495    return TRUE;
4496}
4497void CFX_BitmapComposer::DoCompose(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int dest_width, FX_LPCBYTE clip_scan,
4498                                   FX_LPCBYTE src_extra_alpha, FX_LPBYTE dst_extra_alpha)
4499{
4500    if (m_BitmapAlpha < 255) {
4501        if (clip_scan) {
4502            for (int i = 0; i < dest_width; i ++) {
4503                m_pAddClipScan[i] = clip_scan[i] * m_BitmapAlpha / 255;
4504            }
4505        } else {
4506            FXSYS_memset8(m_pAddClipScan, m_BitmapAlpha, dest_width);
4507        }
4508        clip_scan = m_pAddClipScan;
4509    }
4510    if (m_SrcFormat == FXDIB_8bppMask) {
4511        m_Compositor.CompositeByteMaskLine(dest_scan, src_scan, dest_width, clip_scan, dst_extra_alpha);
4512    } else if ((m_SrcFormat & 0xff) == 8) {
4513        m_Compositor.CompositePalBitmapLine(dest_scan, src_scan, 0, dest_width, clip_scan, src_extra_alpha, dst_extra_alpha);
4514    } else {
4515        m_Compositor.CompositeRgbBitmapLine(dest_scan, src_scan, dest_width, clip_scan, src_extra_alpha, dst_extra_alpha);
4516    }
4517}
4518void CFX_BitmapComposer::ComposeScanline(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha)
4519{
4520    if (m_bVertical) {
4521        ComposeScanlineV(line, scanline, scan_extra_alpha);
4522        return;
4523    }
4524    FX_LPCBYTE clip_scan = NULL;
4525    if (m_pClipMask)
4526        clip_scan = m_pClipMask->GetBuffer() + (m_DestTop + line - m_pClipRgn->GetBox().top) *
4527                    m_pClipMask->GetPitch() + (m_DestLeft - m_pClipRgn->GetBox().left);
4528    FX_LPBYTE dest_scan = (FX_LPBYTE)m_pBitmap->GetScanline(line + m_DestTop) +
4529                          m_DestLeft * m_pBitmap->GetBPP() / 8;
4530    FX_LPBYTE dest_alpha_scan = m_pBitmap->m_pAlphaMask ?
4531                                (FX_LPBYTE)m_pBitmap->m_pAlphaMask->GetScanline(line + m_DestTop) + m_DestLeft : NULL;
4532    DoCompose(dest_scan, scanline, m_DestWidth, clip_scan, scan_extra_alpha, dest_alpha_scan);
4533}
4534void CFX_BitmapComposer::ComposeScanlineV(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha)
4535{
4536    int i;
4537    int Bpp = m_pBitmap->GetBPP() / 8;
4538    int dest_pitch = m_pBitmap->GetPitch();
4539    int dest_alpha_pitch = m_pBitmap->m_pAlphaMask ? m_pBitmap->m_pAlphaMask->GetPitch() : 0;
4540    int dest_x = m_DestLeft + (m_bFlipX ? (m_DestWidth - line - 1) : line);
4541    FX_LPBYTE dest_buf = m_pBitmap->GetBuffer() + dest_x * Bpp + m_DestTop * dest_pitch;
4542    FX_LPBYTE dest_alpha_buf = m_pBitmap->m_pAlphaMask ?
4543                               m_pBitmap->m_pAlphaMask->GetBuffer() + dest_x + m_DestTop * dest_alpha_pitch : NULL;
4544    if (m_bFlipY) {
4545        dest_buf += dest_pitch * (m_DestHeight - 1);
4546        dest_alpha_buf += dest_alpha_pitch * (m_DestHeight - 1);
4547    }
4548    int y_step = dest_pitch;
4549    int y_alpha_step = dest_alpha_pitch;
4550    if (m_bFlipY) {
4551        y_step = -y_step;
4552        y_alpha_step = -y_alpha_step;
4553    }
4554    FX_LPBYTE src_scan = m_pScanlineV;
4555    FX_LPBYTE dest_scan = dest_buf;
4556    for (i = 0; i < m_DestHeight; i ++) {
4557        for (int j = 0; j < Bpp; j ++) {
4558            *src_scan++ = dest_scan[j];
4559        }
4560        dest_scan += y_step;
4561    }
4562    FX_LPBYTE src_alpha_scan = m_pScanlineAlphaV;
4563    FX_LPBYTE dest_alpha_scan = dest_alpha_buf;
4564    if (dest_alpha_scan) {
4565        for (i = 0; i < m_DestHeight; i ++) {
4566            *src_alpha_scan++ = *dest_alpha_scan;
4567            dest_alpha_scan += y_alpha_step;
4568        }
4569    }
4570    FX_LPBYTE clip_scan = NULL;
4571    if (m_pClipMask) {
4572        clip_scan = m_pClipScanV;
4573        int clip_pitch = m_pClipMask->GetPitch();
4574        FX_LPCBYTE src_clip = m_pClipMask->GetBuffer() + (m_DestTop - m_pClipRgn->GetBox().top) *
4575                              clip_pitch + (dest_x - m_pClipRgn->GetBox().left);
4576        if (m_bFlipY) {
4577            src_clip += clip_pitch * (m_DestHeight - 1);
4578            clip_pitch = -clip_pitch;
4579        }
4580        for (i = 0; i < m_DestHeight; i ++) {
4581            clip_scan[i] = *src_clip;
4582            src_clip += clip_pitch;
4583        }
4584    }
4585    DoCompose(m_pScanlineV, scanline, m_DestHeight, clip_scan, scan_extra_alpha, m_pScanlineAlphaV);
4586    src_scan = m_pScanlineV;
4587    dest_scan = dest_buf;
4588    for (i = 0; i < m_DestHeight; i ++) {
4589        for (int j = 0; j < Bpp; j ++) {
4590            dest_scan[j] = *src_scan++;
4591        }
4592        dest_scan += y_step;
4593    }
4594    src_alpha_scan = m_pScanlineAlphaV;
4595    dest_alpha_scan = dest_alpha_buf;
4596    if (dest_alpha_scan) {
4597        for (i = 0; i < m_DestHeight; i ++) {
4598            *dest_alpha_scan = *src_alpha_scan++;
4599            dest_alpha_scan += y_alpha_step;
4600        }
4601    }
4602}
4603