1// Copyright 2017 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 "core/fxge/dib/cfx_scanlinecompositor.h"
8
9#include <algorithm>
10
11#include "core/fxcodec/fx_codec.h"
12
13#define FX_CCOLOR(val) (255 - (val))
14#define FXDIB_ALPHA_UNION(dest, src) ((dest) + (src) - (dest) * (src) / 255)
15#define FXARGB_COPY(dest, src)                    \
16  *(dest) = *(src), *((dest) + 1) = *((src) + 1), \
17  *((dest) + 2) = *((src) + 2), *((dest) + 3) = *((src) + 3)
18#define FXARGB_RGBORDERCOPY(dest, src)                  \
19  *((dest) + 3) = *((src) + 3), *(dest) = *((src) + 2), \
20             *((dest) + 1) = *((src) + 1), *((dest) + 2) = *((src))
21
22namespace {
23
24const uint8_t color_sqrt[256] = {
25    0x00, 0x03, 0x07, 0x0B, 0x0F, 0x12, 0x16, 0x19, 0x1D, 0x20, 0x23, 0x26,
26    0x29, 0x2C, 0x2F, 0x32, 0x35, 0x37, 0x3A, 0x3C, 0x3F, 0x41, 0x43, 0x46,
27    0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x57, 0x59, 0x5B, 0x5C,
28    0x5E, 0x60, 0x61, 0x63, 0x64, 0x65, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D,
29    0x6E, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
30    0x7B, 0x7C, 0x7D, 0x7E, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
31    0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x91,
32    0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C,
33    0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA4, 0xA5,
34    0xA6, 0xA7, 0xA7, 0xA8, 0xA9, 0xAA, 0xAA, 0xAB, 0xAC, 0xAD, 0xAD, 0xAE,
35    0xAF, 0xB0, 0xB0, 0xB1, 0xB2, 0xB3, 0xB3, 0xB4, 0xB5, 0xB5, 0xB6, 0xB7,
36    0xB7, 0xB8, 0xB9, 0xBA, 0xBA, 0xBB, 0xBC, 0xBC, 0xBD, 0xBE, 0xBE, 0xBF,
37    0xC0, 0xC0, 0xC1, 0xC2, 0xC2, 0xC3, 0xC4, 0xC4, 0xC5, 0xC6, 0xC6, 0xC7,
38    0xC7, 0xC8, 0xC9, 0xC9, 0xCA, 0xCB, 0xCB, 0xCC, 0xCC, 0xCD, 0xCE, 0xCE,
39    0xCF, 0xD0, 0xD0, 0xD1, 0xD1, 0xD2, 0xD3, 0xD3, 0xD4, 0xD4, 0xD5, 0xD6,
40    0xD6, 0xD7, 0xD7, 0xD8, 0xD9, 0xD9, 0xDA, 0xDA, 0xDB, 0xDC, 0xDC, 0xDD,
41    0xDD, 0xDE, 0xDE, 0xDF, 0xE0, 0xE0, 0xE1, 0xE1, 0xE2, 0xE2, 0xE3, 0xE4,
42    0xE4, 0xE5, 0xE5, 0xE6, 0xE6, 0xE7, 0xE7, 0xE8, 0xE9, 0xE9, 0xEA, 0xEA,
43    0xEB, 0xEB, 0xEC, 0xEC, 0xED, 0xED, 0xEE, 0xEE, 0xEF, 0xF0, 0xF0, 0xF1,
44    0xF1, 0xF2, 0xF2, 0xF3, 0xF3, 0xF4, 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7,
45    0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFC, 0xFD,
46    0xFD, 0xFE, 0xFE, 0xFF};
47
48int Blend(int blend_mode, int back_color, int src_color) {
49  switch (blend_mode) {
50    case FXDIB_BLEND_NORMAL:
51      return src_color;
52    case FXDIB_BLEND_MULTIPLY:
53      return src_color * back_color / 255;
54    case FXDIB_BLEND_SCREEN:
55      return src_color + back_color - src_color * back_color / 255;
56    case FXDIB_BLEND_OVERLAY:
57      return Blend(FXDIB_BLEND_HARDLIGHT, src_color, back_color);
58    case FXDIB_BLEND_DARKEN:
59      return src_color < back_color ? src_color : back_color;
60    case FXDIB_BLEND_LIGHTEN:
61      return src_color > back_color ? src_color : back_color;
62    case FXDIB_BLEND_COLORDODGE: {
63      if (src_color == 255)
64        return src_color;
65
66      return std::min(back_color * 255 / (255 - src_color), 255);
67    }
68    case FXDIB_BLEND_COLORBURN: {
69      if (src_color == 0)
70        return src_color;
71
72      return 255 - std::min((255 - back_color) * 255 / src_color, 255);
73    }
74    case FXDIB_BLEND_HARDLIGHT:
75      if (src_color < 128)
76        return (src_color * back_color * 2) / 255;
77
78      return Blend(FXDIB_BLEND_SCREEN, back_color, 2 * src_color - 255);
79    case FXDIB_BLEND_SOFTLIGHT: {
80      if (src_color < 128) {
81        return back_color -
82               (255 - 2 * src_color) * back_color * (255 - back_color) / 255 /
83                   255;
84      }
85      return back_color +
86             (2 * src_color - 255) * (color_sqrt[back_color] - back_color) /
87                 255;
88    }
89    case FXDIB_BLEND_DIFFERENCE:
90      return back_color < src_color ? src_color - back_color
91                                    : back_color - src_color;
92    case FXDIB_BLEND_EXCLUSION:
93      return back_color + src_color - 2 * back_color * src_color / 255;
94  }
95  return src_color;
96}
97
98struct RGB {
99  int red;
100  int green;
101  int blue;
102};
103
104int Lum(RGB color) {
105  return (color.red * 30 + color.green * 59 + color.blue * 11) / 100;
106}
107
108RGB ClipColor(RGB color) {
109  int l = Lum(color);
110  int n = std::min(color.red, std::min(color.green, color.blue));
111  int x = std::max(color.red, std::max(color.green, color.blue));
112  if (n < 0) {
113    color.red = l + ((color.red - l) * l / (l - n));
114    color.green = l + ((color.green - l) * l / (l - n));
115    color.blue = l + ((color.blue - l) * l / (l - n));
116  }
117  if (x > 255) {
118    color.red = l + ((color.red - l) * (255 - l) / (x - l));
119    color.green = l + ((color.green - l) * (255 - l) / (x - l));
120    color.blue = l + ((color.blue - l) * (255 - l) / (x - l));
121  }
122  return color;
123}
124
125RGB SetLum(RGB color, int l) {
126  int d = l - Lum(color);
127  color.red += d;
128  color.green += d;
129  color.blue += d;
130  return ClipColor(color);
131}
132
133int Sat(RGB color) {
134  return std::max(color.red, std::max(color.green, color.blue)) -
135         std::min(color.red, std::min(color.green, color.blue));
136}
137
138RGB SetSat(RGB color, int s) {
139  int min = std::min(color.red, std::min(color.green, color.blue));
140  int max = std::max(color.red, std::max(color.green, color.blue));
141  if (min == max)
142    return {0, 0, 0};
143
144  color.red = (color.red - min) * s / (max - min);
145  color.green = (color.green - min) * s / (max - min);
146  color.blue = (color.blue - min) * s / (max - min);
147  return color;
148}
149
150void RGB_Blend(int blend_mode,
151               const uint8_t* src_scan,
152               const uint8_t* dest_scan,
153               int results[3]) {
154  RGB result = {0, 0, 0};
155  RGB src;
156  src.red = src_scan[2];
157  src.green = src_scan[1];
158  src.blue = src_scan[0];
159  RGB back;
160  back.red = dest_scan[2];
161  back.green = dest_scan[1];
162  back.blue = dest_scan[0];
163  switch (blend_mode) {
164    case FXDIB_BLEND_HUE:
165      result = SetLum(SetSat(src, Sat(back)), Lum(back));
166      break;
167    case FXDIB_BLEND_SATURATION:
168      result = SetLum(SetSat(back, Sat(src)), Lum(back));
169      break;
170    case FXDIB_BLEND_COLOR:
171      result = SetLum(src, Lum(back));
172      break;
173    case FXDIB_BLEND_LUMINOSITY:
174      result = SetLum(back, Lum(src));
175      break;
176  }
177  results[0] = result.blue;
178  results[1] = result.green;
179  results[2] = result.red;
180}
181
182int GetAlpha(uint8_t src_alpha, const uint8_t* clip_scan, int col) {
183  return clip_scan ? clip_scan[col] * src_alpha / 255 : src_alpha;
184}
185
186void CompositeRow_AlphaToMask(uint8_t* dest_scan,
187                              const uint8_t* src_scan,
188                              int pixel_count,
189                              const uint8_t* clip_scan,
190                              uint8_t stride) {
191  src_scan += stride - 1;
192  for (int col = 0; col < pixel_count; ++col) {
193    int src_alpha = GetAlpha(*src_scan, clip_scan, col);
194    uint8_t back_alpha = *dest_scan;
195    if (!back_alpha)
196      *dest_scan = src_alpha;
197    else if (src_alpha)
198      *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
199    ++dest_scan;
200    src_scan += stride;
201  }
202}
203
204void CompositeRow_Rgb2Mask(uint8_t* dest_scan,
205                           const uint8_t* src_scan,
206                           int width,
207                           const uint8_t* clip_scan) {
208  if (!clip_scan) {
209    memset(dest_scan, 0xff, width);
210    return;
211  }
212  for (int i = 0; i < width; ++i) {
213    *dest_scan = FXDIB_ALPHA_UNION(*dest_scan, *clip_scan);
214    ++dest_scan;
215    ++clip_scan;
216  }
217}
218
219uint8_t GetGray(const uint8_t* src_scan) {
220  return FXRGB2GRAY(src_scan[2], src_scan[1], *src_scan);
221}
222
223uint8_t GetGrayWithBlend(const uint8_t* src_scan,
224                         const uint8_t* dest_scan,
225                         int blend_type) {
226  uint8_t gray = GetGray(src_scan);
227  if (blend_type >= FXDIB_BLEND_NONSEPARABLE)
228    gray = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
229  else if (blend_type)
230    gray = Blend(blend_type, *dest_scan, gray);
231  return gray;
232}
233
234void CompositeRow_Argb2Graya(uint8_t* dest_scan,
235                             const uint8_t* src_scan,
236                             int pixel_count,
237                             int blend_type,
238                             const uint8_t* clip_scan,
239                             const uint8_t* src_alpha_scan,
240                             uint8_t* dst_alpha_scan) {
241  uint8_t offset = src_alpha_scan ? 3 : 4;
242  for (int col = 0; col < pixel_count; ++col) {
243    const uint8_t* alpha_scan =
244        src_alpha_scan ? src_alpha_scan++ : &src_scan[3];
245    uint8_t back_alpha = *dst_alpha_scan;
246    if (back_alpha == 0) {
247      int src_alpha = GetAlpha(*alpha_scan, clip_scan, col);
248      if (src_alpha) {
249        *dest_scan = GetGray(src_scan);
250        *dst_alpha_scan = src_alpha;
251      }
252      ++dest_scan;
253      ++dst_alpha_scan;
254      src_scan += offset;
255      continue;
256    }
257    uint8_t src_alpha = GetAlpha(*alpha_scan, clip_scan, col);
258    if (src_alpha == 0) {
259      ++dest_scan;
260      ++dst_alpha_scan;
261      src_scan += offset;
262      continue;
263    }
264    *dst_alpha_scan = FXDIB_ALPHA_UNION(back_alpha, src_alpha);
265    int alpha_ratio = src_alpha * 255 / (*dst_alpha_scan);
266    uint8_t gray = GetGray(src_scan);
267    // TODO(npm): Does this if really need src_alpha_scan or was that a bug?
268    if (blend_type && src_alpha_scan) {
269      if (blend_type >= FXDIB_BLEND_NONSEPARABLE)
270        gray = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
271      else
272        gray = Blend(blend_type, *dest_scan, gray);
273    }
274    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
275    ++dest_scan;
276    ++dst_alpha_scan;
277    src_scan += offset;
278  }
279}
280
281void CompositeRow_Argb2Gray(uint8_t* dest_scan,
282                            const uint8_t* src_scan,
283                            int pixel_count,
284                            int blend_type,
285                            const uint8_t* clip_scan,
286                            const uint8_t* src_alpha_scan) {
287  uint8_t gray;
288  uint8_t offset = src_alpha_scan ? 3 : 4;
289  for (int col = 0; col < pixel_count; ++col) {
290    const uint8_t* alpha_scan =
291        src_alpha_scan ? src_alpha_scan++ : &src_scan[3];
292    int src_alpha = GetAlpha(*alpha_scan, clip_scan, col);
293    if (src_alpha) {
294      gray = GetGrayWithBlend(src_scan, dest_scan, blend_type);
295      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
296    }
297    ++dest_scan;
298    src_scan += offset;
299  }
300}
301
302void CompositeRow_Rgb2Gray(uint8_t* dest_scan,
303                           const uint8_t* src_scan,
304                           int src_Bpp,
305                           int pixel_count,
306                           int blend_type,
307                           const uint8_t* clip_scan) {
308  uint8_t gray;
309  for (int col = 0; col < pixel_count; ++col) {
310    gray = GetGrayWithBlend(src_scan, dest_scan, blend_type);
311    if (clip_scan && clip_scan[col] < 255)
312      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
313    else
314      *dest_scan = gray;
315    ++dest_scan;
316    src_scan += src_Bpp;
317  }
318}
319
320void CompositeRow_Rgb2Graya(uint8_t* dest_scan,
321                            const uint8_t* src_scan,
322                            int src_Bpp,
323                            int pixel_count,
324                            int blend_type,
325                            const uint8_t* clip_scan,
326                            uint8_t* dest_alpha_scan) {
327  for (int col = 0; col < pixel_count; ++col) {
328    if (blend_type && *dest_alpha_scan == 0) {
329      *dest_scan = GetGray(src_scan);
330      ++dest_scan;
331      ++dest_alpha_scan;
332      src_scan += src_Bpp;
333      continue;
334    }
335    int src_alpha = clip_scan ? clip_scan[col] : 255;
336    if (src_alpha == 255) {
337      *dest_scan = GetGrayWithBlend(src_scan, dest_scan, blend_type);
338      ++dest_scan;
339      *dest_alpha_scan = 255;
340      ++dest_alpha_scan;
341      src_scan += src_Bpp;
342      continue;
343    }
344    if (src_alpha == 0) {
345      ++dest_scan;
346      ++dest_alpha_scan;
347      src_scan += src_Bpp;
348      continue;
349    }
350    int back_alpha = *dest_alpha_scan;
351    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
352    *dest_alpha_scan = dest_alpha;
353    ++dest_alpha_scan;
354    int alpha_ratio = src_alpha * 255 / dest_alpha;
355    uint8_t gray = GetGrayWithBlend(src_scan, dest_scan, blend_type);
356    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
357    ++dest_scan;
358    src_scan += src_Bpp;
359  }
360}
361
362void CompositeRow_Argb2Argb(uint8_t* dest_scan,
363                            const uint8_t* src_scan,
364                            int pixel_count,
365                            int blend_type,
366                            const uint8_t* clip_scan,
367                            uint8_t* dest_alpha_scan,
368                            const uint8_t* src_alpha_scan) {
369  int blended_colors[3];
370  uint8_t dest_offset = dest_alpha_scan ? 3 : 4;
371  uint8_t src_offset = src_alpha_scan ? 3 : 4;
372  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
373  bool has_src = !!src_alpha_scan;
374  bool has_dest = !!dest_alpha_scan;
375  for (int col = 0; col < pixel_count; ++col) {
376    uint8_t back_alpha = has_dest ? *dest_alpha_scan : dest_scan[3];
377    const uint8_t* alpha_source = has_src ? src_alpha_scan++ : &src_scan[3];
378    uint8_t src_alpha = GetAlpha(*alpha_source, clip_scan, col);
379    if (back_alpha == 0) {
380      if (!has_dest && !has_src) {
381        if (clip_scan) {
382          FXARGB_SETDIB(dest_scan, (FXARGB_GETDIB(src_scan) & 0xffffff) |
383                                       (src_alpha << 24));
384        } else {
385          FXARGB_COPY(dest_scan, src_scan);
386        }
387      } else if (has_dest) {
388        *dest_alpha_scan = src_alpha;
389        for (int i = 0; i < 3; ++i) {
390          *dest_scan = *src_scan++;
391          ++dest_scan;
392        }
393        ++dest_alpha_scan;
394        if (!has_src)
395          ++src_scan;
396      } else {
397        FXARGB_SETDIB(dest_scan, FXARGB_MAKE((src_alpha << 24), src_scan[2],
398                                             src_scan[1], *src_scan));
399      }
400      if (!has_dest) {
401        dest_scan += dest_offset;
402        src_scan += src_offset;
403      }
404      continue;
405    }
406    if (src_alpha == 0) {
407      dest_scan += dest_offset;
408      src_scan += src_offset;
409      if (has_dest)
410        ++dest_alpha_scan;
411      continue;
412    }
413    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
414    if (has_dest) {
415      *dest_alpha_scan = dest_alpha;
416      ++dest_alpha_scan;
417    } else {
418      dest_scan[3] = dest_alpha;
419    }
420    int alpha_ratio = src_alpha * 255 / dest_alpha;
421    if (bNonseparableBlend)
422      RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
423    for (int color = 0; color < 3; ++color) {
424      if (blend_type) {
425        int blended = bNonseparableBlend
426                          ? blended_colors[color]
427                          : Blend(blend_type, *dest_scan, *src_scan);
428        blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha);
429        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
430      } else {
431        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
432      }
433      ++dest_scan;
434      ++src_scan;
435    }
436    if (!has_dest)
437      ++dest_scan;
438    if (!has_src)
439      ++src_scan;
440  }
441}
442
443void CompositeRow_Rgb2Argb_Blend_NoClip(uint8_t* dest_scan,
444                                        const uint8_t* src_scan,
445                                        int width,
446                                        int blend_type,
447                                        int src_Bpp,
448                                        uint8_t* dest_alpha_scan) {
449  int blended_colors[3];
450  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
451  int src_gap = src_Bpp - 3;
452  for (int col = 0; col < width; ++col) {
453    uint8_t* dest_alpha = dest_alpha_scan ? dest_alpha_scan : &dest_scan[3];
454    uint8_t back_alpha = *dest_alpha;
455    if (back_alpha == 0) {
456      if (dest_alpha_scan) {
457        for (int i = 0; i < 3; ++i) {
458          *dest_scan = *src_scan++;
459          ++dest_scan;
460        }
461        *dest_alpha_scan = 0xff;
462        ++dest_alpha_scan;
463      } else {
464        if (src_Bpp == 4) {
465          FXARGB_SETDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan));
466        } else {
467          FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[2], src_scan[1],
468                                               src_scan[0]));
469        }
470        dest_scan += 4;
471      }
472      src_scan += src_Bpp;
473      continue;
474    }
475    *dest_alpha = 0xff;
476    if (bNonseparableBlend)
477      RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
478    for (int color = 0; color < 3; ++color) {
479      int src_color = *src_scan;
480      int blended = bNonseparableBlend
481                        ? blended_colors[color]
482                        : Blend(blend_type, *dest_scan, src_color);
483      *dest_scan = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
484      ++dest_scan;
485      ++src_scan;
486    }
487    if (dest_alpha_scan)
488      ++dest_alpha_scan;
489    else
490      ++dest_scan;
491    src_scan += src_gap;
492  }
493}
494
495void CompositeRow_Rgb2Argb_Blend_Clip(uint8_t* dest_scan,
496                                      const uint8_t* src_scan,
497                                      int width,
498                                      int blend_type,
499                                      int src_Bpp,
500                                      const uint8_t* clip_scan,
501                                      uint8_t* dest_alpha_scan) {
502  int blended_colors[3];
503  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
504  int src_gap = src_Bpp - 3;
505  bool has_dest = !!dest_alpha_scan;
506  for (int col = 0; col < width; ++col) {
507    int src_alpha = *clip_scan++;
508    uint8_t back_alpha = has_dest ? *dest_alpha_scan : dest_scan[3];
509    if (back_alpha == 0) {
510      for (int i = 0; i < 3; ++i) {
511        *dest_scan = *src_scan++;
512        ++dest_scan;
513      }
514      src_scan += src_gap;
515      if (has_dest)
516        dest_alpha_scan++;
517      else
518        dest_scan++;
519      continue;
520    }
521    if (src_alpha == 0) {
522      dest_scan += has_dest ? 3 : 4;
523      if (has_dest)
524        dest_alpha_scan++;
525      src_scan += src_Bpp;
526      continue;
527    }
528    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
529    if (has_dest)
530      *dest_alpha_scan++ = dest_alpha;
531    else
532      dest_scan[3] = dest_alpha;
533    int alpha_ratio = src_alpha * 255 / dest_alpha;
534    if (bNonseparableBlend)
535      RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
536    for (int color = 0; color < 3; color++) {
537      int src_color = *src_scan;
538      int blended = bNonseparableBlend
539                        ? blended_colors[color]
540                        : Blend(blend_type, *dest_scan, src_color);
541      blended = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
542      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
543      dest_scan++;
544      src_scan++;
545    }
546    src_scan += src_gap;
547    if (!has_dest)
548      dest_scan++;
549  }
550}
551
552void CompositeRow_Rgb2Argb_NoBlend_Clip(uint8_t* dest_scan,
553                                        const uint8_t* src_scan,
554                                        int width,
555                                        int src_Bpp,
556                                        const uint8_t* clip_scan,
557                                        uint8_t* dest_alpha_scan) {
558  int src_gap = src_Bpp - 3;
559  if (dest_alpha_scan) {
560    for (int col = 0; col < width; col++) {
561      int src_alpha = clip_scan[col];
562      if (src_alpha == 255) {
563        *dest_scan++ = *src_scan++;
564        *dest_scan++ = *src_scan++;
565        *dest_scan++ = *src_scan++;
566        *dest_alpha_scan++ = 255;
567        src_scan += src_gap;
568        continue;
569      }
570      if (src_alpha == 0) {
571        dest_scan += 3;
572        dest_alpha_scan++;
573        src_scan += src_Bpp;
574        continue;
575      }
576      int back_alpha = *dest_alpha_scan;
577      uint8_t dest_alpha =
578          back_alpha + src_alpha - back_alpha * src_alpha / 255;
579      *dest_alpha_scan++ = dest_alpha;
580      int alpha_ratio = src_alpha * 255 / dest_alpha;
581      for (int color = 0; color < 3; color++) {
582        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
583        dest_scan++;
584        src_scan++;
585      }
586      src_scan += src_gap;
587    }
588  } else {
589    for (int col = 0; col < width; col++) {
590      int src_alpha = clip_scan[col];
591      if (src_alpha == 255) {
592        *dest_scan++ = *src_scan++;
593        *dest_scan++ = *src_scan++;
594        *dest_scan++ = *src_scan++;
595        *dest_scan++ = 255;
596        src_scan += src_gap;
597        continue;
598      }
599      if (src_alpha == 0) {
600        dest_scan += 4;
601        src_scan += src_Bpp;
602        continue;
603      }
604      int back_alpha = dest_scan[3];
605      uint8_t dest_alpha =
606          back_alpha + src_alpha - back_alpha * src_alpha / 255;
607      dest_scan[3] = dest_alpha;
608      int alpha_ratio = src_alpha * 255 / dest_alpha;
609      for (int color = 0; color < 3; color++) {
610        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, alpha_ratio);
611        dest_scan++;
612        src_scan++;
613      }
614      dest_scan++;
615      src_scan += src_gap;
616    }
617  }
618}
619
620void CompositeRow_Rgb2Argb_NoBlend_NoClip(uint8_t* dest_scan,
621                                          const uint8_t* src_scan,
622                                          int width,
623                                          int src_Bpp,
624                                          uint8_t* dest_alpha_scan) {
625  if (dest_alpha_scan) {
626    int src_gap = src_Bpp - 3;
627    for (int col = 0; col < width; col++) {
628      *dest_scan++ = *src_scan++;
629      *dest_scan++ = *src_scan++;
630      *dest_scan++ = *src_scan++;
631      *dest_alpha_scan++ = 0xff;
632      src_scan += src_gap;
633    }
634  } else {
635    for (int col = 0; col < width; col++) {
636      if (src_Bpp == 4) {
637        FXARGB_SETDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan));
638      } else {
639        FXARGB_SETDIB(dest_scan,
640                      FXARGB_MAKE(0xff, src_scan[2], src_scan[1], src_scan[0]));
641      }
642      dest_scan += 4;
643      src_scan += src_Bpp;
644    }
645  }
646}
647
648void CompositeRow_Argb2Rgb_Blend(uint8_t* dest_scan,
649                                 const uint8_t* src_scan,
650                                 int width,
651                                 int blend_type,
652                                 int dest_Bpp,
653                                 const uint8_t* clip_scan,
654                                 const uint8_t* src_alpha_scan) {
655  int blended_colors[3];
656  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
657  int dest_gap = dest_Bpp - 3;
658  if (src_alpha_scan) {
659    for (int col = 0; col < width; col++) {
660      uint8_t src_alpha;
661      if (clip_scan) {
662        src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255;
663      } else {
664        src_alpha = *src_alpha_scan++;
665      }
666      if (src_alpha == 0) {
667        dest_scan += dest_Bpp;
668        src_scan += 3;
669        continue;
670      }
671      if (bNonseparableBlend) {
672        RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
673      }
674      for (int color = 0; color < 3; color++) {
675        int back_color = *dest_scan;
676        int blended = bNonseparableBlend
677                          ? blended_colors[color]
678                          : Blend(blend_type, back_color, *src_scan);
679        *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
680        dest_scan++;
681        src_scan++;
682      }
683      dest_scan += dest_gap;
684    }
685  } else {
686    for (int col = 0; col < width; col++) {
687      uint8_t src_alpha;
688      if (clip_scan) {
689        src_alpha = src_scan[3] * (*clip_scan++) / 255;
690      } else {
691        src_alpha = src_scan[3];
692      }
693      if (src_alpha == 0) {
694        dest_scan += dest_Bpp;
695        src_scan += 4;
696        continue;
697      }
698      if (bNonseparableBlend) {
699        RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
700      }
701      for (int color = 0; color < 3; color++) {
702        int back_color = *dest_scan;
703        int blended = bNonseparableBlend
704                          ? blended_colors[color]
705                          : Blend(blend_type, back_color, *src_scan);
706        *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
707        dest_scan++;
708        src_scan++;
709      }
710      dest_scan += dest_gap;
711      src_scan++;
712    }
713  }
714}
715
716void CompositeRow_Argb2Rgb_NoBlend(uint8_t* dest_scan,
717                                   const uint8_t* src_scan,
718                                   int width,
719                                   int dest_Bpp,
720                                   const uint8_t* clip_scan,
721                                   const uint8_t* src_alpha_scan) {
722  int dest_gap = dest_Bpp - 3;
723  if (src_alpha_scan) {
724    for (int col = 0; col < width; col++) {
725      uint8_t src_alpha;
726      if (clip_scan) {
727        src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255;
728      } else {
729        src_alpha = *src_alpha_scan++;
730      }
731      if (src_alpha == 255) {
732        *dest_scan++ = *src_scan++;
733        *dest_scan++ = *src_scan++;
734        *dest_scan++ = *src_scan++;
735        dest_scan += dest_gap;
736        continue;
737      }
738      if (src_alpha == 0) {
739        dest_scan += dest_Bpp;
740        src_scan += 3;
741        continue;
742      }
743      for (int color = 0; color < 3; color++) {
744        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
745        dest_scan++;
746        src_scan++;
747      }
748      dest_scan += dest_gap;
749    }
750  } else {
751    for (int col = 0; col < width; col++) {
752      uint8_t src_alpha;
753      if (clip_scan) {
754        src_alpha = src_scan[3] * (*clip_scan++) / 255;
755      } else {
756        src_alpha = src_scan[3];
757      }
758      if (src_alpha == 255) {
759        *dest_scan++ = *src_scan++;
760        *dest_scan++ = *src_scan++;
761        *dest_scan++ = *src_scan++;
762        dest_scan += dest_gap;
763        src_scan++;
764        continue;
765      }
766      if (src_alpha == 0) {
767        dest_scan += dest_Bpp;
768        src_scan += 4;
769        continue;
770      }
771      for (int color = 0; color < 3; color++) {
772        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
773        dest_scan++;
774        src_scan++;
775      }
776      dest_scan += dest_gap;
777      src_scan++;
778    }
779  }
780}
781
782void CompositeRow_Rgb2Rgb_Blend_NoClip(uint8_t* dest_scan,
783                                       const uint8_t* src_scan,
784                                       int width,
785                                       int blend_type,
786                                       int dest_Bpp,
787                                       int src_Bpp) {
788  int blended_colors[3];
789  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
790  int dest_gap = dest_Bpp - 3;
791  int src_gap = src_Bpp - 3;
792  for (int col = 0; col < width; col++) {
793    if (bNonseparableBlend) {
794      RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
795    }
796    for (int color = 0; color < 3; color++) {
797      int back_color = *dest_scan;
798      int src_color = *src_scan;
799      int blended = bNonseparableBlend
800                        ? blended_colors[color]
801                        : Blend(blend_type, back_color, src_color);
802      *dest_scan = blended;
803      dest_scan++;
804      src_scan++;
805    }
806    dest_scan += dest_gap;
807    src_scan += src_gap;
808  }
809}
810
811void CompositeRow_Rgb2Rgb_Blend_Clip(uint8_t* dest_scan,
812                                     const uint8_t* src_scan,
813                                     int width,
814                                     int blend_type,
815                                     int dest_Bpp,
816                                     int src_Bpp,
817                                     const uint8_t* clip_scan) {
818  int blended_colors[3];
819  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
820  int dest_gap = dest_Bpp - 3;
821  int src_gap = src_Bpp - 3;
822  for (int col = 0; col < width; col++) {
823    uint8_t src_alpha = *clip_scan++;
824    if (src_alpha == 0) {
825      dest_scan += dest_Bpp;
826      src_scan += src_Bpp;
827      continue;
828    }
829    if (bNonseparableBlend) {
830      RGB_Blend(blend_type, src_scan, dest_scan, blended_colors);
831    }
832    for (int color = 0; color < 3; color++) {
833      int src_color = *src_scan;
834      int back_color = *dest_scan;
835      int blended = bNonseparableBlend
836                        ? blended_colors[color]
837                        : Blend(blend_type, back_color, src_color);
838      *dest_scan = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
839      dest_scan++;
840      src_scan++;
841    }
842    dest_scan += dest_gap;
843    src_scan += src_gap;
844  }
845}
846
847void CompositeRow_Rgb2Rgb_NoBlend_NoClip(uint8_t* dest_scan,
848                                         const uint8_t* src_scan,
849                                         int width,
850                                         int dest_Bpp,
851                                         int src_Bpp) {
852  if (dest_Bpp == src_Bpp) {
853    memcpy(dest_scan, src_scan, width * dest_Bpp);
854    return;
855  }
856  for (int col = 0; col < width; col++) {
857    dest_scan[0] = src_scan[0];
858    dest_scan[1] = src_scan[1];
859    dest_scan[2] = src_scan[2];
860    dest_scan += dest_Bpp;
861    src_scan += src_Bpp;
862  }
863}
864
865void CompositeRow_Rgb2Rgb_NoBlend_Clip(uint8_t* dest_scan,
866                                       const uint8_t* src_scan,
867                                       int width,
868                                       int dest_Bpp,
869                                       int src_Bpp,
870                                       const uint8_t* clip_scan) {
871  for (int col = 0; col < width; col++) {
872    int src_alpha = clip_scan[col];
873    if (src_alpha == 255) {
874      dest_scan[0] = src_scan[0];
875      dest_scan[1] = src_scan[1];
876      dest_scan[2] = src_scan[2];
877    } else if (src_alpha) {
878      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
879      dest_scan++;
880      src_scan++;
881      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
882      dest_scan++;
883      src_scan++;
884      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, *src_scan, src_alpha);
885      dest_scan += dest_Bpp - 2;
886      src_scan += src_Bpp - 2;
887      continue;
888    }
889    dest_scan += dest_Bpp;
890    src_scan += src_Bpp;
891  }
892}
893
894void CompositeRow_8bppPal2Gray(uint8_t* dest_scan,
895                               const uint8_t* src_scan,
896                               const uint8_t* pPalette,
897                               int pixel_count,
898                               int blend_type,
899                               const uint8_t* clip_scan,
900                               const uint8_t* src_alpha_scan) {
901  if (src_alpha_scan) {
902    if (blend_type) {
903      bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
904      for (int col = 0; col < pixel_count; col++) {
905        uint8_t gray = pPalette[*src_scan];
906        int src_alpha = GetAlpha(*src_alpha_scan++, clip_scan, col);
907        if (bNonseparableBlend)
908          gray = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
909        else
910          gray = Blend(blend_type, *dest_scan, gray);
911        if (src_alpha)
912          *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
913        else
914          *dest_scan = gray;
915        dest_scan++;
916        src_scan++;
917      }
918      return;
919    }
920    for (int col = 0; col < pixel_count; col++) {
921      uint8_t gray = pPalette[*src_scan];
922      int src_alpha = GetAlpha(*src_alpha_scan++, clip_scan, col);
923      if (src_alpha)
924        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
925      else
926        *dest_scan = gray;
927      dest_scan++;
928      src_scan++;
929    }
930  } else {
931    if (blend_type) {
932      bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
933      for (int col = 0; col < pixel_count; col++) {
934        uint8_t gray = pPalette[*src_scan];
935        if (bNonseparableBlend)
936          gray = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
937        else
938          gray = Blend(blend_type, *dest_scan, gray);
939        if (clip_scan && clip_scan[col] < 255)
940          *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
941        else
942          *dest_scan = gray;
943        dest_scan++;
944        src_scan++;
945      }
946      return;
947    }
948    for (int col = 0; col < pixel_count; col++) {
949      uint8_t gray = pPalette[*src_scan];
950      if (clip_scan && clip_scan[col] < 255)
951        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
952      else
953        *dest_scan = gray;
954      dest_scan++;
955      src_scan++;
956    }
957  }
958}
959
960void CompositeRow_8bppPal2Graya(uint8_t* dest_scan,
961                                const uint8_t* src_scan,
962                                const uint8_t* pPalette,
963                                int pixel_count,
964                                int blend_type,
965                                const uint8_t* clip_scan,
966                                uint8_t* dest_alpha_scan,
967                                const uint8_t* src_alpha_scan) {
968  if (src_alpha_scan) {
969    if (blend_type) {
970      bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
971      for (int col = 0; col < pixel_count; col++) {
972        uint8_t gray = pPalette[*src_scan];
973        src_scan++;
974        uint8_t back_alpha = *dest_alpha_scan;
975        if (back_alpha == 0) {
976          int src_alpha = GetAlpha(*src_alpha_scan++, clip_scan, col);
977          if (src_alpha) {
978            *dest_scan = gray;
979            *dest_alpha_scan = src_alpha;
980          }
981          dest_scan++;
982          dest_alpha_scan++;
983          continue;
984        }
985        uint8_t src_alpha = GetAlpha(*src_alpha_scan++, clip_scan, col);
986        if (src_alpha == 0) {
987          dest_scan++;
988          dest_alpha_scan++;
989          continue;
990        }
991        *dest_alpha_scan =
992            back_alpha + src_alpha - back_alpha * src_alpha / 255;
993        int alpha_ratio = src_alpha * 255 / (*dest_alpha_scan);
994        if (bNonseparableBlend)
995          gray = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
996        else
997          gray = Blend(blend_type, *dest_scan, gray);
998        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
999        dest_alpha_scan++;
1000        dest_scan++;
1001      }
1002      return;
1003    }
1004    for (int col = 0; col < pixel_count; col++) {
1005      uint8_t gray = pPalette[*src_scan];
1006      src_scan++;
1007      uint8_t back_alpha = *dest_alpha_scan;
1008      if (back_alpha == 0) {
1009        int src_alpha = GetAlpha(*src_alpha_scan++, clip_scan, col);
1010        if (src_alpha) {
1011          *dest_scan = gray;
1012          *dest_alpha_scan = src_alpha;
1013        }
1014        dest_scan++;
1015        dest_alpha_scan++;
1016        continue;
1017      }
1018      uint8_t src_alpha = GetAlpha(*src_alpha_scan++, clip_scan, col);
1019      if (src_alpha == 0) {
1020        dest_scan++;
1021        dest_alpha_scan++;
1022        continue;
1023      }
1024      *dest_alpha_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1025      int alpha_ratio = src_alpha * 255 / (*dest_alpha_scan);
1026      dest_alpha_scan++;
1027      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1028      dest_scan++;
1029    }
1030  } else {
1031    if (blend_type) {
1032      bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1033      for (int col = 0; col < pixel_count; col++) {
1034        uint8_t gray = pPalette[*src_scan];
1035        src_scan++;
1036        if (!clip_scan || clip_scan[col] == 255) {
1037          *dest_scan++ = gray;
1038          *dest_alpha_scan++ = 255;
1039          continue;
1040        }
1041        int src_alpha = clip_scan[col];
1042        if (src_alpha == 0) {
1043          dest_scan++;
1044          dest_alpha_scan++;
1045          continue;
1046        }
1047        int back_alpha = *dest_alpha_scan;
1048        uint8_t dest_alpha =
1049            back_alpha + src_alpha - back_alpha * src_alpha / 255;
1050        *dest_alpha_scan++ = dest_alpha;
1051        int alpha_ratio = src_alpha * 255 / dest_alpha;
1052        if (bNonseparableBlend)
1053          gray = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1054        else
1055          gray = Blend(blend_type, *dest_scan, gray);
1056        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1057        dest_scan++;
1058      }
1059      return;
1060    }
1061    for (int col = 0; col < pixel_count; col++) {
1062      uint8_t gray = pPalette[*src_scan];
1063      src_scan++;
1064      if (!clip_scan || clip_scan[col] == 255) {
1065        *dest_scan++ = gray;
1066        *dest_alpha_scan++ = 255;
1067        continue;
1068      }
1069      int src_alpha = clip_scan[col];
1070      if (src_alpha == 0) {
1071        dest_scan++;
1072        dest_alpha_scan++;
1073        continue;
1074      }
1075      int back_alpha = *dest_alpha_scan;
1076      uint8_t dest_alpha =
1077          back_alpha + src_alpha - back_alpha * src_alpha / 255;
1078      *dest_alpha_scan++ = dest_alpha;
1079      int alpha_ratio = src_alpha * 255 / dest_alpha;
1080      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1081      dest_scan++;
1082    }
1083  }
1084}
1085
1086void CompositeRow_1bppPal2Gray(uint8_t* dest_scan,
1087                               const uint8_t* src_scan,
1088                               int src_left,
1089                               const uint8_t* pPalette,
1090                               int pixel_count,
1091                               int blend_type,
1092                               const uint8_t* clip_scan) {
1093  int reset_gray = pPalette[0];
1094  int set_gray = pPalette[1];
1095  if (blend_type) {
1096    bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1097    for (int col = 0; col < pixel_count; col++) {
1098      uint8_t gray =
1099          (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8)))
1100              ? set_gray
1101              : reset_gray;
1102      if (bNonseparableBlend)
1103        gray = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1104      else
1105        gray = Blend(blend_type, *dest_scan, gray);
1106      if (clip_scan && clip_scan[col] < 255) {
1107        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
1108      } else {
1109        *dest_scan = gray;
1110      }
1111      dest_scan++;
1112    }
1113    return;
1114  }
1115  for (int col = 0; col < pixel_count; col++) {
1116    uint8_t gray =
1117        (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8)))
1118            ? set_gray
1119            : reset_gray;
1120    if (clip_scan && clip_scan[col] < 255) {
1121      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, clip_scan[col]);
1122    } else {
1123      *dest_scan = gray;
1124    }
1125    dest_scan++;
1126  }
1127}
1128
1129void CompositeRow_1bppPal2Graya(uint8_t* dest_scan,
1130                                const uint8_t* src_scan,
1131                                int src_left,
1132                                const uint8_t* pPalette,
1133                                int pixel_count,
1134                                int blend_type,
1135                                const uint8_t* clip_scan,
1136                                uint8_t* dest_alpha_scan) {
1137  int reset_gray = pPalette[0];
1138  int set_gray = pPalette[1];
1139  if (blend_type) {
1140    bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
1141    for (int col = 0; col < pixel_count; col++) {
1142      uint8_t gray =
1143          (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8)))
1144              ? set_gray
1145              : reset_gray;
1146      if (!clip_scan || clip_scan[col] == 255) {
1147        *dest_scan++ = gray;
1148        *dest_alpha_scan++ = 255;
1149        continue;
1150      }
1151      int src_alpha = clip_scan[col];
1152      if (src_alpha == 0) {
1153        dest_scan++;
1154        dest_alpha_scan++;
1155        continue;
1156      }
1157      int back_alpha = *dest_alpha_scan;
1158      uint8_t dest_alpha =
1159          back_alpha + src_alpha - back_alpha * src_alpha / 255;
1160      *dest_alpha_scan++ = dest_alpha;
1161      int alpha_ratio = src_alpha * 255 / dest_alpha;
1162      if (bNonseparableBlend)
1163        gray = blend_type == FXDIB_BLEND_LUMINOSITY ? gray : *dest_scan;
1164      else
1165        gray = Blend(blend_type, *dest_scan, gray);
1166      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1167      dest_scan++;
1168    }
1169    return;
1170  }
1171  for (int col = 0; col < pixel_count; col++) {
1172    uint8_t gray =
1173        (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8)))
1174            ? set_gray
1175            : reset_gray;
1176    if (!clip_scan || clip_scan[col] == 255) {
1177      *dest_scan++ = gray;
1178      *dest_alpha_scan++ = 255;
1179      continue;
1180    }
1181    int src_alpha = clip_scan[col];
1182    if (src_alpha == 0) {
1183      dest_scan++;
1184      dest_alpha_scan++;
1185      continue;
1186    }
1187    int back_alpha = *dest_alpha_scan;
1188    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1189    *dest_alpha_scan++ = dest_alpha;
1190    int alpha_ratio = src_alpha * 255 / dest_alpha;
1191    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, alpha_ratio);
1192    dest_scan++;
1193  }
1194}
1195
1196void CompositeRow_8bppRgb2Rgb_NoBlend(uint8_t* dest_scan,
1197                                      const uint8_t* src_scan,
1198                                      uint32_t* pPalette,
1199                                      int pixel_count,
1200                                      int DestBpp,
1201                                      const uint8_t* clip_scan,
1202                                      const uint8_t* src_alpha_scan) {
1203  if (src_alpha_scan) {
1204    int dest_gap = DestBpp - 3;
1205    FX_ARGB argb = 0;
1206    for (int col = 0; col < pixel_count; col++) {
1207      argb = pPalette[*src_scan];
1208      int src_r = FXARGB_R(argb);
1209      int src_g = FXARGB_G(argb);
1210      int src_b = FXARGB_B(argb);
1211      src_scan++;
1212      uint8_t src_alpha = 0;
1213      if (clip_scan) {
1214        src_alpha = (*src_alpha_scan++) * (*clip_scan++) / 255;
1215      } else {
1216        src_alpha = *src_alpha_scan++;
1217      }
1218      if (src_alpha == 255) {
1219        *dest_scan++ = src_b;
1220        *dest_scan++ = src_g;
1221        *dest_scan++ = src_r;
1222        dest_scan += dest_gap;
1223        continue;
1224      }
1225      if (src_alpha == 0) {
1226        dest_scan += DestBpp;
1227        continue;
1228      }
1229      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha);
1230      dest_scan++;
1231      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha);
1232      dest_scan++;
1233      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha);
1234      dest_scan++;
1235      dest_scan += dest_gap;
1236    }
1237  } else {
1238    FX_ARGB argb = 0;
1239    for (int col = 0; col < pixel_count; col++) {
1240      argb = pPalette[*src_scan];
1241      int src_r = FXARGB_R(argb);
1242      int src_g = FXARGB_G(argb);
1243      int src_b = FXARGB_B(argb);
1244      if (clip_scan && clip_scan[col] < 255) {
1245        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, clip_scan[col]);
1246        dest_scan++;
1247        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, clip_scan[col]);
1248        dest_scan++;
1249        *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, clip_scan[col]);
1250        dest_scan++;
1251      } else {
1252        *dest_scan++ = src_b;
1253        *dest_scan++ = src_g;
1254        *dest_scan++ = src_r;
1255      }
1256      if (DestBpp == 4) {
1257        dest_scan++;
1258      }
1259      src_scan++;
1260    }
1261  }
1262}
1263
1264void CompositeRow_1bppRgb2Rgb_NoBlend(uint8_t* dest_scan,
1265                                      const uint8_t* src_scan,
1266                                      int src_left,
1267                                      uint32_t* pPalette,
1268                                      int pixel_count,
1269                                      int DestBpp,
1270                                      const uint8_t* clip_scan) {
1271  int reset_r, reset_g, reset_b;
1272  int set_r, set_g, set_b;
1273  reset_r = FXARGB_R(pPalette[0]);
1274  reset_g = FXARGB_G(pPalette[0]);
1275  reset_b = FXARGB_B(pPalette[0]);
1276  set_r = FXARGB_R(pPalette[1]);
1277  set_g = FXARGB_G(pPalette[1]);
1278  set_b = FXARGB_B(pPalette[1]);
1279  for (int col = 0; col < pixel_count; col++) {
1280    int src_r, src_g, src_b;
1281    if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
1282      src_r = set_r;
1283      src_g = set_g;
1284      src_b = set_b;
1285    } else {
1286      src_r = reset_r;
1287      src_g = reset_g;
1288      src_b = reset_b;
1289    }
1290    if (clip_scan && clip_scan[col] < 255) {
1291      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, clip_scan[col]);
1292      dest_scan++;
1293      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, clip_scan[col]);
1294      dest_scan++;
1295      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, clip_scan[col]);
1296      dest_scan++;
1297    } else {
1298      *dest_scan++ = src_b;
1299      *dest_scan++ = src_g;
1300      *dest_scan++ = src_r;
1301    }
1302    if (DestBpp == 4) {
1303      dest_scan++;
1304    }
1305  }
1306}
1307
1308void CompositeRow_8bppRgb2Argb_NoBlend(uint8_t* dest_scan,
1309                                       const uint8_t* src_scan,
1310                                       int width,
1311                                       uint32_t* pPalette,
1312                                       const uint8_t* clip_scan,
1313                                       const uint8_t* src_alpha_scan) {
1314  if (src_alpha_scan) {
1315    for (int col = 0; col < width; col++) {
1316      FX_ARGB argb = pPalette[*src_scan];
1317      src_scan++;
1318      int src_r = FXARGB_R(argb);
1319      int src_g = FXARGB_G(argb);
1320      int src_b = FXARGB_B(argb);
1321      uint8_t back_alpha = dest_scan[3];
1322      if (back_alpha == 0) {
1323        if (clip_scan) {
1324          int src_alpha = clip_scan[col] * (*src_alpha_scan) / 255;
1325          FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
1326        } else {
1327          FXARGB_SETDIB(dest_scan,
1328                        FXARGB_MAKE(*src_alpha_scan, src_r, src_g, src_b));
1329        }
1330        dest_scan += 4;
1331        src_alpha_scan++;
1332        continue;
1333      }
1334      uint8_t src_alpha;
1335      if (clip_scan) {
1336        src_alpha = clip_scan[col] * (*src_alpha_scan++) / 255;
1337      } else {
1338        src_alpha = *src_alpha_scan++;
1339      }
1340      if (src_alpha == 0) {
1341        dest_scan += 4;
1342        continue;
1343      }
1344      uint8_t dest_alpha =
1345          back_alpha + src_alpha - back_alpha * src_alpha / 255;
1346      dest_scan[3] = dest_alpha;
1347      int alpha_ratio = src_alpha * 255 / dest_alpha;
1348      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
1349      dest_scan++;
1350      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
1351      dest_scan++;
1352      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
1353      dest_scan++;
1354      dest_scan++;
1355    }
1356  } else {
1357    for (int col = 0; col < width; col++) {
1358      FX_ARGB argb = pPalette[*src_scan];
1359      int src_r = FXARGB_R(argb);
1360      int src_g = FXARGB_G(argb);
1361      int src_b = FXARGB_B(argb);
1362      if (!clip_scan || clip_scan[col] == 255) {
1363        *dest_scan++ = src_b;
1364        *dest_scan++ = src_g;
1365        *dest_scan++ = src_r;
1366        *dest_scan++ = 255;
1367        src_scan++;
1368        continue;
1369      }
1370      int src_alpha = clip_scan[col];
1371      if (src_alpha == 0) {
1372        dest_scan += 4;
1373        src_scan++;
1374        continue;
1375      }
1376      int back_alpha = dest_scan[3];
1377      uint8_t dest_alpha =
1378          back_alpha + src_alpha - back_alpha * src_alpha / 255;
1379      dest_scan[3] = dest_alpha;
1380      int alpha_ratio = src_alpha * 255 / dest_alpha;
1381      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
1382      dest_scan++;
1383      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
1384      dest_scan++;
1385      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
1386      dest_scan++;
1387      dest_scan++;
1388      src_scan++;
1389    }
1390  }
1391}
1392
1393void CompositeRow_1bppRgb2Argb_NoBlend(uint8_t* dest_scan,
1394                                       const uint8_t* src_scan,
1395                                       int src_left,
1396                                       int width,
1397                                       uint32_t* pPalette,
1398                                       const uint8_t* clip_scan) {
1399  int reset_r, reset_g, reset_b;
1400  int set_r, set_g, set_b;
1401  reset_r = FXARGB_R(pPalette[0]);
1402  reset_g = FXARGB_G(pPalette[0]);
1403  reset_b = FXARGB_B(pPalette[0]);
1404  set_r = FXARGB_R(pPalette[1]);
1405  set_g = FXARGB_G(pPalette[1]);
1406  set_b = FXARGB_B(pPalette[1]);
1407  for (int col = 0; col < width; col++) {
1408    int src_r, src_g, src_b;
1409    if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
1410      src_r = set_r;
1411      src_g = set_g;
1412      src_b = set_b;
1413    } else {
1414      src_r = reset_r;
1415      src_g = reset_g;
1416      src_b = reset_b;
1417    }
1418    if (!clip_scan || clip_scan[col] == 255) {
1419      *dest_scan++ = src_b;
1420      *dest_scan++ = src_g;
1421      *dest_scan++ = src_r;
1422      *dest_scan++ = 255;
1423      continue;
1424    }
1425    int src_alpha = clip_scan[col];
1426    if (src_alpha == 0) {
1427      dest_scan += 4;
1428      continue;
1429    }
1430    int back_alpha = dest_scan[3];
1431    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1432    dest_scan[3] = dest_alpha;
1433    int alpha_ratio = src_alpha * 255 / dest_alpha;
1434    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
1435    dest_scan++;
1436    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
1437    dest_scan++;
1438    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
1439    dest_scan++;
1440    dest_scan++;
1441  }
1442}
1443
1444void CompositeRow_1bppRgb2Rgba_NoBlend(uint8_t* dest_scan,
1445                                       const uint8_t* src_scan,
1446                                       int src_left,
1447                                       int width,
1448                                       uint32_t* pPalette,
1449                                       const uint8_t* clip_scan,
1450                                       uint8_t* dest_alpha_scan) {
1451  int reset_r, reset_g, reset_b;
1452  int set_r, set_g, set_b;
1453  reset_r = FXARGB_R(pPalette[0]);
1454  reset_g = FXARGB_G(pPalette[0]);
1455  reset_b = FXARGB_B(pPalette[0]);
1456  set_r = FXARGB_R(pPalette[1]);
1457  set_g = FXARGB_G(pPalette[1]);
1458  set_b = FXARGB_B(pPalette[1]);
1459  for (int col = 0; col < width; col++) {
1460    int src_r, src_g, src_b;
1461    if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
1462      src_r = set_r;
1463      src_g = set_g;
1464      src_b = set_b;
1465    } else {
1466      src_r = reset_r;
1467      src_g = reset_g;
1468      src_b = reset_b;
1469    }
1470    if (!clip_scan || clip_scan[col] == 255) {
1471      *dest_scan++ = src_b;
1472      *dest_scan++ = src_g;
1473      *dest_scan++ = src_r;
1474      *dest_alpha_scan++ = 255;
1475      continue;
1476    }
1477    int src_alpha = clip_scan[col];
1478    if (src_alpha == 0) {
1479      dest_scan += 3;
1480      dest_alpha_scan++;
1481      continue;
1482    }
1483    int back_alpha = *dest_alpha_scan;
1484    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1485    *dest_alpha_scan++ = dest_alpha;
1486    int alpha_ratio = src_alpha * 255 / dest_alpha;
1487    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
1488    dest_scan++;
1489    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
1490    dest_scan++;
1491    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
1492    dest_scan++;
1493  }
1494}
1495
1496void CompositeRow_ByteMask2Argb(uint8_t* dest_scan,
1497                                const uint8_t* src_scan,
1498                                int mask_alpha,
1499                                int src_r,
1500                                int src_g,
1501                                int src_b,
1502                                int pixel_count,
1503                                int blend_type,
1504                                const uint8_t* clip_scan) {
1505  for (int col = 0; col < pixel_count; col++) {
1506    int src_alpha;
1507    if (clip_scan) {
1508      src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
1509    } else {
1510      src_alpha = mask_alpha * src_scan[col] / 255;
1511    }
1512    uint8_t back_alpha = dest_scan[3];
1513    if (back_alpha == 0) {
1514      FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
1515      dest_scan += 4;
1516      continue;
1517    }
1518    if (src_alpha == 0) {
1519      dest_scan += 4;
1520      continue;
1521    }
1522    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1523    dest_scan[3] = dest_alpha;
1524    int alpha_ratio = src_alpha * 255 / dest_alpha;
1525    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
1526      int blended_colors[3];
1527      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
1528                         static_cast<uint8_t>(src_g),
1529                         static_cast<uint8_t>(src_r)};
1530      RGB_Blend(blend_type, scan, dest_scan, blended_colors);
1531      *dest_scan =
1532          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio);
1533      dest_scan++;
1534      *dest_scan =
1535          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio);
1536      dest_scan++;
1537      *dest_scan =
1538          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio);
1539    } else if (blend_type) {
1540      int blended = Blend(blend_type, *dest_scan, src_b);
1541      blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
1542      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1543      dest_scan++;
1544      blended = Blend(blend_type, *dest_scan, src_g);
1545      blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
1546      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1547      dest_scan++;
1548      blended = Blend(blend_type, *dest_scan, src_r);
1549      blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
1550      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1551    } else {
1552      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
1553      dest_scan++;
1554      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
1555      dest_scan++;
1556      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
1557    }
1558    dest_scan += 2;
1559  }
1560}
1561
1562void CompositeRow_ByteMask2Rgba(uint8_t* dest_scan,
1563                                const uint8_t* src_scan,
1564                                int mask_alpha,
1565                                int src_r,
1566                                int src_g,
1567                                int src_b,
1568                                int pixel_count,
1569                                int blend_type,
1570                                const uint8_t* clip_scan,
1571                                uint8_t* dest_alpha_scan) {
1572  for (int col = 0; col < pixel_count; col++) {
1573    int src_alpha;
1574    if (clip_scan) {
1575      src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
1576    } else {
1577      src_alpha = mask_alpha * src_scan[col] / 255;
1578    }
1579    uint8_t back_alpha = *dest_alpha_scan;
1580    if (back_alpha == 0) {
1581      *dest_scan++ = src_b;
1582      *dest_scan++ = src_g;
1583      *dest_scan++ = src_r;
1584      *dest_alpha_scan++ = src_alpha;
1585      continue;
1586    }
1587    if (src_alpha == 0) {
1588      dest_scan += 3;
1589      dest_alpha_scan++;
1590      continue;
1591    }
1592    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1593    *dest_alpha_scan++ = dest_alpha;
1594    int alpha_ratio = src_alpha * 255 / dest_alpha;
1595    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
1596      int blended_colors[3];
1597      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
1598                         static_cast<uint8_t>(src_g),
1599                         static_cast<uint8_t>(src_r)};
1600      RGB_Blend(blend_type, scan, dest_scan, blended_colors);
1601      *dest_scan =
1602          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio);
1603      dest_scan++;
1604      *dest_scan =
1605          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio);
1606      dest_scan++;
1607      *dest_scan =
1608          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio);
1609      dest_scan++;
1610    } else if (blend_type) {
1611      int blended = Blend(blend_type, *dest_scan, src_b);
1612      blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
1613      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1614      dest_scan++;
1615      blended = Blend(blend_type, *dest_scan, src_g);
1616      blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
1617      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1618      dest_scan++;
1619      blended = Blend(blend_type, *dest_scan, src_r);
1620      blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
1621      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1622      dest_scan++;
1623    } else {
1624      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
1625      dest_scan++;
1626      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
1627      dest_scan++;
1628      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
1629      dest_scan++;
1630    }
1631  }
1632}
1633
1634void CompositeRow_ByteMask2Rgb(uint8_t* dest_scan,
1635                               const uint8_t* src_scan,
1636                               int mask_alpha,
1637                               int src_r,
1638                               int src_g,
1639                               int src_b,
1640                               int pixel_count,
1641                               int blend_type,
1642                               int Bpp,
1643                               const uint8_t* clip_scan) {
1644  for (int col = 0; col < pixel_count; col++) {
1645    int src_alpha;
1646    if (clip_scan) {
1647      src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
1648    } else {
1649      src_alpha = mask_alpha * src_scan[col] / 255;
1650    }
1651    if (src_alpha == 0) {
1652      dest_scan += Bpp;
1653      continue;
1654    }
1655    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
1656      int blended_colors[3];
1657      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
1658                         static_cast<uint8_t>(src_g),
1659                         static_cast<uint8_t>(src_r)};
1660      RGB_Blend(blend_type, scan, dest_scan, blended_colors);
1661      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], src_alpha);
1662      dest_scan++;
1663      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], src_alpha);
1664      dest_scan++;
1665      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], src_alpha);
1666    } else if (blend_type) {
1667      int blended = Blend(blend_type, *dest_scan, src_b);
1668      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
1669      dest_scan++;
1670      blended = Blend(blend_type, *dest_scan, src_g);
1671      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
1672      dest_scan++;
1673      blended = Blend(blend_type, *dest_scan, src_r);
1674      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
1675    } else {
1676      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha);
1677      dest_scan++;
1678      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha);
1679      dest_scan++;
1680      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha);
1681    }
1682    dest_scan += Bpp - 2;
1683  }
1684}
1685
1686void CompositeRow_ByteMask2Mask(uint8_t* dest_scan,
1687                                const uint8_t* src_scan,
1688                                int mask_alpha,
1689                                int pixel_count,
1690                                const uint8_t* clip_scan) {
1691  for (int col = 0; col < pixel_count; col++) {
1692    int src_alpha;
1693    if (clip_scan) {
1694      src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
1695    } else {
1696      src_alpha = mask_alpha * src_scan[col] / 255;
1697    }
1698    uint8_t back_alpha = *dest_scan;
1699    if (!back_alpha) {
1700      *dest_scan = src_alpha;
1701    } else if (src_alpha) {
1702      *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1703    }
1704    dest_scan++;
1705  }
1706}
1707
1708void CompositeRow_ByteMask2Gray(uint8_t* dest_scan,
1709                                const uint8_t* src_scan,
1710                                int mask_alpha,
1711                                int src_gray,
1712                                int pixel_count,
1713                                const uint8_t* clip_scan) {
1714  for (int col = 0; col < pixel_count; col++) {
1715    int src_alpha;
1716    if (clip_scan) {
1717      src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
1718    } else {
1719      src_alpha = mask_alpha * src_scan[col] / 255;
1720    }
1721    if (src_alpha) {
1722      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, src_alpha);
1723    }
1724    dest_scan++;
1725  }
1726}
1727
1728void CompositeRow_ByteMask2Graya(uint8_t* dest_scan,
1729                                 const uint8_t* src_scan,
1730                                 int mask_alpha,
1731                                 int src_gray,
1732                                 int pixel_count,
1733                                 const uint8_t* clip_scan,
1734                                 uint8_t* dest_alpha_scan) {
1735  for (int col = 0; col < pixel_count; col++) {
1736    int src_alpha;
1737    if (clip_scan) {
1738      src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
1739    } else {
1740      src_alpha = mask_alpha * src_scan[col] / 255;
1741    }
1742    uint8_t back_alpha = *dest_alpha_scan;
1743    if (back_alpha == 0) {
1744      *dest_scan++ = src_gray;
1745      *dest_alpha_scan++ = src_alpha;
1746      continue;
1747    }
1748    if (src_alpha == 0) {
1749      dest_scan++;
1750      dest_alpha_scan++;
1751      continue;
1752    }
1753    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1754    *dest_alpha_scan++ = dest_alpha;
1755    int alpha_ratio = src_alpha * 255 / dest_alpha;
1756    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, alpha_ratio);
1757    dest_scan++;
1758  }
1759}
1760
1761void CompositeRow_BitMask2Argb(uint8_t* dest_scan,
1762                               const uint8_t* src_scan,
1763                               int mask_alpha,
1764                               int src_r,
1765                               int src_g,
1766                               int src_b,
1767                               int src_left,
1768                               int pixel_count,
1769                               int blend_type,
1770                               const uint8_t* clip_scan) {
1771  if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) {
1772    FX_ARGB argb = FXARGB_MAKE(0xff, src_r, src_g, src_b);
1773    for (int col = 0; col < pixel_count; col++) {
1774      if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
1775        FXARGB_SETDIB(dest_scan, argb);
1776      }
1777      dest_scan += 4;
1778    }
1779    return;
1780  }
1781  for (int col = 0; col < pixel_count; col++) {
1782    if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
1783      dest_scan += 4;
1784      continue;
1785    }
1786    int src_alpha;
1787    if (clip_scan) {
1788      src_alpha = mask_alpha * clip_scan[col] / 255;
1789    } else {
1790      src_alpha = mask_alpha;
1791    }
1792    uint8_t back_alpha = dest_scan[3];
1793    if (back_alpha == 0) {
1794      FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
1795      dest_scan += 4;
1796      continue;
1797    }
1798    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1799    dest_scan[3] = dest_alpha;
1800    int alpha_ratio = src_alpha * 255 / dest_alpha;
1801    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
1802      int blended_colors[3];
1803      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
1804                         static_cast<uint8_t>(src_g),
1805                         static_cast<uint8_t>(src_r)};
1806      RGB_Blend(blend_type, scan, dest_scan, blended_colors);
1807      *dest_scan =
1808          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], alpha_ratio);
1809      dest_scan++;
1810      *dest_scan =
1811          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], alpha_ratio);
1812      dest_scan++;
1813      *dest_scan =
1814          FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], alpha_ratio);
1815    } else if (blend_type) {
1816      int blended = Blend(blend_type, *dest_scan, src_b);
1817      blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
1818      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1819      dest_scan++;
1820      blended = Blend(blend_type, *dest_scan, src_g);
1821      blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
1822      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1823      dest_scan++;
1824      blended = Blend(blend_type, *dest_scan, src_r);
1825      blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
1826      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, alpha_ratio);
1827    } else {
1828      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, alpha_ratio);
1829      dest_scan++;
1830      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, alpha_ratio);
1831      dest_scan++;
1832      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, alpha_ratio);
1833    }
1834    dest_scan += 2;
1835  }
1836}
1837
1838void CompositeRow_BitMask2Rgb(uint8_t* dest_scan,
1839                              const uint8_t* src_scan,
1840                              int mask_alpha,
1841                              int src_r,
1842                              int src_g,
1843                              int src_b,
1844                              int src_left,
1845                              int pixel_count,
1846                              int blend_type,
1847                              int Bpp,
1848                              const uint8_t* clip_scan) {
1849  if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) {
1850    for (int col = 0; col < pixel_count; col++) {
1851      if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
1852        dest_scan[2] = src_r;
1853        dest_scan[1] = src_g;
1854        dest_scan[0] = src_b;
1855      }
1856      dest_scan += Bpp;
1857    }
1858    return;
1859  }
1860  for (int col = 0; col < pixel_count; col++) {
1861    if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
1862      dest_scan += Bpp;
1863      continue;
1864    }
1865    int src_alpha;
1866    if (clip_scan) {
1867      src_alpha = mask_alpha * clip_scan[col] / 255;
1868    } else {
1869      src_alpha = mask_alpha;
1870    }
1871    if (src_alpha == 0) {
1872      dest_scan += Bpp;
1873      continue;
1874    }
1875    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
1876      int blended_colors[3];
1877      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
1878                         static_cast<uint8_t>(src_g),
1879                         static_cast<uint8_t>(src_r)};
1880      RGB_Blend(blend_type, scan, dest_scan, blended_colors);
1881      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[0], src_alpha);
1882      dest_scan++;
1883      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[1], src_alpha);
1884      dest_scan++;
1885      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended_colors[2], src_alpha);
1886    } else if (blend_type) {
1887      int blended = Blend(blend_type, *dest_scan, src_b);
1888      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
1889      dest_scan++;
1890      blended = Blend(blend_type, *dest_scan, src_g);
1891      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
1892      dest_scan++;
1893      blended = Blend(blend_type, *dest_scan, src_r);
1894      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, blended, src_alpha);
1895    } else {
1896      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_b, src_alpha);
1897      dest_scan++;
1898      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_g, src_alpha);
1899      dest_scan++;
1900      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_r, src_alpha);
1901    }
1902    dest_scan += Bpp - 2;
1903  }
1904}
1905
1906void CompositeRow_BitMask2Mask(uint8_t* dest_scan,
1907                               const uint8_t* src_scan,
1908                               int mask_alpha,
1909                               int src_left,
1910                               int pixel_count,
1911                               const uint8_t* clip_scan) {
1912  for (int col = 0; col < pixel_count; col++) {
1913    if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
1914      dest_scan++;
1915      continue;
1916    }
1917    int src_alpha;
1918    if (clip_scan) {
1919      src_alpha = mask_alpha * clip_scan[col] / 255;
1920    } else {
1921      src_alpha = mask_alpha;
1922    }
1923    uint8_t back_alpha = *dest_scan;
1924    if (!back_alpha) {
1925      *dest_scan = src_alpha;
1926    } else if (src_alpha) {
1927      *dest_scan = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1928    }
1929    dest_scan++;
1930  }
1931}
1932
1933void CompositeRow_BitMask2Gray(uint8_t* dest_scan,
1934                               const uint8_t* src_scan,
1935                               int mask_alpha,
1936                               int src_gray,
1937                               int src_left,
1938                               int pixel_count,
1939                               const uint8_t* clip_scan) {
1940  for (int col = 0; col < pixel_count; col++) {
1941    if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
1942      dest_scan++;
1943      continue;
1944    }
1945    int src_alpha;
1946    if (clip_scan) {
1947      src_alpha = mask_alpha * clip_scan[col] / 255;
1948    } else {
1949      src_alpha = mask_alpha;
1950    }
1951    if (src_alpha) {
1952      *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, src_alpha);
1953    }
1954    dest_scan++;
1955  }
1956}
1957
1958void CompositeRow_BitMask2Graya(uint8_t* dest_scan,
1959                                const uint8_t* src_scan,
1960                                int mask_alpha,
1961                                int src_gray,
1962                                int src_left,
1963                                int pixel_count,
1964                                const uint8_t* clip_scan,
1965                                uint8_t* dest_alpha_scan) {
1966  for (int col = 0; col < pixel_count; col++) {
1967    if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
1968      dest_scan++;
1969      dest_alpha_scan++;
1970      continue;
1971    }
1972    int src_alpha;
1973    if (clip_scan) {
1974      src_alpha = mask_alpha * clip_scan[col] / 255;
1975    } else {
1976      src_alpha = mask_alpha;
1977    }
1978    uint8_t back_alpha = *dest_alpha_scan;
1979    if (back_alpha == 0) {
1980      *dest_scan++ = src_gray;
1981      *dest_alpha_scan++ = src_alpha;
1982      continue;
1983    }
1984    if (src_alpha == 0) {
1985      dest_scan++;
1986      dest_alpha_scan++;
1987      continue;
1988    }
1989    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
1990    *dest_alpha_scan++ = dest_alpha;
1991    int alpha_ratio = src_alpha * 255 / dest_alpha;
1992    *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, src_gray, alpha_ratio);
1993    dest_scan++;
1994  }
1995}
1996
1997void CompositeRow_Argb2Argb_RgbByteOrder(uint8_t* dest_scan,
1998                                         const uint8_t* src_scan,
1999                                         int pixel_count,
2000                                         int blend_type,
2001                                         const uint8_t* clip_scan) {
2002  int blended_colors[3];
2003  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2004  for (int col = 0; col < pixel_count; col++) {
2005    uint8_t back_alpha = dest_scan[3];
2006    if (back_alpha == 0) {
2007      if (clip_scan) {
2008        int src_alpha = clip_scan[col] * src_scan[3] / 255;
2009        dest_scan[3] = src_alpha;
2010        dest_scan[0] = src_scan[2];
2011        dest_scan[1] = src_scan[1];
2012        dest_scan[2] = src_scan[0];
2013      } else {
2014        FXARGB_RGBORDERCOPY(dest_scan, src_scan);
2015      }
2016      dest_scan += 4;
2017      src_scan += 4;
2018      continue;
2019    }
2020    uint8_t src_alpha;
2021    if (clip_scan) {
2022      src_alpha = clip_scan[col] * src_scan[3] / 255;
2023    } else {
2024      src_alpha = src_scan[3];
2025    }
2026    if (src_alpha == 0) {
2027      dest_scan += 4;
2028      src_scan += 4;
2029      continue;
2030    }
2031    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2032    dest_scan[3] = dest_alpha;
2033    int alpha_ratio = src_alpha * 255 / dest_alpha;
2034    if (bNonseparableBlend) {
2035      uint8_t dest_scan_o[3];
2036      dest_scan_o[0] = dest_scan[2];
2037      dest_scan_o[1] = dest_scan[1];
2038      dest_scan_o[2] = dest_scan[0];
2039      RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2040    }
2041    for (int color = 0; color < 3; color++) {
2042      int index = 2 - color;
2043      if (blend_type) {
2044        int blended = bNonseparableBlend
2045                          ? blended_colors[color]
2046                          : Blend(blend_type, dest_scan[index], *src_scan);
2047        blended = FXDIB_ALPHA_MERGE(*src_scan, blended, back_alpha);
2048        dest_scan[index] =
2049            FXDIB_ALPHA_MERGE(dest_scan[index], blended, alpha_ratio);
2050      } else {
2051        dest_scan[index] =
2052            FXDIB_ALPHA_MERGE(dest_scan[index], *src_scan, alpha_ratio);
2053      }
2054      src_scan++;
2055    }
2056    dest_scan += 4;
2057    src_scan++;
2058  }
2059}
2060
2061void CompositeRow_Rgb2Argb_Blend_NoClip_RgbByteOrder(uint8_t* dest_scan,
2062                                                     const uint8_t* src_scan,
2063                                                     int width,
2064                                                     int blend_type,
2065                                                     int src_Bpp) {
2066  int blended_colors[3];
2067  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2068  int src_gap = src_Bpp - 3;
2069  for (int col = 0; col < width; col++) {
2070    uint8_t back_alpha = dest_scan[3];
2071    if (back_alpha == 0) {
2072      if (src_Bpp == 4) {
2073        FXARGB_SETRGBORDERDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan));
2074      } else {
2075        FXARGB_SETRGBORDERDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[2],
2076                                                     src_scan[1], src_scan[0]));
2077      }
2078      dest_scan += 4;
2079      src_scan += src_Bpp;
2080      continue;
2081    }
2082    dest_scan[3] = 0xff;
2083    if (bNonseparableBlend) {
2084      uint8_t dest_scan_o[3];
2085      dest_scan_o[0] = dest_scan[2];
2086      dest_scan_o[1] = dest_scan[1];
2087      dest_scan_o[2] = dest_scan[0];
2088      RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2089    }
2090    for (int color = 0; color < 3; color++) {
2091      int index = 2 - color;
2092      int src_color = *src_scan;
2093      int blended = bNonseparableBlend
2094                        ? blended_colors[color]
2095                        : Blend(blend_type, dest_scan[index], src_color);
2096      dest_scan[index] = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
2097      src_scan++;
2098    }
2099    dest_scan += 4;
2100    src_scan += src_gap;
2101  }
2102}
2103
2104void CompositeRow_Argb2Rgb_Blend_RgbByteOrder(uint8_t* dest_scan,
2105                                              const uint8_t* src_scan,
2106                                              int width,
2107                                              int blend_type,
2108                                              int dest_Bpp,
2109                                              const uint8_t* clip_scan) {
2110  int blended_colors[3];
2111  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2112  for (int col = 0; col < width; col++) {
2113    uint8_t src_alpha;
2114    if (clip_scan) {
2115      src_alpha = src_scan[3] * (*clip_scan++) / 255;
2116    } else {
2117      src_alpha = src_scan[3];
2118    }
2119    if (src_alpha == 0) {
2120      dest_scan += dest_Bpp;
2121      src_scan += 4;
2122      continue;
2123    }
2124    if (bNonseparableBlend) {
2125      uint8_t dest_scan_o[3];
2126      dest_scan_o[0] = dest_scan[2];
2127      dest_scan_o[1] = dest_scan[1];
2128      dest_scan_o[2] = dest_scan[0];
2129      RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2130    }
2131    for (int color = 0; color < 3; color++) {
2132      int index = 2 - color;
2133      int back_color = dest_scan[index];
2134      int blended = bNonseparableBlend
2135                        ? blended_colors[color]
2136                        : Blend(blend_type, back_color, *src_scan);
2137      dest_scan[index] = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
2138      src_scan++;
2139    }
2140    dest_scan += dest_Bpp;
2141    src_scan++;
2142  }
2143}
2144
2145void CompositeRow_Rgb2Argb_NoBlend_NoClip_RgbByteOrder(uint8_t* dest_scan,
2146                                                       const uint8_t* src_scan,
2147                                                       int width,
2148                                                       int src_Bpp) {
2149  for (int col = 0; col < width; col++) {
2150    if (src_Bpp == 4) {
2151      FXARGB_SETRGBORDERDIB(dest_scan, 0xff000000 | FXARGB_GETDIB(src_scan));
2152    } else {
2153      FXARGB_SETRGBORDERDIB(
2154          dest_scan, FXARGB_MAKE(0xff, src_scan[2], src_scan[1], src_scan[0]));
2155    }
2156    dest_scan += 4;
2157    src_scan += src_Bpp;
2158  }
2159}
2160
2161void CompositeRow_Rgb2Rgb_Blend_NoClip_RgbByteOrder(uint8_t* dest_scan,
2162                                                    const uint8_t* src_scan,
2163                                                    int width,
2164                                                    int blend_type,
2165                                                    int dest_Bpp,
2166                                                    int src_Bpp) {
2167  int blended_colors[3];
2168  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2169  int src_gap = src_Bpp - 3;
2170  for (int col = 0; col < width; col++) {
2171    if (bNonseparableBlend) {
2172      uint8_t dest_scan_o[3];
2173      dest_scan_o[0] = dest_scan[2];
2174      dest_scan_o[1] = dest_scan[1];
2175      dest_scan_o[2] = dest_scan[0];
2176      RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2177    }
2178    for (int color = 0; color < 3; color++) {
2179      int index = 2 - color;
2180      int back_color = dest_scan[index];
2181      int src_color = *src_scan;
2182      int blended = bNonseparableBlend
2183                        ? blended_colors[color]
2184                        : Blend(blend_type, back_color, src_color);
2185      dest_scan[index] = blended;
2186      src_scan++;
2187    }
2188    dest_scan += dest_Bpp;
2189    src_scan += src_gap;
2190  }
2191}
2192
2193void CompositeRow_Argb2Rgb_NoBlend_RgbByteOrder(uint8_t* dest_scan,
2194                                                const uint8_t* src_scan,
2195                                                int width,
2196                                                int dest_Bpp,
2197                                                const uint8_t* clip_scan) {
2198  for (int col = 0; col < width; col++) {
2199    uint8_t src_alpha;
2200    if (clip_scan) {
2201      src_alpha = src_scan[3] * (*clip_scan++) / 255;
2202    } else {
2203      src_alpha = src_scan[3];
2204    }
2205    if (src_alpha == 255) {
2206      dest_scan[2] = *src_scan++;
2207      dest_scan[1] = *src_scan++;
2208      dest_scan[0] = *src_scan++;
2209      dest_scan += dest_Bpp;
2210      src_scan++;
2211      continue;
2212    }
2213    if (src_alpha == 0) {
2214      dest_scan += dest_Bpp;
2215      src_scan += 4;
2216      continue;
2217    }
2218    for (int color = 0; color < 3; color++) {
2219      int index = 2 - color;
2220      dest_scan[index] =
2221          FXDIB_ALPHA_MERGE(dest_scan[index], *src_scan, src_alpha);
2222      src_scan++;
2223    }
2224    dest_scan += dest_Bpp;
2225    src_scan++;
2226  }
2227}
2228
2229void CompositeRow_Rgb2Rgb_NoBlend_NoClip_RgbByteOrder(uint8_t* dest_scan,
2230                                                      const uint8_t* src_scan,
2231                                                      int width,
2232                                                      int dest_Bpp,
2233                                                      int src_Bpp) {
2234  for (int col = 0; col < width; col++) {
2235    dest_scan[2] = src_scan[0];
2236    dest_scan[1] = src_scan[1];
2237    dest_scan[0] = src_scan[2];
2238    dest_scan += dest_Bpp;
2239    src_scan += src_Bpp;
2240  }
2241}
2242
2243void CompositeRow_Rgb2Argb_Blend_Clip_RgbByteOrder(uint8_t* dest_scan,
2244                                                   const uint8_t* src_scan,
2245                                                   int width,
2246                                                   int blend_type,
2247                                                   int src_Bpp,
2248                                                   const uint8_t* clip_scan) {
2249  int blended_colors[3];
2250  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2251  int src_gap = src_Bpp - 3;
2252  for (int col = 0; col < width; col++) {
2253    int src_alpha = *clip_scan++;
2254    uint8_t back_alpha = dest_scan[3];
2255    if (back_alpha == 0) {
2256      dest_scan[2] = *src_scan++;
2257      dest_scan[1] = *src_scan++;
2258      dest_scan[0] = *src_scan++;
2259      src_scan += src_gap;
2260      dest_scan += 4;
2261      continue;
2262    }
2263    if (src_alpha == 0) {
2264      dest_scan += 4;
2265      src_scan += src_Bpp;
2266      continue;
2267    }
2268    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2269    dest_scan[3] = dest_alpha;
2270    int alpha_ratio = src_alpha * 255 / dest_alpha;
2271    if (bNonseparableBlend) {
2272      uint8_t dest_scan_o[3];
2273      dest_scan_o[0] = dest_scan[2];
2274      dest_scan_o[1] = dest_scan[1];
2275      dest_scan_o[2] = dest_scan[0];
2276      RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2277    }
2278    for (int color = 0; color < 3; color++) {
2279      int index = 2 - color;
2280      int src_color = *src_scan;
2281      int blended = bNonseparableBlend
2282                        ? blended_colors[color]
2283                        : Blend(blend_type, dest_scan[index], src_color);
2284      blended = FXDIB_ALPHA_MERGE(src_color, blended, back_alpha);
2285      dest_scan[index] =
2286          FXDIB_ALPHA_MERGE(dest_scan[index], blended, alpha_ratio);
2287      src_scan++;
2288    }
2289    dest_scan += 4;
2290    src_scan += src_gap;
2291  }
2292}
2293
2294void CompositeRow_Rgb2Rgb_Blend_Clip_RgbByteOrder(uint8_t* dest_scan,
2295                                                  const uint8_t* src_scan,
2296                                                  int width,
2297                                                  int blend_type,
2298                                                  int dest_Bpp,
2299                                                  int src_Bpp,
2300                                                  const uint8_t* clip_scan) {
2301  int blended_colors[3];
2302  bool bNonseparableBlend = blend_type >= FXDIB_BLEND_NONSEPARABLE;
2303  int src_gap = src_Bpp - 3;
2304  for (int col = 0; col < width; col++) {
2305    uint8_t src_alpha = *clip_scan++;
2306    if (src_alpha == 0) {
2307      dest_scan += dest_Bpp;
2308      src_scan += src_Bpp;
2309      continue;
2310    }
2311    if (bNonseparableBlend) {
2312      uint8_t dest_scan_o[3];
2313      dest_scan_o[0] = dest_scan[2];
2314      dest_scan_o[1] = dest_scan[1];
2315      dest_scan_o[2] = dest_scan[0];
2316      RGB_Blend(blend_type, src_scan, dest_scan_o, blended_colors);
2317    }
2318    for (int color = 0; color < 3; color++) {
2319      int index = 2 - color;
2320      int src_color = *src_scan;
2321      int back_color = dest_scan[index];
2322      int blended = bNonseparableBlend
2323                        ? blended_colors[color]
2324                        : Blend(blend_type, back_color, src_color);
2325      dest_scan[index] = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
2326      src_scan++;
2327    }
2328    dest_scan += dest_Bpp;
2329    src_scan += src_gap;
2330  }
2331}
2332
2333void CompositeRow_Rgb2Argb_NoBlend_Clip_RgbByteOrder(uint8_t* dest_scan,
2334                                                     const uint8_t* src_scan,
2335                                                     int width,
2336                                                     int src_Bpp,
2337                                                     const uint8_t* clip_scan) {
2338  int src_gap = src_Bpp - 3;
2339  for (int col = 0; col < width; col++) {
2340    int src_alpha = clip_scan[col];
2341    if (src_alpha == 255) {
2342      dest_scan[2] = *src_scan++;
2343      dest_scan[1] = *src_scan++;
2344      dest_scan[0] = *src_scan++;
2345      dest_scan[3] = 255;
2346      dest_scan += 4;
2347      src_scan += src_gap;
2348      continue;
2349    }
2350    if (src_alpha == 0) {
2351      dest_scan += 4;
2352      src_scan += src_Bpp;
2353      continue;
2354    }
2355    int back_alpha = dest_scan[3];
2356    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2357    dest_scan[3] = dest_alpha;
2358    int alpha_ratio = src_alpha * 255 / dest_alpha;
2359    for (int color = 0; color < 3; color++) {
2360      int index = 2 - color;
2361      dest_scan[index] =
2362          FXDIB_ALPHA_MERGE(dest_scan[index], *src_scan, alpha_ratio);
2363      src_scan++;
2364    }
2365    dest_scan += 4;
2366    src_scan += src_gap;
2367  }
2368}
2369
2370void CompositeRow_Rgb2Rgb_NoBlend_Clip_RgbByteOrder(uint8_t* dest_scan,
2371                                                    const uint8_t* src_scan,
2372                                                    int width,
2373                                                    int dest_Bpp,
2374                                                    int src_Bpp,
2375                                                    const uint8_t* clip_scan) {
2376  for (int col = 0; col < width; col++) {
2377    int src_alpha = clip_scan[col];
2378    if (src_alpha == 255) {
2379      dest_scan[2] = src_scan[0];
2380      dest_scan[1] = src_scan[1];
2381      dest_scan[0] = src_scan[2];
2382    } else if (src_alpha) {
2383      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], *src_scan, src_alpha);
2384      src_scan++;
2385      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], *src_scan, src_alpha);
2386      src_scan++;
2387      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], *src_scan, src_alpha);
2388      dest_scan += dest_Bpp;
2389      src_scan += src_Bpp - 2;
2390      continue;
2391    }
2392    dest_scan += dest_Bpp;
2393    src_scan += src_Bpp;
2394  }
2395}
2396
2397void CompositeRow_8bppRgb2Rgb_NoBlend_RgbByteOrder(uint8_t* dest_scan,
2398                                                   const uint8_t* src_scan,
2399                                                   FX_ARGB* pPalette,
2400                                                   int pixel_count,
2401                                                   int DestBpp,
2402                                                   const uint8_t* clip_scan) {
2403  for (int col = 0; col < pixel_count; col++) {
2404    FX_ARGB argb = pPalette ? pPalette[*src_scan] : (*src_scan) * 0x010101;
2405    int src_r = FXARGB_R(argb);
2406    int src_g = FXARGB_G(argb);
2407    int src_b = FXARGB_B(argb);
2408    if (clip_scan && clip_scan[col] < 255) {
2409      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, clip_scan[col]);
2410      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, clip_scan[col]);
2411      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, clip_scan[col]);
2412    } else {
2413      dest_scan[2] = src_b;
2414      dest_scan[1] = src_g;
2415      dest_scan[0] = src_r;
2416    }
2417    dest_scan += DestBpp;
2418    src_scan++;
2419  }
2420}
2421
2422void CompositeRow_1bppRgb2Rgb_NoBlend_RgbByteOrder(uint8_t* dest_scan,
2423                                                   const uint8_t* src_scan,
2424                                                   int src_left,
2425                                                   FX_ARGB* pPalette,
2426                                                   int pixel_count,
2427                                                   int DestBpp,
2428                                                   const uint8_t* clip_scan) {
2429  int reset_r, reset_g, reset_b;
2430  int set_r, set_g, set_b;
2431  if (pPalette) {
2432    reset_r = FXARGB_R(pPalette[0]);
2433    reset_g = FXARGB_G(pPalette[0]);
2434    reset_b = FXARGB_B(pPalette[0]);
2435    set_r = FXARGB_R(pPalette[1]);
2436    set_g = FXARGB_G(pPalette[1]);
2437    set_b = FXARGB_B(pPalette[1]);
2438  } else {
2439    reset_r = reset_g = reset_b = 0;
2440    set_r = set_g = set_b = 255;
2441  }
2442  for (int col = 0; col < pixel_count; col++) {
2443    int src_r, src_g, src_b;
2444    if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
2445      src_r = set_r;
2446      src_g = set_g;
2447      src_b = set_b;
2448    } else {
2449      src_r = reset_r;
2450      src_g = reset_g;
2451      src_b = reset_b;
2452    }
2453    if (clip_scan && clip_scan[col] < 255) {
2454      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, clip_scan[col]);
2455      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, clip_scan[col]);
2456      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, clip_scan[col]);
2457    } else {
2458      dest_scan[2] = src_b;
2459      dest_scan[1] = src_g;
2460      dest_scan[0] = src_r;
2461    }
2462    dest_scan += DestBpp;
2463  }
2464}
2465
2466void CompositeRow_8bppRgb2Argb_NoBlend_RgbByteOrder(uint8_t* dest_scan,
2467                                                    const uint8_t* src_scan,
2468                                                    int width,
2469                                                    FX_ARGB* pPalette,
2470                                                    const uint8_t* clip_scan) {
2471  for (int col = 0; col < width; col++) {
2472    int src_r, src_g, src_b;
2473    if (pPalette) {
2474      FX_ARGB argb = pPalette[*src_scan];
2475      src_r = FXARGB_R(argb);
2476      src_g = FXARGB_G(argb);
2477      src_b = FXARGB_B(argb);
2478    } else {
2479      src_r = src_g = src_b = *src_scan;
2480    }
2481    if (!clip_scan || clip_scan[col] == 255) {
2482      dest_scan[2] = src_b;
2483      dest_scan[1] = src_g;
2484      dest_scan[0] = src_r;
2485      dest_scan[3] = 255;
2486      src_scan++;
2487      dest_scan += 4;
2488      continue;
2489    }
2490    int src_alpha = clip_scan[col];
2491    if (src_alpha == 0) {
2492      dest_scan += 4;
2493      src_scan++;
2494      continue;
2495    }
2496    int back_alpha = dest_scan[3];
2497    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2498    dest_scan[3] = dest_alpha;
2499    int alpha_ratio = src_alpha * 255 / dest_alpha;
2500    dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, alpha_ratio);
2501    dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, alpha_ratio);
2502    dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, alpha_ratio);
2503    dest_scan += 4;
2504    src_scan++;
2505  }
2506}
2507
2508void CompositeRow_1bppRgb2Argb_NoBlend_RgbByteOrder(uint8_t* dest_scan,
2509                                                    const uint8_t* src_scan,
2510                                                    int src_left,
2511                                                    int width,
2512                                                    FX_ARGB* pPalette,
2513                                                    const uint8_t* clip_scan) {
2514  int reset_r, reset_g, reset_b;
2515  int set_r, set_g, set_b;
2516  if (pPalette) {
2517    reset_r = FXARGB_R(pPalette[0]);
2518    reset_g = FXARGB_G(pPalette[0]);
2519    reset_b = FXARGB_B(pPalette[0]);
2520    set_r = FXARGB_R(pPalette[1]);
2521    set_g = FXARGB_G(pPalette[1]);
2522    set_b = FXARGB_B(pPalette[1]);
2523  } else {
2524    reset_r = reset_g = reset_b = 0;
2525    set_r = set_g = set_b = 255;
2526  }
2527  for (int col = 0; col < width; col++) {
2528    int src_r, src_g, src_b;
2529    if (src_scan[(col + src_left) / 8] & (1 << (7 - (col + src_left) % 8))) {
2530      src_r = set_r;
2531      src_g = set_g;
2532      src_b = set_b;
2533    } else {
2534      src_r = reset_r;
2535      src_g = reset_g;
2536      src_b = reset_b;
2537    }
2538    if (!clip_scan || clip_scan[col] == 255) {
2539      dest_scan[2] = src_b;
2540      dest_scan[1] = src_g;
2541      dest_scan[0] = src_r;
2542      dest_scan[3] = 255;
2543      dest_scan += 4;
2544      continue;
2545    }
2546    int src_alpha = clip_scan[col];
2547    if (src_alpha == 0) {
2548      dest_scan += 4;
2549      continue;
2550    }
2551    int back_alpha = dest_scan[3];
2552    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2553    dest_scan[3] = dest_alpha;
2554    int alpha_ratio = src_alpha * 255 / dest_alpha;
2555    dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, alpha_ratio);
2556    dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, alpha_ratio);
2557    dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, alpha_ratio);
2558    dest_scan += 4;
2559  }
2560}
2561
2562void CompositeRow_ByteMask2Argb_RgbByteOrder(uint8_t* dest_scan,
2563                                             const uint8_t* src_scan,
2564                                             int mask_alpha,
2565                                             int src_r,
2566                                             int src_g,
2567                                             int src_b,
2568                                             int pixel_count,
2569                                             int blend_type,
2570                                             const uint8_t* clip_scan) {
2571  for (int col = 0; col < pixel_count; col++) {
2572    int src_alpha;
2573    if (clip_scan) {
2574      src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
2575    } else {
2576      src_alpha = mask_alpha * src_scan[col] / 255;
2577    }
2578    uint8_t back_alpha = dest_scan[3];
2579    if (back_alpha == 0) {
2580      FXARGB_SETRGBORDERDIB(dest_scan,
2581                            FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
2582      dest_scan += 4;
2583      continue;
2584    }
2585    if (src_alpha == 0) {
2586      dest_scan += 4;
2587      continue;
2588    }
2589    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2590    dest_scan[3] = dest_alpha;
2591    int alpha_ratio = src_alpha * 255 / dest_alpha;
2592    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2593      int blended_colors[3];
2594      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
2595                         static_cast<uint8_t>(src_g),
2596                         static_cast<uint8_t>(src_r)};
2597      uint8_t dest_scan_o[3] = {dest_scan[2], dest_scan[1], dest_scan[0]};
2598      RGB_Blend(blend_type, scan, dest_scan_o, blended_colors);
2599      dest_scan[2] =
2600          FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], alpha_ratio);
2601      dest_scan[1] =
2602          FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], alpha_ratio);
2603      dest_scan[0] =
2604          FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], alpha_ratio);
2605    } else if (blend_type) {
2606      int blended = Blend(blend_type, dest_scan[2], src_b);
2607      blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
2608      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, alpha_ratio);
2609      blended = Blend(blend_type, dest_scan[1], src_g);
2610      blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
2611      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, alpha_ratio);
2612      blended = Blend(blend_type, dest_scan[0], src_r);
2613      blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
2614      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, alpha_ratio);
2615    } else {
2616      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, alpha_ratio);
2617      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, alpha_ratio);
2618      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, alpha_ratio);
2619    }
2620    dest_scan += 4;
2621  }
2622}
2623
2624void CompositeRow_ByteMask2Rgb_RgbByteOrder(uint8_t* dest_scan,
2625                                            const uint8_t* src_scan,
2626                                            int mask_alpha,
2627                                            int src_r,
2628                                            int src_g,
2629                                            int src_b,
2630                                            int pixel_count,
2631                                            int blend_type,
2632                                            int Bpp,
2633                                            const uint8_t* clip_scan) {
2634  for (int col = 0; col < pixel_count; col++) {
2635    int src_alpha;
2636    if (clip_scan) {
2637      src_alpha = mask_alpha * clip_scan[col] * src_scan[col] / 255 / 255;
2638    } else {
2639      src_alpha = mask_alpha * src_scan[col] / 255;
2640    }
2641    if (src_alpha == 0) {
2642      dest_scan += Bpp;
2643      continue;
2644    }
2645    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2646      int blended_colors[3];
2647      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
2648                         static_cast<uint8_t>(src_g),
2649                         static_cast<uint8_t>(src_r)};
2650      uint8_t dest_scan_o[3] = {dest_scan[2], dest_scan[1], dest_scan[0]};
2651      RGB_Blend(blend_type, scan, dest_scan_o, blended_colors);
2652      dest_scan[2] =
2653          FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], src_alpha);
2654      dest_scan[1] =
2655          FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], src_alpha);
2656      dest_scan[0] =
2657          FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], src_alpha);
2658    } else if (blend_type) {
2659      int blended = Blend(blend_type, dest_scan[2], src_b);
2660      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, src_alpha);
2661      blended = Blend(blend_type, dest_scan[1], src_g);
2662      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, src_alpha);
2663      blended = Blend(blend_type, dest_scan[0], src_r);
2664      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, src_alpha);
2665    } else {
2666      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, src_alpha);
2667      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, src_alpha);
2668      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, src_alpha);
2669    }
2670    dest_scan += Bpp;
2671  }
2672}
2673
2674void CompositeRow_BitMask2Argb_RgbByteOrder(uint8_t* dest_scan,
2675                                            const uint8_t* src_scan,
2676                                            int mask_alpha,
2677                                            int src_r,
2678                                            int src_g,
2679                                            int src_b,
2680                                            int src_left,
2681                                            int pixel_count,
2682                                            int blend_type,
2683                                            const uint8_t* clip_scan) {
2684  if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) {
2685    FX_ARGB argb = FXARGB_MAKE(0xff, src_r, src_g, src_b);
2686    for (int col = 0; col < pixel_count; col++) {
2687      if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
2688        FXARGB_SETRGBORDERDIB(dest_scan, argb);
2689      }
2690      dest_scan += 4;
2691    }
2692    return;
2693  }
2694  for (int col = 0; col < pixel_count; col++) {
2695    if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
2696      dest_scan += 4;
2697      continue;
2698    }
2699    int src_alpha;
2700    if (clip_scan) {
2701      src_alpha = mask_alpha * clip_scan[col] / 255;
2702    } else {
2703      src_alpha = mask_alpha;
2704    }
2705    uint8_t back_alpha = dest_scan[3];
2706    if (back_alpha == 0) {
2707      FXARGB_SETRGBORDERDIB(dest_scan,
2708                            FXARGB_MAKE(src_alpha, src_r, src_g, src_b));
2709      dest_scan += 4;
2710      continue;
2711    }
2712    uint8_t dest_alpha = back_alpha + src_alpha - back_alpha * src_alpha / 255;
2713    dest_scan[3] = dest_alpha;
2714    int alpha_ratio = src_alpha * 255 / dest_alpha;
2715    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2716      int blended_colors[3];
2717      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
2718                         static_cast<uint8_t>(src_g),
2719                         static_cast<uint8_t>(src_r)};
2720      uint8_t dest_scan_o[3] = {dest_scan[2], dest_scan[1], dest_scan[0]};
2721      RGB_Blend(blend_type, scan, dest_scan_o, blended_colors);
2722      dest_scan[2] =
2723          FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], alpha_ratio);
2724      dest_scan[1] =
2725          FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], alpha_ratio);
2726      dest_scan[0] =
2727          FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], alpha_ratio);
2728    } else if (blend_type) {
2729      int blended = Blend(blend_type, dest_scan[2], src_b);
2730      blended = FXDIB_ALPHA_MERGE(src_b, blended, back_alpha);
2731      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], blended, alpha_ratio);
2732      blended = Blend(blend_type, dest_scan[1], src_g);
2733      blended = FXDIB_ALPHA_MERGE(src_g, blended, back_alpha);
2734      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], blended, alpha_ratio);
2735      blended = Blend(blend_type, dest_scan[0], src_r);
2736      blended = FXDIB_ALPHA_MERGE(src_r, blended, back_alpha);
2737      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], blended, alpha_ratio);
2738    } else {
2739      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, alpha_ratio);
2740      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, alpha_ratio);
2741      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, alpha_ratio);
2742    }
2743    dest_scan += 4;
2744  }
2745}
2746
2747void CompositeRow_BitMask2Rgb_RgbByteOrder(uint8_t* dest_scan,
2748                                           const uint8_t* src_scan,
2749                                           int mask_alpha,
2750                                           int src_r,
2751                                           int src_g,
2752                                           int src_b,
2753                                           int src_left,
2754                                           int pixel_count,
2755                                           int blend_type,
2756                                           int Bpp,
2757                                           const uint8_t* clip_scan) {
2758  if (blend_type == FXDIB_BLEND_NORMAL && !clip_scan && mask_alpha == 255) {
2759    for (int col = 0; col < pixel_count; col++) {
2760      if (src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8))) {
2761        dest_scan[2] = src_b;
2762        dest_scan[1] = src_g;
2763        dest_scan[0] = src_r;
2764      }
2765      dest_scan += Bpp;
2766    }
2767    return;
2768  }
2769  for (int col = 0; col < pixel_count; col++) {
2770    if (!(src_scan[(src_left + col) / 8] & (1 << (7 - (src_left + col) % 8)))) {
2771      dest_scan += Bpp;
2772      continue;
2773    }
2774    int src_alpha;
2775    if (clip_scan) {
2776      src_alpha = mask_alpha * clip_scan[col] / 255;
2777    } else {
2778      src_alpha = mask_alpha;
2779    }
2780    if (src_alpha == 0) {
2781      dest_scan += Bpp;
2782      continue;
2783    }
2784    if (blend_type >= FXDIB_BLEND_NONSEPARABLE) {
2785      int blended_colors[3];
2786      uint8_t scan[3] = {static_cast<uint8_t>(src_b),
2787                         static_cast<uint8_t>(src_g),
2788                         static_cast<uint8_t>(src_r)};
2789      uint8_t dest_scan_o[3] = {dest_scan[2], dest_scan[1], dest_scan[0]};
2790      RGB_Blend(blend_type, scan, dest_scan_o, blended_colors);
2791      dest_scan[2] =
2792          FXDIB_ALPHA_MERGE(dest_scan[2], blended_colors[0], src_alpha);
2793      dest_scan[1] =
2794          FXDIB_ALPHA_MERGE(dest_scan[1], blended_colors[1], src_alpha);
2795      dest_scan[0] =
2796          FXDIB_ALPHA_MERGE(dest_scan[0], blended_colors[2], src_alpha);
2797    } else if (blend_type) {
2798      int back_color = dest_scan[2];
2799      int blended = Blend(blend_type, back_color, src_b);
2800      dest_scan[2] = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
2801      back_color = dest_scan[1];
2802      blended = Blend(blend_type, back_color, src_g);
2803      dest_scan[1] = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
2804      back_color = dest_scan[0];
2805      blended = Blend(blend_type, back_color, src_r);
2806      dest_scan[0] = FXDIB_ALPHA_MERGE(back_color, blended, src_alpha);
2807    } else {
2808      dest_scan[2] = FXDIB_ALPHA_MERGE(dest_scan[2], src_b, src_alpha);
2809      dest_scan[1] = FXDIB_ALPHA_MERGE(dest_scan[1], src_g, src_alpha);
2810      dest_scan[0] = FXDIB_ALPHA_MERGE(dest_scan[0], src_r, src_alpha);
2811    }
2812    dest_scan += Bpp;
2813  }
2814}
2815
2816}  // namespace
2817
2818CFX_ScanlineCompositor::CFX_ScanlineCompositor()
2819    : m_BlendType(FXDIB_BLEND_NORMAL), m_bRgbByteOrder(false) {}
2820
2821CFX_ScanlineCompositor::~CFX_ScanlineCompositor() {}
2822
2823bool CFX_ScanlineCompositor::Init(FXDIB_Format dest_format,
2824                                  FXDIB_Format src_format,
2825                                  int32_t width,
2826                                  uint32_t* pSrcPalette,
2827                                  uint32_t mask_color,
2828                                  int blend_type,
2829                                  bool bClip,
2830                                  bool bRgbByteOrder,
2831                                  int alpha_flag) {
2832  m_SrcFormat = src_format;
2833  m_DestFormat = dest_format;
2834  m_BlendType = blend_type;
2835  m_bRgbByteOrder = bRgbByteOrder;
2836  if ((dest_format & 0xff) == 1)
2837    return false;
2838  if (m_SrcFormat == FXDIB_1bppMask || m_SrcFormat == FXDIB_8bppMask) {
2839    InitSourceMask(alpha_flag, mask_color);
2840    return true;
2841  }
2842  if ((~src_format & 0x0400) && (dest_format & 0x0400))
2843    return false;
2844  if ((m_SrcFormat & 0xff) <= 8) {
2845    if (dest_format == FXDIB_8bppMask)
2846      return true;
2847
2848    InitSourcePalette(src_format, dest_format, pSrcPalette);
2849    m_iTransparency =
2850        (dest_format == FXDIB_Argb ? 1 : 0) + (dest_format & 0x0200 ? 2 : 0) +
2851        (dest_format & 0x0400 ? 4 : 0) + ((src_format & 0xff) == 1 ? 8 : 0);
2852    return true;
2853  }
2854  m_iTransparency =
2855      (src_format & 0x0200 ? 0 : 1) + (dest_format & 0x0200 ? 0 : 2) +
2856      (blend_type == FXDIB_BLEND_NORMAL ? 4 : 0) + (bClip ? 8 : 0) +
2857      (src_format & 0x0400 ? 16 : 0) + (dest_format & 0x0400 ? 32 : 0);
2858  return true;
2859}
2860
2861void CFX_ScanlineCompositor::InitSourceMask(int alpha_flag,
2862                                            uint32_t mask_color) {
2863  int mask_black = 0;
2864  if (alpha_flag >> 8) {
2865    m_MaskAlpha = alpha_flag & 0xff;
2866    m_MaskRed = FXSYS_GetCValue(mask_color);
2867    m_MaskGreen = FXSYS_GetMValue(mask_color);
2868    m_MaskBlue = FXSYS_GetYValue(mask_color);
2869    mask_black = FXSYS_GetKValue(mask_color);
2870  } else {
2871    m_MaskAlpha = FXARGB_A(mask_color);
2872    m_MaskRed = FXARGB_R(mask_color);
2873    m_MaskGreen = FXARGB_G(mask_color);
2874    m_MaskBlue = FXARGB_B(mask_color);
2875  }
2876  if (m_DestFormat == FXDIB_8bppMask)
2877    return;
2878
2879  if ((m_DestFormat & 0xff) == 8) {
2880    if (alpha_flag >> 8) {
2881      uint8_t r;
2882      uint8_t g;
2883      uint8_t b;
2884      std::tie(r, g, b) =
2885          AdobeCMYK_to_sRGB1(m_MaskRed, m_MaskGreen, m_MaskBlue, mask_black);
2886      m_MaskRed = FXRGB2GRAY(r, g, b);
2887    } else {
2888      m_MaskRed = FXRGB2GRAY(m_MaskRed, m_MaskGreen, m_MaskBlue);
2889    }
2890    if (m_DestFormat & 0x0400)
2891      m_MaskRed = FX_CCOLOR(m_MaskRed);
2892    return;
2893  }
2894  uint8_t* mask_color_p = (uint8_t*)&mask_color;
2895  mask_color =
2896      (alpha_flag >> 8) ? FXCMYK_TODIB(mask_color) : FXARGB_TODIB(mask_color);
2897  if (alpha_flag >> 8) {
2898    std::tie(mask_color_p[2], mask_color_p[1], mask_color_p[0]) =
2899        AdobeCMYK_to_sRGB1(mask_color_p[0], mask_color_p[1], mask_color_p[2],
2900                           mask_color_p[3]);
2901    m_MaskRed = mask_color_p[2];
2902    m_MaskGreen = mask_color_p[1];
2903    m_MaskBlue = mask_color_p[0];
2904  }
2905}
2906
2907void CFX_ScanlineCompositor::InitSourcePalette(FXDIB_Format src_format,
2908                                               FXDIB_Format dest_format,
2909                                               const uint32_t* pSrcPalette) {
2910  bool isSrcCmyk = !!(src_format & 0x0400);
2911  bool isDstCmyk = !!(dest_format & 0x0400);
2912  m_pSrcPalette = nullptr;
2913  if (pSrcPalette) {
2914    if ((dest_format & 0xff) == 8) {
2915      int pal_count = 1 << (src_format & 0xff);
2916      uint8_t* gray_pal = FX_Alloc(uint8_t, pal_count);
2917      m_pSrcPalette.reset(reinterpret_cast<uint32_t*>(gray_pal));
2918      if (isSrcCmyk) {
2919        for (int i = 0; i < pal_count; ++i) {
2920          FX_CMYK cmyk = pSrcPalette[i];
2921          uint8_t r;
2922          uint8_t g;
2923          uint8_t b;
2924          std::tie(r, g, b) =
2925              AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk),
2926                                 FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk));
2927          *gray_pal++ = FXRGB2GRAY(r, g, b);
2928        }
2929      } else {
2930        for (int i = 0; i < pal_count; ++i) {
2931          FX_ARGB argb = pSrcPalette[i];
2932          *gray_pal++ =
2933              FXRGB2GRAY(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb));
2934        }
2935      }
2936      return;
2937    }
2938    int palsize = 1 << (src_format & 0xff);
2939    m_pSrcPalette.reset(FX_Alloc(uint32_t, palsize));
2940    uint32_t* pPalette = m_pSrcPalette.get();
2941    if (isDstCmyk == isSrcCmyk) {
2942      memcpy(pPalette, pSrcPalette, palsize * sizeof(uint32_t));
2943    } else {
2944      for (int i = 0; i < palsize; ++i) {
2945        FX_CMYK cmyk = pSrcPalette[i];
2946        uint8_t r;
2947        uint8_t g;
2948        uint8_t b;
2949        std::tie(r, g, b) =
2950            AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk),
2951                               FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk));
2952        pPalette[i] = FXARGB_MAKE(0xff, r, g, b);
2953      }
2954    }
2955    return;
2956  }
2957  if ((dest_format & 0xff) == 8) {
2958    int pal_count = 1 << (src_format & 0xff);
2959    uint8_t* gray_pal = FX_Alloc(uint8_t, pal_count);
2960    if (pal_count == 2) {
2961      gray_pal[0] = 0;
2962      gray_pal[1] = 255;
2963    } else {
2964      for (int i = 0; i < pal_count; ++i)
2965        gray_pal[i] = i;
2966    }
2967    m_pSrcPalette.reset(reinterpret_cast<uint32_t*>(gray_pal));
2968    return;
2969  }
2970  int palsize = 1 << (src_format & 0xff);
2971  m_pSrcPalette.reset(FX_Alloc(uint32_t, palsize));
2972  uint32_t* pPalette = m_pSrcPalette.get();
2973  if (palsize == 2) {
2974    pPalette[0] = isSrcCmyk ? 255 : 0xff000000;
2975    pPalette[1] = isSrcCmyk ? 0 : 0xffffffff;
2976  } else {
2977    for (int i = 0; i < palsize; ++i)
2978      pPalette[i] = isSrcCmyk ? FX_CCOLOR(i) : (i * 0x10101);
2979  }
2980  if (isSrcCmyk != isDstCmyk) {
2981    for (int i = 0; i < palsize; ++i) {
2982      FX_CMYK cmyk = pPalette[i];
2983      uint8_t r;
2984      uint8_t g;
2985      uint8_t b;
2986      std::tie(r, g, b) =
2987          AdobeCMYK_to_sRGB1(FXSYS_GetCValue(cmyk), FXSYS_GetMValue(cmyk),
2988                             FXSYS_GetYValue(cmyk), FXSYS_GetKValue(cmyk));
2989      pPalette[i] = FXARGB_MAKE(0xff, r, g, b);
2990    }
2991  }
2992}
2993
2994void CFX_ScanlineCompositor::CompositeRgbBitmapLine(
2995    uint8_t* dest_scan,
2996    const uint8_t* src_scan,
2997    int width,
2998    const uint8_t* clip_scan,
2999    const uint8_t* src_extra_alpha,
3000    uint8_t* dst_extra_alpha) {
3001  int src_Bpp = (m_SrcFormat & 0xff) >> 3;
3002  int dest_Bpp = (m_DestFormat & 0xff) >> 3;
3003  if (m_bRgbByteOrder) {
3004    switch (m_iTransparency) {
3005      case 0:
3006      case 4:
3007      case 8:
3008      case 12:
3009        CompositeRow_Argb2Argb_RgbByteOrder(dest_scan, src_scan, width,
3010                                            m_BlendType, clip_scan);
3011        break;
3012      case 1:
3013        CompositeRow_Rgb2Argb_Blend_NoClip_RgbByteOrder(
3014            dest_scan, src_scan, width, m_BlendType, src_Bpp);
3015        break;
3016      case 2:
3017      case 10:
3018        CompositeRow_Argb2Rgb_Blend_RgbByteOrder(
3019            dest_scan, src_scan, width, m_BlendType, dest_Bpp, clip_scan);
3020        break;
3021      case 3:
3022        CompositeRow_Rgb2Rgb_Blend_NoClip_RgbByteOrder(
3023            dest_scan, src_scan, width, m_BlendType, dest_Bpp, src_Bpp);
3024        break;
3025      case 5:
3026        CompositeRow_Rgb2Argb_NoBlend_NoClip_RgbByteOrder(dest_scan, src_scan,
3027                                                          width, src_Bpp);
3028        break;
3029      case 6:
3030      case 14:
3031        CompositeRow_Argb2Rgb_NoBlend_RgbByteOrder(dest_scan, src_scan, width,
3032                                                   dest_Bpp, clip_scan);
3033        break;
3034      case 7:
3035        CompositeRow_Rgb2Rgb_NoBlend_NoClip_RgbByteOrder(
3036            dest_scan, src_scan, width, dest_Bpp, src_Bpp);
3037        break;
3038      case 9:
3039        CompositeRow_Rgb2Argb_Blend_Clip_RgbByteOrder(
3040            dest_scan, src_scan, width, m_BlendType, src_Bpp, clip_scan);
3041        break;
3042      case 11:
3043        CompositeRow_Rgb2Rgb_Blend_Clip_RgbByteOrder(dest_scan, src_scan, width,
3044                                                     m_BlendType, dest_Bpp,
3045                                                     src_Bpp, clip_scan);
3046        break;
3047      case 13:
3048        CompositeRow_Rgb2Argb_NoBlend_Clip_RgbByteOrder(
3049            dest_scan, src_scan, width, src_Bpp, clip_scan);
3050        break;
3051      case 15:
3052        CompositeRow_Rgb2Rgb_NoBlend_Clip_RgbByteOrder(
3053            dest_scan, src_scan, width, dest_Bpp, src_Bpp, clip_scan);
3054        break;
3055    }
3056    return;
3057  }
3058  if (m_DestFormat == FXDIB_8bppMask) {
3059    if (m_SrcFormat & 0x0200) {
3060      if (m_SrcFormat == FXDIB_Argb) {
3061        CompositeRow_AlphaToMask(dest_scan, src_scan, width, clip_scan, 4);
3062      } else {
3063        CompositeRow_AlphaToMask(dest_scan, src_extra_alpha, width, clip_scan,
3064                                 1);
3065      }
3066    } else {
3067      CompositeRow_Rgb2Mask(dest_scan, src_scan, width, clip_scan);
3068    }
3069  } else if ((m_DestFormat & 0xff) == 8) {
3070    if (m_DestFormat & 0x0400) {
3071      for (int i = 0; i < width; ++i) {
3072        *dest_scan = ~*dest_scan;
3073        dest_scan++;
3074      }
3075    }
3076    if (m_SrcFormat & 0x0200) {
3077      if (m_DestFormat & 0x0200) {
3078        CompositeRow_Argb2Graya(dest_scan, src_scan, width, m_BlendType,
3079                                clip_scan, src_extra_alpha, dst_extra_alpha);
3080      } else {
3081        CompositeRow_Argb2Gray(dest_scan, src_scan, width, m_BlendType,
3082                               clip_scan, src_extra_alpha);
3083      }
3084    } else {
3085      if (m_DestFormat & 0x0200) {
3086        CompositeRow_Rgb2Graya(dest_scan, src_scan, src_Bpp, width, m_BlendType,
3087                               clip_scan, dst_extra_alpha);
3088      } else {
3089        CompositeRow_Rgb2Gray(dest_scan, src_scan, src_Bpp, width, m_BlendType,
3090                              clip_scan);
3091      }
3092    }
3093    if (m_DestFormat & 0x0400) {
3094      for (int i = 0; i < width; ++i) {
3095        *dest_scan = ~*dest_scan;
3096        dest_scan++;
3097      }
3098    }
3099  } else {
3100    switch (m_iTransparency) {
3101      case 0:
3102      case 4:
3103      case 8:
3104      case 4 + 8: {
3105        CompositeRow_Argb2Argb(dest_scan, src_scan, width, m_BlendType,
3106                               clip_scan, dst_extra_alpha, src_extra_alpha);
3107      } break;
3108      case 1:
3109        CompositeRow_Rgb2Argb_Blend_NoClip(
3110            dest_scan, src_scan, width, m_BlendType, src_Bpp, dst_extra_alpha);
3111        break;
3112      case 1 + 8:
3113        CompositeRow_Rgb2Argb_Blend_Clip(dest_scan, src_scan, width,
3114                                         m_BlendType, src_Bpp, clip_scan,
3115                                         dst_extra_alpha);
3116        break;
3117      case 1 + 4:
3118        CompositeRow_Rgb2Argb_NoBlend_NoClip(dest_scan, src_scan, width,
3119                                             src_Bpp, dst_extra_alpha);
3120        break;
3121      case 1 + 4 + 8:
3122        CompositeRow_Rgb2Argb_NoBlend_Clip(dest_scan, src_scan, width, src_Bpp,
3123                                           clip_scan, dst_extra_alpha);
3124        break;
3125      case 2:
3126      case 2 + 8:
3127        CompositeRow_Argb2Rgb_Blend(dest_scan, src_scan, width, m_BlendType,
3128                                    dest_Bpp, clip_scan, src_extra_alpha);
3129        break;
3130      case 2 + 4:
3131      case 2 + 4 + 8:
3132        CompositeRow_Argb2Rgb_NoBlend(dest_scan, src_scan, width, dest_Bpp,
3133                                      clip_scan, src_extra_alpha);
3134        break;
3135      case 1 + 2:
3136        CompositeRow_Rgb2Rgb_Blend_NoClip(dest_scan, src_scan, width,
3137                                          m_BlendType, dest_Bpp, src_Bpp);
3138        break;
3139      case 1 + 2 + 8:
3140        CompositeRow_Rgb2Rgb_Blend_Clip(dest_scan, src_scan, width, m_BlendType,
3141                                        dest_Bpp, src_Bpp, clip_scan);
3142        break;
3143      case 1 + 2 + 4:
3144        CompositeRow_Rgb2Rgb_NoBlend_NoClip(dest_scan, src_scan, width,
3145                                            dest_Bpp, src_Bpp);
3146        break;
3147      case 1 + 2 + 4 + 8:
3148        CompositeRow_Rgb2Rgb_NoBlend_Clip(dest_scan, src_scan, width, dest_Bpp,
3149                                          src_Bpp, clip_scan);
3150        break;
3151    }
3152  }
3153}
3154
3155void CFX_ScanlineCompositor::CompositePalBitmapLine(
3156    uint8_t* dest_scan,
3157    const uint8_t* src_scan,
3158    int src_left,
3159    int width,
3160    const uint8_t* clip_scan,
3161    const uint8_t* src_extra_alpha,
3162    uint8_t* dst_extra_alpha) {
3163  if (m_bRgbByteOrder) {
3164    if (m_SrcFormat == FXDIB_1bppRgb) {
3165      if (m_DestFormat == FXDIB_8bppRgb) {
3166        return;
3167      }
3168      if (m_DestFormat == FXDIB_Argb) {
3169        CompositeRow_1bppRgb2Argb_NoBlend_RgbByteOrder(
3170            dest_scan, src_scan, src_left, width, m_pSrcPalette.get(),
3171            clip_scan);
3172      } else {
3173        CompositeRow_1bppRgb2Rgb_NoBlend_RgbByteOrder(
3174            dest_scan, src_scan, src_left, m_pSrcPalette.get(), width,
3175            (m_DestFormat & 0xff) >> 3, clip_scan);
3176      }
3177    } else {
3178      if (m_DestFormat == FXDIB_8bppRgb) {
3179        return;
3180      }
3181      if (m_DestFormat == FXDIB_Argb) {
3182        CompositeRow_8bppRgb2Argb_NoBlend_RgbByteOrder(
3183            dest_scan, src_scan, width, m_pSrcPalette.get(), clip_scan);
3184      } else {
3185        CompositeRow_8bppRgb2Rgb_NoBlend_RgbByteOrder(
3186            dest_scan, src_scan, m_pSrcPalette.get(), width,
3187            (m_DestFormat & 0xff) >> 3, clip_scan);
3188      }
3189    }
3190    return;
3191  }
3192  if (m_DestFormat == FXDIB_8bppMask) {
3193    CompositeRow_Rgb2Mask(dest_scan, src_scan, width, clip_scan);
3194    return;
3195  }
3196  if ((m_DestFormat & 0xff) == 8) {
3197    if (m_iTransparency & 8) {
3198      if (m_DestFormat & 0x0200) {
3199        CompositeRow_1bppPal2Graya(
3200            dest_scan, src_scan, src_left,
3201            reinterpret_cast<const uint8_t*>(m_pSrcPalette.get()), width,
3202            m_BlendType, clip_scan, dst_extra_alpha);
3203      } else {
3204        CompositeRow_1bppPal2Gray(
3205            dest_scan, src_scan, src_left,
3206            reinterpret_cast<const uint8_t*>(m_pSrcPalette.get()), width,
3207            m_BlendType, clip_scan);
3208      }
3209    } else {
3210      if (m_DestFormat & 0x0200)
3211        CompositeRow_8bppPal2Graya(
3212            dest_scan, src_scan,
3213            reinterpret_cast<const uint8_t*>(m_pSrcPalette.get()), width,
3214            m_BlendType, clip_scan, dst_extra_alpha, src_extra_alpha);
3215      else
3216        CompositeRow_8bppPal2Gray(
3217            dest_scan, src_scan,
3218            reinterpret_cast<const uint8_t*>(m_pSrcPalette.get()), width,
3219            m_BlendType, clip_scan, src_extra_alpha);
3220    }
3221  } else {
3222    switch (m_iTransparency) {
3223      case 1 + 2:
3224        CompositeRow_8bppRgb2Argb_NoBlend(dest_scan, src_scan, width,
3225                                          m_pSrcPalette.get(), clip_scan,
3226                                          src_extra_alpha);
3227        break;
3228      case 1 + 2 + 8:
3229        CompositeRow_1bppRgb2Argb_NoBlend(dest_scan, src_scan, src_left, width,
3230                                          m_pSrcPalette.get(), clip_scan);
3231        break;
3232      case 0:
3233        CompositeRow_8bppRgb2Rgb_NoBlend(
3234            dest_scan, src_scan, m_pSrcPalette.get(), width,
3235            (m_DestFormat & 0xff) >> 3, clip_scan, src_extra_alpha);
3236        break;
3237      case 0 + 8:
3238        CompositeRow_1bppRgb2Rgb_NoBlend(dest_scan, src_scan, src_left,
3239                                         m_pSrcPalette.get(), width,
3240                                         (m_DestFormat & 0xff) >> 3, clip_scan);
3241        break;
3242      case 0 + 2:
3243        CompositeRow_8bppRgb2Rgb_NoBlend(
3244            dest_scan, src_scan, m_pSrcPalette.get(), width,
3245            (m_DestFormat & 0xff) >> 3, clip_scan, src_extra_alpha);
3246        break;
3247      case 0 + 2 + 8:
3248        CompositeRow_1bppRgb2Rgba_NoBlend(dest_scan, src_scan, src_left, width,
3249                                          m_pSrcPalette.get(), clip_scan,
3250                                          dst_extra_alpha);
3251        break;
3252        break;
3253    }
3254  }
3255}
3256
3257void CFX_ScanlineCompositor::CompositeByteMaskLine(uint8_t* dest_scan,
3258                                                   const uint8_t* src_scan,
3259                                                   int width,
3260                                                   const uint8_t* clip_scan,
3261                                                   uint8_t* dst_extra_alpha) {
3262  if (m_DestFormat == FXDIB_8bppMask) {
3263    CompositeRow_ByteMask2Mask(dest_scan, src_scan, m_MaskAlpha, width,
3264                               clip_scan);
3265  } else if ((m_DestFormat & 0xff) == 8) {
3266    if (m_DestFormat & 0x0200) {
3267      CompositeRow_ByteMask2Graya(dest_scan, src_scan, m_MaskAlpha, m_MaskRed,
3268                                  width, clip_scan, dst_extra_alpha);
3269    } else {
3270      CompositeRow_ByteMask2Gray(dest_scan, src_scan, m_MaskAlpha, m_MaskRed,
3271                                 width, clip_scan);
3272    }
3273  } else if (m_bRgbByteOrder) {
3274    if (m_DestFormat == FXDIB_Argb) {
3275      CompositeRow_ByteMask2Argb_RgbByteOrder(
3276          dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
3277          width, m_BlendType, clip_scan);
3278    } else {
3279      CompositeRow_ByteMask2Rgb_RgbByteOrder(
3280          dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
3281          width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan);
3282    }
3283    return;
3284  } else if (m_DestFormat == FXDIB_Argb) {
3285    CompositeRow_ByteMask2Argb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed,
3286                               m_MaskGreen, m_MaskBlue, width, m_BlendType,
3287                               clip_scan);
3288  } else if (m_DestFormat == FXDIB_Rgb || m_DestFormat == FXDIB_Rgb32) {
3289    CompositeRow_ByteMask2Rgb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed,
3290                              m_MaskGreen, m_MaskBlue, width, m_BlendType,
3291                              (m_DestFormat & 0xff) >> 3, clip_scan);
3292  } else if (m_DestFormat == FXDIB_Rgba) {
3293    CompositeRow_ByteMask2Rgba(dest_scan, src_scan, m_MaskAlpha, m_MaskRed,
3294                               m_MaskGreen, m_MaskBlue, width, m_BlendType,
3295                               clip_scan, dst_extra_alpha);
3296  }
3297}
3298
3299void CFX_ScanlineCompositor::CompositeBitMaskLine(uint8_t* dest_scan,
3300                                                  const uint8_t* src_scan,
3301                                                  int src_left,
3302                                                  int width,
3303                                                  const uint8_t* clip_scan,
3304                                                  uint8_t* dst_extra_alpha) {
3305  if (m_DestFormat == FXDIB_8bppMask) {
3306    CompositeRow_BitMask2Mask(dest_scan, src_scan, m_MaskAlpha, src_left, width,
3307                              clip_scan);
3308  } else if ((m_DestFormat & 0xff) == 8) {
3309    if (m_DestFormat & 0x0200) {
3310      CompositeRow_BitMask2Graya(dest_scan, src_scan, m_MaskAlpha, m_MaskRed,
3311                                 src_left, width, clip_scan, dst_extra_alpha);
3312    } else {
3313      CompositeRow_BitMask2Gray(dest_scan, src_scan, m_MaskAlpha, m_MaskRed,
3314                                src_left, width, clip_scan);
3315    }
3316  } else if (m_bRgbByteOrder) {
3317    if (m_DestFormat == FXDIB_Argb) {
3318      CompositeRow_BitMask2Argb_RgbByteOrder(
3319          dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
3320          src_left, width, m_BlendType, clip_scan);
3321    } else {
3322      CompositeRow_BitMask2Rgb_RgbByteOrder(
3323          dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
3324          src_left, width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan);
3325    }
3326    return;
3327  } else if (m_DestFormat == FXDIB_Argb) {
3328    CompositeRow_BitMask2Argb(dest_scan, src_scan, m_MaskAlpha, m_MaskRed,
3329                              m_MaskGreen, m_MaskBlue, src_left, width,
3330                              m_BlendType, clip_scan);
3331  } else if (m_DestFormat == FXDIB_Rgb || m_DestFormat == FXDIB_Rgb32) {
3332    CompositeRow_BitMask2Rgb(
3333        dest_scan, src_scan, m_MaskAlpha, m_MaskRed, m_MaskGreen, m_MaskBlue,
3334        src_left, width, m_BlendType, (m_DestFormat & 0xff) >> 3, clip_scan);
3335  }
3336}
3337