Don't bother checking pointers before delete[] and FX_Free().
[pdfium.git] / core / src / fxge / dib / fx_dib_main.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../../include/fxge/fx_dib.h"
8 #include "../../../include/fxge/fx_ge.h"
9 #include "../../../include/fxcodec/fx_codec.h"
10 #include "dib_int.h"
11 #include <limits.h>
12 FX_BOOL ConvertBuffer(FXDIB_Format dest_format,
13                       uint8_t* dest_buf,
14                       int dest_pitch,
15                       int width,
16                       int height,
17                       const CFX_DIBSource* pSrcBitmap,
18                       int src_left,
19                       int src_top,
20                       FX_DWORD*& pal,
21                       void* pIccTransform);
22 void CmykDecode(FX_DWORD cmyk, int& c, int& m, int& y, int& k) {
23   c = FXSYS_GetCValue(cmyk);
24   m = FXSYS_GetMValue(cmyk);
25   y = FXSYS_GetYValue(cmyk);
26   k = FXSYS_GetKValue(cmyk);
27 }
28 void ArgbDecode(FX_DWORD argb, int& a, int& r, int& g, int& b) {
29   a = FXARGB_A(argb);
30   r = FXARGB_R(argb);
31   g = FXARGB_G(argb);
32   b = FXARGB_B(argb);
33 }
34 void ArgbDecode(FX_DWORD argb, int& a, FX_COLORREF& rgb) {
35   a = FXARGB_A(argb);
36   rgb = FXSYS_RGB(FXARGB_R(argb), FXARGB_G(argb), FXARGB_B(argb));
37 }
38 FX_DWORD ArgbEncode(int a, FX_COLORREF rgb) {
39   return FXARGB_MAKE(a, FXSYS_GetRValue(rgb), FXSYS_GetGValue(rgb),
40                      FXSYS_GetBValue(rgb));
41 }
42 CFX_DIBSource::CFX_DIBSource() {
43   m_bpp = 0;
44   m_AlphaFlag = 0;
45   m_Width = m_Height = 0;
46   m_Pitch = 0;
47   m_pPalette = NULL;
48   m_pAlphaMask = NULL;
49 }
50 CFX_DIBSource::~CFX_DIBSource() {
51   FX_Free(m_pPalette);
52   delete m_pAlphaMask;
53 }
54 CFX_DIBitmap::CFX_DIBitmap() {
55   m_bExtBuf = FALSE;
56   m_pBuffer = NULL;
57   m_pPalette = NULL;
58 }
59 #define _MAX_OOM_LIMIT_ 12000000
60 FX_BOOL CFX_DIBitmap::Create(int width,
61                              int height,
62                              FXDIB_Format format,
63                              uint8_t* pBuffer,
64                              int pitch) {
65   m_pBuffer = NULL;
66   m_bpp = (uint8_t)format;
67   m_AlphaFlag = (uint8_t)(format >> 8);
68   m_Width = m_Height = m_Pitch = 0;
69   if (width <= 0 || height <= 0 || pitch < 0) {
70     return FALSE;
71   }
72   if ((INT_MAX - 31) / width < (format & 0xff)) {
73     return FALSE;
74   }
75   if (!pitch) {
76     pitch = (width * (format & 0xff) + 31) / 32 * 4;
77   }
78   if ((1 << 30) / pitch < height) {
79     return FALSE;
80   }
81   if (pBuffer) {
82     m_pBuffer = pBuffer;
83     m_bExtBuf = TRUE;
84   } else {
85     int size = pitch * height + 4;
86     int oomlimit = _MAX_OOM_LIMIT_;
87     if (oomlimit >= 0 && size >= oomlimit) {
88       m_pBuffer = FX_TryAlloc(uint8_t, size);
89       if (m_pBuffer == NULL) {
90         return FALSE;
91       }
92     } else {
93       m_pBuffer = FX_Alloc(uint8_t, size);
94     }
95   }
96   m_Width = width;
97   m_Height = height;
98   m_Pitch = pitch;
99   if (HasAlpha() && format != FXDIB_Argb) {
100     FX_BOOL ret = TRUE;
101     ret = BuildAlphaMask();
102     if (!ret) {
103       if (!m_bExtBuf) {
104         FX_Free(m_pBuffer);
105         m_pBuffer = NULL;
106         m_Width = m_Height = m_Pitch = 0;
107         return FALSE;
108       }
109     }
110   }
111   return TRUE;
112 }
113 FX_BOOL CFX_DIBitmap::Copy(const CFX_DIBSource* pSrc) {
114   if (m_pBuffer) {
115     return FALSE;
116   }
117   if (!Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat())) {
118     return FALSE;
119   }
120   CopyPalette(pSrc->GetPalette());
121   CopyAlphaMask(pSrc->m_pAlphaMask);
122   for (int row = 0; row < pSrc->GetHeight(); row++) {
123     FXSYS_memcpy(m_pBuffer + row * m_Pitch, pSrc->GetScanline(row), m_Pitch);
124   }
125   return TRUE;
126 }
127 CFX_DIBitmap::~CFX_DIBitmap() {
128   if (!m_bExtBuf) {
129     FX_Free(m_pBuffer);
130   }
131   m_pBuffer = NULL;
132 }
133 void CFX_DIBitmap::TakeOver(CFX_DIBitmap* pSrcBitmap) {
134   if (!m_bExtBuf) {
135     FX_Free(m_pBuffer);
136   }
137   FX_Free(m_pPalette);
138   delete m_pAlphaMask;
139   m_pBuffer = pSrcBitmap->m_pBuffer;
140   m_pPalette = pSrcBitmap->m_pPalette;
141   m_pAlphaMask = pSrcBitmap->m_pAlphaMask;
142   pSrcBitmap->m_pBuffer = NULL;
143   pSrcBitmap->m_pPalette = NULL;
144   pSrcBitmap->m_pAlphaMask = NULL;
145   m_bpp = pSrcBitmap->m_bpp;
146   m_bExtBuf = pSrcBitmap->m_bExtBuf;
147   m_AlphaFlag = pSrcBitmap->m_AlphaFlag;
148   m_Width = pSrcBitmap->m_Width;
149   m_Height = pSrcBitmap->m_Height;
150   m_Pitch = pSrcBitmap->m_Pitch;
151 }
152 CFX_DIBitmap* CFX_DIBSource::Clone(const FX_RECT* pClip) const {
153   FX_RECT rect(0, 0, m_Width, m_Height);
154   if (pClip) {
155     rect.Intersect(*pClip);
156     if (rect.IsEmpty()) {
157       return NULL;
158     }
159   }
160   CFX_DIBitmap* pNewBitmap = new CFX_DIBitmap;
161   if (!pNewBitmap->Create(rect.Width(), rect.Height(), GetFormat())) {
162     delete pNewBitmap;
163     return NULL;
164   }
165   pNewBitmap->CopyPalette(m_pPalette);
166   pNewBitmap->CopyAlphaMask(m_pAlphaMask, pClip);
167   if (GetBPP() == 1 && rect.left % 8 != 0) {
168     int left_shift = rect.left % 32;
169     int right_shift = 32 - left_shift;
170     int dword_count = pNewBitmap->m_Pitch / 4;
171     for (int row = rect.top; row < rect.bottom; row++) {
172       FX_DWORD* src_scan = (FX_DWORD*)GetScanline(row) + rect.left / 32;
173       FX_DWORD* dest_scan = (FX_DWORD*)pNewBitmap->GetScanline(row - rect.top);
174       for (int i = 0; i < dword_count; i++) {
175         dest_scan[i] =
176             (src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift);
177       }
178     }
179   } else {
180     int copy_len = (pNewBitmap->GetWidth() * pNewBitmap->GetBPP() + 7) / 8;
181     if (m_Pitch < (FX_DWORD)copy_len) {
182       copy_len = m_Pitch;
183     }
184     for (int row = rect.top; row < rect.bottom; row++) {
185       const uint8_t* src_scan = GetScanline(row) + rect.left * m_bpp / 8;
186       uint8_t* dest_scan = (uint8_t*)pNewBitmap->GetScanline(row - rect.top);
187       FXSYS_memcpy(dest_scan, src_scan, copy_len);
188     }
189   }
190   return pNewBitmap;
191 }
192 void CFX_DIBSource::BuildPalette() {
193   if (m_pPalette) {
194     return;
195   }
196   if (GetBPP() == 1) {
197     m_pPalette = FX_Alloc(FX_DWORD, 2);
198     if (IsCmykImage()) {
199       m_pPalette[0] = 0xff;
200       m_pPalette[1] = 0;
201     } else {
202       m_pPalette[0] = 0xff000000;
203       m_pPalette[1] = 0xffffffff;
204     }
205   } else if (GetBPP() == 8) {
206     m_pPalette = FX_Alloc(FX_DWORD, 256);
207     if (IsCmykImage()) {
208       for (int i = 0; i < 256; i++) {
209         m_pPalette[i] = 0xff - i;
210       }
211     } else {
212       for (int i = 0; i < 256; i++) {
213         m_pPalette[i] = 0xff000000 | (i * 0x10101);
214       }
215     }
216   }
217 }
218 FX_BOOL CFX_DIBSource::BuildAlphaMask() {
219   if (m_pAlphaMask) {
220     return TRUE;
221   }
222   m_pAlphaMask = new CFX_DIBitmap;
223   if (!m_pAlphaMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
224     delete m_pAlphaMask;
225     m_pAlphaMask = NULL;
226     return FALSE;
227   }
228   FXSYS_memset(m_pAlphaMask->GetBuffer(), 0xff,
229                m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch());
230   return TRUE;
231 }
232 FX_DWORD CFX_DIBSource::GetPaletteEntry(int index) const {
233   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
234   if (m_pPalette) {
235     return m_pPalette[index];
236   }
237   if (IsCmykImage()) {
238     if (GetBPP() == 1) {
239       return index ? 0 : 0xff;
240     }
241     return 0xff - index;
242   }
243   if (GetBPP() == 1) {
244     return index ? 0xffffffff : 0xff000000;
245   }
246   return index * 0x10101 | 0xff000000;
247 }
248 void CFX_DIBSource::SetPaletteEntry(int index, FX_DWORD color) {
249   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
250   if (m_pPalette == NULL) {
251     BuildPalette();
252   }
253   m_pPalette[index] = color;
254 }
255 int CFX_DIBSource::FindPalette(FX_DWORD color) const {
256   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
257   if (m_pPalette == NULL) {
258     if (IsCmykImage()) {
259       if (GetBPP() == 1) {
260         return ((uint8_t)color == 0xff) ? 0 : 1;
261       }
262       return 0xff - (uint8_t)color;
263     }
264     if (GetBPP() == 1) {
265       return ((uint8_t)color == 0xff) ? 1 : 0;
266     }
267     return (uint8_t)color;
268   }
269   int palsize = (1 << GetBPP());
270   for (int i = 0; i < palsize; i++)
271     if (m_pPalette[i] == color) {
272       return i;
273     }
274   return -1;
275 }
276 void CFX_DIBitmap::Clear(FX_DWORD color) {
277   if (m_pBuffer == NULL) {
278     return;
279   }
280   switch (GetFormat()) {
281     case FXDIB_1bppMask:
282       FXSYS_memset(m_pBuffer, (color & 0xff000000) ? 0xff : 0,
283                    m_Pitch * m_Height);
284       break;
285     case FXDIB_1bppRgb: {
286       int index = FindPalette(color);
287       FXSYS_memset(m_pBuffer, index ? 0xff : 0, m_Pitch * m_Height);
288       break;
289     }
290     case FXDIB_8bppMask:
291       FXSYS_memset(m_pBuffer, color >> 24, m_Pitch * m_Height);
292       break;
293     case FXDIB_8bppRgb: {
294       int index = FindPalette(color);
295       FXSYS_memset(m_pBuffer, index, m_Pitch * m_Height);
296       break;
297     }
298     case FXDIB_Rgb:
299     case FXDIB_Rgba: {
300       int a, r, g, b;
301       ArgbDecode(color, a, r, g, b);
302       if (r == g && g == b) {
303         FXSYS_memset(m_pBuffer, r, m_Pitch * m_Height);
304       } else {
305         int byte_pos = 0;
306         for (int col = 0; col < m_Width; col++) {
307           m_pBuffer[byte_pos++] = b;
308           m_pBuffer[byte_pos++] = g;
309           m_pBuffer[byte_pos++] = r;
310         }
311         for (int row = 1; row < m_Height; row++) {
312           FXSYS_memcpy(m_pBuffer + row * m_Pitch, m_pBuffer, m_Pitch);
313         }
314       }
315       break;
316     }
317     case FXDIB_Rgb32:
318     case FXDIB_Argb: {
319       color = IsCmykImage() ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
320       for (int i = 0; i < m_Width; i++) {
321         ((FX_DWORD*)m_pBuffer)[i] = color;
322       }
323       for (int row = 1; row < m_Height; row++) {
324         FXSYS_memcpy(m_pBuffer + row * m_Pitch, m_pBuffer, m_Pitch);
325       }
326       break;
327     }
328     default:
329       break;
330   }
331 }
332 void CFX_DIBSource::GetOverlapRect(int& dest_left,
333                                    int& dest_top,
334                                    int& width,
335                                    int& height,
336                                    int src_width,
337                                    int src_height,
338                                    int& src_left,
339                                    int& src_top,
340                                    const CFX_ClipRgn* pClipRgn) {
341   if (width == 0 || height == 0) {
342     return;
343   }
344   ASSERT(width > 0 && height > 0);
345   if (dest_left > m_Width || dest_top > m_Height) {
346     width = 0;
347     height = 0;
348     return;
349   }
350   int x_offset = dest_left - src_left;
351   int y_offset = dest_top - src_top;
352   FX_RECT src_rect(src_left, src_top, src_left + width, src_top + height);
353   FX_RECT src_bound(0, 0, src_width, src_height);
354   src_rect.Intersect(src_bound);
355   FX_RECT dest_rect(src_rect.left + x_offset, src_rect.top + y_offset,
356                     src_rect.right + x_offset, src_rect.bottom + y_offset);
357   FX_RECT dest_bound(0, 0, m_Width, m_Height);
358   dest_rect.Intersect(dest_bound);
359   if (pClipRgn) {
360     dest_rect.Intersect(pClipRgn->GetBox());
361   }
362   dest_left = dest_rect.left;
363   dest_top = dest_rect.top;
364   src_left = dest_left - x_offset;
365   src_top = dest_top - y_offset;
366   width = dest_rect.right - dest_rect.left;
367   height = dest_rect.bottom - dest_rect.top;
368 }
369 FX_BOOL CFX_DIBitmap::TransferBitmap(int dest_left,
370                                      int dest_top,
371                                      int width,
372                                      int height,
373                                      const CFX_DIBSource* pSrcBitmap,
374                                      int src_left,
375                                      int src_top,
376                                      void* pIccTransform) {
377   if (m_pBuffer == NULL) {
378     return FALSE;
379   }
380   GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(),
381                  pSrcBitmap->GetHeight(), src_left, src_top, NULL);
382   if (width == 0 || height == 0) {
383     return TRUE;
384   }
385   FXDIB_Format dest_format = GetFormat();
386   FXDIB_Format src_format = pSrcBitmap->GetFormat();
387   if (dest_format == src_format && pIccTransform == NULL) {
388     if (GetBPP() == 1) {
389       for (int row = 0; row < height; row++) {
390         uint8_t* dest_scan = m_pBuffer + (dest_top + row) * m_Pitch;
391         const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
392         for (int col = 0; col < width; col++) {
393           if (src_scan[(src_left + col) / 8] &
394               (1 << (7 - (src_left + col) % 8))) {
395             dest_scan[(dest_left + col) / 8] |= 1
396                                                 << (7 - (dest_left + col) % 8);
397           } else {
398             dest_scan[(dest_left + col) / 8] &=
399                 ~(1 << (7 - (dest_left + col) % 8));
400           }
401         }
402       }
403     } else {
404       int Bpp = GetBPP() / 8;
405       for (int row = 0; row < height; row++) {
406         uint8_t* dest_scan =
407             m_pBuffer + (dest_top + row) * m_Pitch + dest_left * Bpp;
408         const uint8_t* src_scan =
409             pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
410         FXSYS_memcpy(dest_scan, src_scan, width * Bpp);
411       }
412     }
413   } else {
414     if (m_pPalette) {
415       return FALSE;
416     }
417     if (m_bpp == 8) {
418       dest_format = FXDIB_8bppMask;
419     }
420     uint8_t* dest_buf =
421         m_pBuffer + dest_top * m_Pitch + dest_left * GetBPP() / 8;
422     FX_DWORD* d_plt = NULL;
423     if (!ConvertBuffer(dest_format, dest_buf, m_Pitch, width, height,
424                        pSrcBitmap, src_left, src_top, d_plt, pIccTransform)) {
425       return FALSE;
426     }
427   }
428   return TRUE;
429 }
430 FX_BOOL CFX_DIBitmap::TransferMask(int dest_left,
431                                    int dest_top,
432                                    int width,
433                                    int height,
434                                    const CFX_DIBSource* pMask,
435                                    FX_DWORD color,
436                                    int src_left,
437                                    int src_top,
438                                    int alpha_flag,
439                                    void* pIccTransform) {
440   if (m_pBuffer == NULL) {
441     return FALSE;
442   }
443   ASSERT(HasAlpha() && (m_bpp >= 24));
444   ASSERT(pMask->IsAlphaMask());
445   if (!HasAlpha() || !pMask->IsAlphaMask() || m_bpp < 24) {
446     return FALSE;
447   }
448   GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(),
449                  pMask->GetHeight(), src_left, src_top, NULL);
450   if (width == 0 || height == 0) {
451     return TRUE;
452   }
453   int src_bpp = pMask->GetBPP();
454   int alpha;
455   FX_DWORD dst_color;
456   if (alpha_flag >> 8) {
457     alpha = alpha_flag & 0xff;
458     dst_color = FXCMYK_TODIB(color);
459   } else {
460     alpha = FXARGB_A(color);
461     dst_color = FXARGB_TODIB(color);
462   }
463   uint8_t* color_p = (uint8_t*)&dst_color;
464   if (pIccTransform && CFX_GEModule::Get()->GetCodecModule() &&
465       CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) {
466     ICodec_IccModule* pIccModule =
467         CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
468     pIccModule->TranslateScanline(pIccTransform, color_p, color_p, 1);
469   } else {
470     if (alpha_flag >> 8 && !IsCmykImage())
471       AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color),
472                          FXSYS_GetYValue(color), FXSYS_GetKValue(color),
473                          color_p[2], color_p[1], color_p[0]);
474     else if (!(alpha_flag >> 8) && IsCmykImage()) {
475       return FALSE;
476     }
477   }
478   if (!IsCmykImage()) {
479     color_p[3] = (uint8_t)alpha;
480   }
481   if (GetFormat() == FXDIB_Argb) {
482     for (int row = 0; row < height; row++) {
483       FX_DWORD* dest_pos =
484           (FX_DWORD*)(m_pBuffer + (dest_top + row) * m_Pitch + dest_left * 4);
485       const uint8_t* src_scan = pMask->GetScanline(src_top + row);
486       if (src_bpp == 1) {
487         for (int col = 0; col < width; col++) {
488           int src_bitpos = src_left + col;
489           if (src_scan[src_bitpos / 8] & (1 << (7 - src_bitpos % 8))) {
490             *dest_pos = dst_color;
491           } else {
492             *dest_pos = 0;
493           }
494           dest_pos++;
495         }
496       } else {
497         src_scan += src_left;
498         dst_color = FXARGB_TODIB(dst_color);
499         dst_color &= 0xffffff;
500         for (int col = 0; col < width; col++) {
501           FXARGB_SETDIB(dest_pos++,
502                         dst_color | ((alpha * (*src_scan++) / 255) << 24));
503         }
504       }
505     }
506   } else {
507     int comps = m_bpp / 8;
508     for (int row = 0; row < height; row++) {
509       uint8_t* dest_color_pos =
510           m_pBuffer + (dest_top + row) * m_Pitch + dest_left * comps;
511       uint8_t* dest_alpha_pos =
512           (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left;
513       const uint8_t* src_scan = pMask->GetScanline(src_top + row);
514       if (src_bpp == 1) {
515         for (int col = 0; col < width; col++) {
516           int src_bitpos = src_left + col;
517           if (src_scan[src_bitpos / 8] & (1 << (7 - src_bitpos % 8))) {
518             FXSYS_memcpy(dest_color_pos, color_p, comps);
519             *dest_alpha_pos = 0xff;
520           } else {
521             FXSYS_memset(dest_color_pos, 0, comps);
522             *dest_alpha_pos = 0;
523           }
524           dest_color_pos += comps;
525           dest_alpha_pos++;
526         }
527       } else {
528         src_scan += src_left;
529         for (int col = 0; col < width; col++) {
530           FXSYS_memcpy(dest_color_pos, color_p, comps);
531           dest_color_pos += comps;
532           *dest_alpha_pos++ = (alpha * (*src_scan++) / 255);
533         }
534       }
535     }
536   }
537   return TRUE;
538 }
539 void CFX_DIBSource::CopyPalette(const FX_DWORD* pSrc, FX_DWORD size) {
540   if (pSrc == NULL || GetBPP() > 8) {
541     FX_Free(m_pPalette);
542     m_pPalette = NULL;
543   } else {
544     FX_DWORD pal_size = 1 << GetBPP();
545     if (m_pPalette == NULL) {
546       m_pPalette = FX_Alloc(FX_DWORD, pal_size);
547     }
548     if (pal_size > size) {
549       pal_size = size;
550     }
551     FXSYS_memcpy(m_pPalette, pSrc, pal_size * sizeof(FX_DWORD));
552   }
553 }
554 void CFX_DIBSource::GetPalette(FX_DWORD* pal, int alpha) const {
555   ASSERT(GetBPP() <= 8 && !IsCmykImage());
556   if (GetBPP() == 1) {
557     pal[0] =
558         ((m_pPalette ? m_pPalette[0] : 0xff000000) & 0xffffff) | (alpha << 24);
559     pal[1] =
560         ((m_pPalette ? m_pPalette[1] : 0xffffffff) & 0xffffff) | (alpha << 24);
561     return;
562   }
563   if (m_pPalette) {
564     for (int i = 0; i < 256; i++) {
565       pal[i] = (m_pPalette[i] & 0x00ffffff) | (alpha << 24);
566     }
567   } else {
568     for (int i = 0; i < 256; i++) {
569       pal[i] = (i * 0x10101) | (alpha << 24);
570     }
571   }
572 }
573 CFX_DIBitmap* CFX_DIBSource::GetAlphaMask(const FX_RECT* pClip) const {
574   ASSERT(GetFormat() == FXDIB_Argb);
575   FX_RECT rect(0, 0, m_Width, m_Height);
576   if (pClip) {
577     rect.Intersect(*pClip);
578     if (rect.IsEmpty()) {
579       return NULL;
580     }
581   }
582   CFX_DIBitmap* pMask = new CFX_DIBitmap;
583   if (!pMask->Create(rect.Width(), rect.Height(), FXDIB_8bppMask)) {
584     delete pMask;
585     return NULL;
586   }
587   for (int row = rect.top; row < rect.bottom; row++) {
588     const uint8_t* src_scan = GetScanline(row) + rect.left * 4 + 3;
589     uint8_t* dest_scan = (uint8_t*)pMask->GetScanline(row - rect.top);
590     for (int col = rect.left; col < rect.right; col++) {
591       *dest_scan++ = *src_scan;
592       src_scan += 4;
593     }
594   }
595   return pMask;
596 }
597 FX_BOOL CFX_DIBSource::CopyAlphaMask(const CFX_DIBSource* pAlphaMask,
598                                      const FX_RECT* pClip) {
599   if (!HasAlpha() || GetFormat() == FXDIB_Argb) {
600     return FALSE;
601   }
602   if (pAlphaMask) {
603     FX_RECT rect(0, 0, pAlphaMask->m_Width, pAlphaMask->m_Height);
604     if (pClip) {
605       rect.Intersect(*pClip);
606       if (rect.IsEmpty() || rect.Width() != m_Width ||
607           rect.Height() != m_Height) {
608         return FALSE;
609       }
610     } else {
611       if (pAlphaMask->m_Width != m_Width || pAlphaMask->m_Height != m_Height) {
612         return FALSE;
613       }
614     }
615     for (int row = 0; row < m_Height; row++)
616       FXSYS_memcpy((void*)m_pAlphaMask->GetScanline(row),
617                    pAlphaMask->GetScanline(row + rect.top) + rect.left,
618                    m_pAlphaMask->m_Pitch);
619   } else {
620     m_pAlphaMask->Clear(0xff000000);
621   }
622   return TRUE;
623 }
624 const int g_ChannelOffset[] = {0, 2, 1, 0, 0, 1, 2, 3, 3};
625 FX_BOOL CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel,
626                                   const CFX_DIBSource* pSrcBitmap,
627                                   FXDIB_Channel srcChannel) {
628   if (m_pBuffer == NULL) {
629     return FALSE;
630   }
631   CFX_DIBSource* pSrcClone = (CFX_DIBSource*)pSrcBitmap;
632   CFX_DIBitmap* pDst = this;
633   int destOffset, srcOffset;
634   if (srcChannel == FXDIB_Alpha) {
635     if (!pSrcBitmap->HasAlpha() && !pSrcBitmap->IsAlphaMask()) {
636       return FALSE;
637     }
638     if (pSrcBitmap->GetBPP() == 1) {
639       pSrcClone = pSrcBitmap->CloneConvert(FXDIB_8bppMask);
640       if (pSrcClone == NULL) {
641         return FALSE;
642       }
643     }
644     if (pSrcBitmap->GetFormat() == FXDIB_Argb) {
645       srcOffset = 3;
646     } else {
647       srcOffset = 0;
648     }
649   } else {
650     if (pSrcBitmap->IsAlphaMask()) {
651       return FALSE;
652     }
653     if (pSrcBitmap->GetBPP() < 24) {
654       if (pSrcBitmap->IsCmykImage()) {
655         pSrcClone = pSrcBitmap->CloneConvert(
656             (FXDIB_Format)((pSrcBitmap->GetFormat() & 0xff00) | 0x20));
657       } else {
658         pSrcClone = pSrcBitmap->CloneConvert(
659             (FXDIB_Format)((pSrcBitmap->GetFormat() & 0xff00) | 0x18));
660       }
661       if (pSrcClone == NULL) {
662         return FALSE;
663       }
664     }
665     srcOffset = g_ChannelOffset[srcChannel];
666   }
667   if (destChannel == FXDIB_Alpha) {
668     if (IsAlphaMask()) {
669       if (!ConvertFormat(FXDIB_8bppMask)) {
670         if (pSrcClone != pSrcBitmap) {
671           delete pSrcClone;
672         }
673         return FALSE;
674       }
675       destOffset = 0;
676     } else {
677       destOffset = 0;
678       if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
679         if (pSrcClone != pSrcBitmap) {
680           delete pSrcClone;
681         }
682         return FALSE;
683       }
684       if (GetFormat() == FXDIB_Argb) {
685         destOffset = 3;
686       }
687     }
688   } else {
689     if (IsAlphaMask()) {
690       if (pSrcClone != pSrcBitmap) {
691         delete pSrcClone;
692       }
693       return FALSE;
694     }
695     if (GetBPP() < 24) {
696       if (HasAlpha()) {
697         if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
698           if (pSrcClone != pSrcBitmap) {
699             delete pSrcClone;
700           }
701           return FALSE;
702         }
703       } else
704 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
705           if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) {
706 #else
707           if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) {
708 #endif
709         if (pSrcClone != pSrcBitmap) {
710           delete pSrcClone;
711         }
712         return FALSE;
713       }
714     }
715     destOffset = g_ChannelOffset[destChannel];
716   }
717   if (srcChannel == FXDIB_Alpha && pSrcClone->m_pAlphaMask) {
718     CFX_DIBitmap* pAlphaMask = pSrcClone->m_pAlphaMask;
719     if (pSrcClone->GetWidth() != m_Width ||
720         pSrcClone->GetHeight() != m_Height) {
721       if (pAlphaMask) {
722         pAlphaMask = pAlphaMask->StretchTo(m_Width, m_Height);
723         if (pAlphaMask == NULL) {
724           if (pSrcClone != pSrcBitmap) {
725             delete pSrcClone;
726           }
727           return FALSE;
728         }
729       }
730     }
731     if (pSrcClone != pSrcBitmap) {
732       pSrcClone->m_pAlphaMask = NULL;
733       delete pSrcClone;
734     }
735     pSrcClone = pAlphaMask;
736     srcOffset = 0;
737   } else if (pSrcClone->GetWidth() != m_Width ||
738              pSrcClone->GetHeight() != m_Height) {
739     CFX_DIBitmap* pSrcMatched = pSrcClone->StretchTo(m_Width, m_Height);
740     if (pSrcClone != pSrcBitmap) {
741       delete pSrcClone;
742     }
743     if (pSrcMatched == NULL) {
744       return FALSE;
745     }
746     pSrcClone = pSrcMatched;
747   }
748   if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
749     pDst = m_pAlphaMask;
750     destOffset = 0;
751   }
752   int srcBytes = pSrcClone->GetBPP() / 8;
753   int destBytes = pDst->GetBPP() / 8;
754   for (int row = 0; row < m_Height; row++) {
755     uint8_t* dest_pos = (uint8_t*)pDst->GetScanline(row) + destOffset;
756     const uint8_t* src_pos = pSrcClone->GetScanline(row) + srcOffset;
757     for (int col = 0; col < m_Width; col++) {
758       *dest_pos = *src_pos;
759       dest_pos += destBytes;
760       src_pos += srcBytes;
761     }
762   }
763   if (pSrcClone != pSrcBitmap && pSrcClone != pSrcBitmap->m_pAlphaMask) {
764     delete pSrcClone;
765   }
766   return TRUE;
767 }
768 FX_BOOL CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel, int value) {
769   if (m_pBuffer == NULL) {
770     return FALSE;
771   }
772   int destOffset;
773   if (destChannel == FXDIB_Alpha) {
774     if (IsAlphaMask()) {
775       if (!ConvertFormat(FXDIB_8bppMask)) {
776         return FALSE;
777       }
778       destOffset = 0;
779     } else {
780       destOffset = 0;
781       if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
782         return FALSE;
783       }
784       if (GetFormat() == FXDIB_Argb) {
785         destOffset = 3;
786       }
787     }
788   } else {
789     if (IsAlphaMask()) {
790       return FALSE;
791     }
792     if (GetBPP() < 24) {
793       if (HasAlpha()) {
794         if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
795           return FALSE;
796         }
797       } else
798 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
799           if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) {
800         return FALSE;
801       }
802 #else
803           if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) {
804         return FALSE;
805       }
806 #endif
807     }
808     destOffset = g_ChannelOffset[destChannel];
809   }
810   int Bpp = GetBPP() / 8;
811   if (Bpp == 1) {
812     FXSYS_memset(m_pBuffer, value, m_Height * m_Pitch);
813     return TRUE;
814   }
815   if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
816     FXSYS_memset(m_pAlphaMask->GetBuffer(), value,
817                  m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch());
818     return TRUE;
819   }
820   for (int row = 0; row < m_Height; row++) {
821     uint8_t* scan_line = m_pBuffer + row * m_Pitch + destOffset;
822     for (int col = 0; col < m_Width; col++) {
823       *scan_line = value;
824       scan_line += Bpp;
825     }
826   }
827   return TRUE;
828 }
829 FX_BOOL CFX_DIBitmap::MultiplyAlpha(const CFX_DIBSource* pSrcBitmap) {
830   if (m_pBuffer == NULL) {
831     return FALSE;
832   }
833   ASSERT(pSrcBitmap->IsAlphaMask());
834   if (!pSrcBitmap->IsAlphaMask()) {
835     return FALSE;
836   }
837   if (!IsAlphaMask() && !HasAlpha()) {
838     return LoadChannel(FXDIB_Alpha, pSrcBitmap, FXDIB_Alpha);
839   }
840   CFX_DIBitmap* pSrcClone = (CFX_DIBitmap*)pSrcBitmap;
841   if (pSrcBitmap->GetWidth() != m_Width ||
842       pSrcBitmap->GetHeight() != m_Height) {
843     pSrcClone = pSrcBitmap->StretchTo(m_Width, m_Height);
844     ASSERT(pSrcClone != NULL);
845     if (pSrcClone == NULL) {
846       return FALSE;
847     }
848   }
849   if (IsAlphaMask()) {
850     if (!ConvertFormat(FXDIB_8bppMask)) {
851       if (pSrcClone != pSrcBitmap) {
852         delete pSrcClone;
853       }
854       return FALSE;
855     }
856     for (int row = 0; row < m_Height; row++) {
857       uint8_t* dest_scan = m_pBuffer + m_Pitch * row;
858       uint8_t* src_scan = pSrcClone->m_pBuffer + pSrcClone->m_Pitch * row;
859       if (pSrcClone->GetBPP() == 1) {
860         for (int col = 0; col < m_Width; col++) {
861           if (!((1 << (7 - col % 8)) & src_scan[col / 8])) {
862             dest_scan[col] = 0;
863           }
864         }
865       } else {
866         for (int col = 0; col < m_Width; col++) {
867           *dest_scan = (*dest_scan) * src_scan[col] / 255;
868           dest_scan++;
869         }
870       }
871     }
872   } else {
873     if (GetFormat() == FXDIB_Argb) {
874       if (pSrcClone->GetBPP() == 1) {
875         if (pSrcClone != pSrcBitmap) {
876           delete pSrcClone;
877         }
878         return FALSE;
879       }
880       for (int row = 0; row < m_Height; row++) {
881         uint8_t* dest_scan = m_pBuffer + m_Pitch * row + 3;
882         uint8_t* src_scan = pSrcClone->m_pBuffer + pSrcClone->m_Pitch * row;
883         for (int col = 0; col < m_Width; col++) {
884           *dest_scan = (*dest_scan) * src_scan[col] / 255;
885           dest_scan += 4;
886         }
887       }
888     } else {
889       m_pAlphaMask->MultiplyAlpha(pSrcClone);
890     }
891   }
892   if (pSrcClone != pSrcBitmap) {
893     delete pSrcClone;
894   }
895   return TRUE;
896 }
897 FX_BOOL CFX_DIBitmap::GetGrayData(void* pIccTransform) {
898   if (m_pBuffer == NULL) {
899     return FALSE;
900   }
901   switch (GetFormat()) {
902     case FXDIB_1bppRgb: {
903       if (m_pPalette == NULL) {
904         return FALSE;
905       }
906       uint8_t gray[2];
907       for (int i = 0; i < 2; i++) {
908         int r = (uint8_t)(m_pPalette[i] >> 16);
909         int g = (uint8_t)(m_pPalette[i] >> 8);
910         int b = (uint8_t)m_pPalette[i];
911         gray[i] = (uint8_t)FXRGB2GRAY(r, g, b);
912       }
913       CFX_DIBitmap* pMask = new CFX_DIBitmap;
914       if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
915         delete pMask;
916         return FALSE;
917       }
918       FXSYS_memset(pMask->GetBuffer(), gray[0], pMask->GetPitch() * m_Height);
919       for (int row = 0; row < m_Height; row++) {
920         uint8_t* src_pos = m_pBuffer + row * m_Pitch;
921         uint8_t* dest_pos = (uint8_t*)pMask->GetScanline(row);
922         for (int col = 0; col < m_Width; col++) {
923           if (src_pos[col / 8] & (1 << (7 - col % 8))) {
924             *dest_pos = gray[1];
925           }
926           dest_pos++;
927         }
928       }
929       TakeOver(pMask);
930       delete pMask;
931       break;
932     }
933     case FXDIB_8bppRgb: {
934       if (m_pPalette == NULL) {
935         return FALSE;
936       }
937       uint8_t gray[256];
938       for (int i = 0; i < 256; i++) {
939         int r = (uint8_t)(m_pPalette[i] >> 16);
940         int g = (uint8_t)(m_pPalette[i] >> 8);
941         int b = (uint8_t)m_pPalette[i];
942         gray[i] = (uint8_t)FXRGB2GRAY(r, g, b);
943       }
944       CFX_DIBitmap* pMask = new CFX_DIBitmap;
945       if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
946         delete pMask;
947         return FALSE;
948       }
949       for (int row = 0; row < m_Height; row++) {
950         uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
951         uint8_t* src_pos = m_pBuffer + row * m_Pitch;
952         for (int col = 0; col < m_Width; col++) {
953           *dest_pos++ = gray[*src_pos++];
954         }
955       }
956       TakeOver(pMask);
957       delete pMask;
958       break;
959     }
960     case FXDIB_Rgb: {
961       CFX_DIBitmap* pMask = new CFX_DIBitmap;
962       if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
963         delete pMask;
964         return FALSE;
965       }
966       for (int row = 0; row < m_Height; row++) {
967         uint8_t* src_pos = m_pBuffer + row * m_Pitch;
968         uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
969         for (int col = 0; col < m_Width; col++) {
970           *dest_pos++ = FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos);
971           src_pos += 3;
972         }
973       }
974       TakeOver(pMask);
975       delete pMask;
976       break;
977     }
978     case FXDIB_Rgb32: {
979       CFX_DIBitmap* pMask = new CFX_DIBitmap;
980       if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
981         delete pMask;
982         return FALSE;
983       }
984       for (int row = 0; row < m_Height; row++) {
985         uint8_t* src_pos = m_pBuffer + row * m_Pitch;
986         uint8_t* dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
987         for (int col = 0; col < m_Width; col++) {
988           *dest_pos++ = FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos);
989           src_pos += 4;
990         }
991       }
992       TakeOver(pMask);
993       delete pMask;
994       break;
995     }
996     default:
997       return FALSE;
998   }
999   return TRUE;
1000 }
1001 FX_BOOL CFX_DIBitmap::MultiplyAlpha(int alpha) {
1002   if (m_pBuffer == NULL) {
1003     return FALSE;
1004   }
1005   switch (GetFormat()) {
1006     case FXDIB_1bppMask:
1007       if (!ConvertFormat(FXDIB_8bppMask)) {
1008         return FALSE;
1009       }
1010       MultiplyAlpha(alpha);
1011       break;
1012     case FXDIB_8bppMask: {
1013       for (int row = 0; row < m_Height; row++) {
1014         uint8_t* scan_line = m_pBuffer + row * m_Pitch;
1015         for (int col = 0; col < m_Width; col++) {
1016           scan_line[col] = scan_line[col] * alpha / 255;
1017         }
1018       }
1019       break;
1020     }
1021     case FXDIB_Argb: {
1022       for (int row = 0; row < m_Height; row++) {
1023         uint8_t* scan_line = m_pBuffer + row * m_Pitch + 3;
1024         for (int col = 0; col < m_Width; col++) {
1025           *scan_line = (*scan_line) * alpha / 255;
1026           scan_line += 4;
1027         }
1028       }
1029       break;
1030     }
1031     default:
1032       if (HasAlpha()) {
1033         m_pAlphaMask->MultiplyAlpha(alpha);
1034       } else if (IsCmykImage()) {
1035         if (!ConvertFormat((FXDIB_Format)(GetFormat() | 0x0200))) {
1036           return FALSE;
1037         }
1038         m_pAlphaMask->MultiplyAlpha(alpha);
1039       } else {
1040         if (!ConvertFormat(FXDIB_Argb)) {
1041           return FALSE;
1042         }
1043         MultiplyAlpha(alpha);
1044       }
1045       break;
1046   }
1047   return TRUE;
1048 }
1049 FX_DWORD CFX_DIBitmap::GetPixel(int x, int y) const {
1050   if (m_pBuffer == NULL) {
1051     return 0;
1052   }
1053   uint8_t* pos = m_pBuffer + y * m_Pitch + x * GetBPP() / 8;
1054   switch (GetFormat()) {
1055     case FXDIB_1bppMask: {
1056       if ((*pos) & (1 << (7 - x % 8))) {
1057         return 0xff000000;
1058       }
1059       return 0;
1060     }
1061     case FXDIB_1bppRgb: {
1062       if ((*pos) & (1 << (7 - x % 8))) {
1063         return m_pPalette ? m_pPalette[1] : 0xffffffff;
1064       }
1065       return m_pPalette ? m_pPalette[0] : 0xff000000;
1066     }
1067     case FXDIB_8bppMask:
1068       return (*pos) << 24;
1069     case FXDIB_8bppRgb:
1070       return m_pPalette ? m_pPalette[*pos] : (0xff000000 | ((*pos) * 0x10101));
1071     case FXDIB_Rgb:
1072     case FXDIB_Rgba:
1073     case FXDIB_Rgb32:
1074       return FXARGB_GETDIB(pos) | 0xff000000;
1075     case FXDIB_Argb:
1076       return FXARGB_GETDIB(pos);
1077     default:
1078       break;
1079   }
1080   return 0;
1081 }
1082 void CFX_DIBitmap::SetPixel(int x, int y, FX_DWORD color) {
1083   if (m_pBuffer == NULL) {
1084     return;
1085   }
1086   if (x < 0 || x >= m_Width || y < 0 || y >= m_Height) {
1087     return;
1088   }
1089   uint8_t* pos = m_pBuffer + y * m_Pitch + x * GetBPP() / 8;
1090   switch (GetFormat()) {
1091     case FXDIB_1bppMask:
1092       if (color >> 24) {
1093         *pos |= 1 << (7 - x % 8);
1094       } else {
1095         *pos &= ~(1 << (7 - x % 8));
1096       }
1097       break;
1098     case FXDIB_1bppRgb:
1099       if (m_pPalette) {
1100         if (color == m_pPalette[1]) {
1101           *pos |= 1 << (7 - x % 8);
1102         } else {
1103           *pos &= ~(1 << (7 - x % 8));
1104         }
1105       } else {
1106         if (color == 0xffffffff) {
1107           *pos |= 1 << (7 - x % 8);
1108         } else {
1109           *pos &= ~(1 << (7 - x % 8));
1110         }
1111       }
1112       break;
1113     case FXDIB_8bppMask:
1114       *pos = (uint8_t)(color >> 24);
1115       break;
1116     case FXDIB_8bppRgb: {
1117       if (m_pPalette) {
1118         for (int i = 0; i < 256; i++) {
1119           if (m_pPalette[i] == color) {
1120             *pos = (uint8_t)i;
1121             return;
1122           }
1123         }
1124         *pos = 0;
1125       } else {
1126         *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
1127       }
1128       break;
1129     }
1130     case FXDIB_Rgb:
1131     case FXDIB_Rgb32: {
1132       int alpha = FXARGB_A(color);
1133       pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255;
1134       pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255;
1135       pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255;
1136       break;
1137     }
1138     case FXDIB_Rgba: {
1139       pos[0] = FXARGB_B(color);
1140       pos[1] = FXARGB_G(color);
1141       pos[2] = FXARGB_R(color);
1142       break;
1143     }
1144     case FXDIB_Argb:
1145       FXARGB_SETDIB(pos, color);
1146       break;
1147     default:
1148       break;
1149   }
1150 }
1151 void CFX_DIBitmap::DownSampleScanline(int line,
1152                                       uint8_t* dest_scan,
1153                                       int dest_bpp,
1154                                       int dest_width,
1155                                       FX_BOOL bFlipX,
1156                                       int clip_left,
1157                                       int clip_width) const {
1158   if (m_pBuffer == NULL) {
1159     return;
1160   }
1161   int src_Bpp = m_bpp / 8;
1162   uint8_t* scanline = m_pBuffer + line * m_Pitch;
1163   if (src_Bpp == 0) {
1164     for (int i = 0; i < clip_width; i++) {
1165       FX_DWORD dest_x = clip_left + i;
1166       FX_DWORD src_x = dest_x * m_Width / dest_width;
1167       if (bFlipX) {
1168         src_x = m_Width - src_x - 1;
1169       }
1170       src_x %= m_Width;
1171       dest_scan[i] = (scanline[src_x / 8] & (1 << (7 - src_x % 8))) ? 255 : 0;
1172     }
1173   } else if (src_Bpp == 1) {
1174     for (int i = 0; i < clip_width; i++) {
1175       FX_DWORD dest_x = clip_left + i;
1176       FX_DWORD src_x = dest_x * m_Width / dest_width;
1177       if (bFlipX) {
1178         src_x = m_Width - src_x - 1;
1179       }
1180       src_x %= m_Width;
1181       int dest_pos = i;
1182       if (m_pPalette) {
1183         if (!IsCmykImage()) {
1184           dest_pos *= 3;
1185           FX_ARGB argb = m_pPalette[scanline[src_x]];
1186           dest_scan[dest_pos] = FXARGB_B(argb);
1187           dest_scan[dest_pos + 1] = FXARGB_G(argb);
1188           dest_scan[dest_pos + 2] = FXARGB_R(argb);
1189         } else {
1190           dest_pos *= 4;
1191           FX_CMYK cmyk = m_pPalette[scanline[src_x]];
1192           dest_scan[dest_pos] = FXSYS_GetCValue(cmyk);
1193           dest_scan[dest_pos + 1] = FXSYS_GetMValue(cmyk);
1194           dest_scan[dest_pos + 2] = FXSYS_GetYValue(cmyk);
1195           dest_scan[dest_pos + 3] = FXSYS_GetKValue(cmyk);
1196         }
1197       } else {
1198         dest_scan[dest_pos] = scanline[src_x];
1199       }
1200     }
1201   } else {
1202     for (int i = 0; i < clip_width; i++) {
1203       FX_DWORD dest_x = clip_left + i;
1204       FX_DWORD src_x =
1205           bFlipX ? (m_Width - dest_x * m_Width / dest_width - 1) * src_Bpp
1206                  : (dest_x * m_Width / dest_width) * src_Bpp;
1207       src_x %= m_Width * src_Bpp;
1208       int dest_pos = i * src_Bpp;
1209       for (int b = 0; b < src_Bpp; b++) {
1210         dest_scan[dest_pos + b] = scanline[src_x + b];
1211       }
1212     }
1213   }
1214 }
1215 FX_BOOL CFX_DIBitmap::ConvertColorScale(FX_DWORD forecolor,
1216                                         FX_DWORD backcolor) {
1217   ASSERT(!IsAlphaMask());
1218   if (m_pBuffer == NULL || IsAlphaMask()) {
1219     return FALSE;
1220   }
1221   int fc, fm, fy, fk, bc, bm, by, bk;
1222   int fr, fg, fb, br, bg, bb;
1223   FX_BOOL isCmykImage = IsCmykImage();
1224   if (isCmykImage) {
1225     fc = FXSYS_GetCValue(forecolor);
1226     fm = FXSYS_GetMValue(forecolor);
1227     fy = FXSYS_GetYValue(forecolor);
1228     fk = FXSYS_GetKValue(forecolor);
1229     bc = FXSYS_GetCValue(backcolor);
1230     bm = FXSYS_GetMValue(backcolor);
1231     by = FXSYS_GetYValue(backcolor);
1232     bk = FXSYS_GetKValue(backcolor);
1233   } else {
1234     fr = FXSYS_GetRValue(forecolor);
1235     fg = FXSYS_GetGValue(forecolor);
1236     fb = FXSYS_GetBValue(forecolor);
1237     br = FXSYS_GetRValue(backcolor);
1238     bg = FXSYS_GetGValue(backcolor);
1239     bb = FXSYS_GetBValue(backcolor);
1240   }
1241   if (m_bpp <= 8) {
1242     if (isCmykImage) {
1243       if (forecolor == 0xff && backcolor == 0 && m_pPalette == NULL) {
1244         return TRUE;
1245       }
1246     } else if (forecolor == 0 && backcolor == 0xffffff && m_pPalette == NULL) {
1247       return TRUE;
1248     }
1249     if (m_pPalette == NULL) {
1250       BuildPalette();
1251     }
1252     int size = 1 << m_bpp;
1253     if (isCmykImage) {
1254       for (int i = 0; i < size; i++) {
1255         uint8_t b, g, r;
1256         AdobeCMYK_to_sRGB1(FXSYS_GetCValue(m_pPalette[i]),
1257                            FXSYS_GetMValue(m_pPalette[i]),
1258                            FXSYS_GetYValue(m_pPalette[i]),
1259                            FXSYS_GetKValue(m_pPalette[i]), r, g, b);
1260         int gray = 255 - FXRGB2GRAY(r, g, b);
1261         m_pPalette[i] = CmykEncode(
1262             bc + (fc - bc) * gray / 255, bm + (fm - bm) * gray / 255,
1263             by + (fy - by) * gray / 255, bk + (fk - bk) * gray / 255);
1264       }
1265     } else
1266       for (int i = 0; i < size; i++) {
1267         int gray = FXRGB2GRAY(FXARGB_R(m_pPalette[i]), FXARGB_G(m_pPalette[i]),
1268                               FXARGB_B(m_pPalette[i]));
1269         m_pPalette[i] = FXARGB_MAKE(0xff, br + (fr - br) * gray / 255,
1270                                     bg + (fg - bg) * gray / 255,
1271                                     bb + (fb - bb) * gray / 255);
1272       }
1273     return TRUE;
1274   }
1275   if (isCmykImage) {
1276     if (forecolor == 0xff && backcolor == 0x00) {
1277       for (int row = 0; row < m_Height; row++) {
1278         uint8_t* scanline = m_pBuffer + row * m_Pitch;
1279         for (int col = 0; col < m_Width; col++) {
1280           uint8_t b, g, r;
1281           AdobeCMYK_to_sRGB1(scanline[0], scanline[1], scanline[2], scanline[3],
1282                              r, g, b);
1283           *scanline++ = 0;
1284           *scanline++ = 0;
1285           *scanline++ = 0;
1286           *scanline++ = 255 - FXRGB2GRAY(r, g, b);
1287         }
1288       }
1289       return TRUE;
1290     }
1291   } else if (forecolor == 0 && backcolor == 0xffffff) {
1292     for (int row = 0; row < m_Height; row++) {
1293       uint8_t* scanline = m_pBuffer + row * m_Pitch;
1294       int gap = m_bpp / 8 - 2;
1295       for (int col = 0; col < m_Width; col++) {
1296         int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
1297         *scanline++ = gray;
1298         *scanline++ = gray;
1299         *scanline = gray;
1300         scanline += gap;
1301       }
1302     }
1303     return TRUE;
1304   }
1305   if (isCmykImage) {
1306     for (int row = 0; row < m_Height; row++) {
1307       uint8_t* scanline = m_pBuffer + row * m_Pitch;
1308       for (int col = 0; col < m_Width; col++) {
1309         uint8_t b, g, r;
1310         AdobeCMYK_to_sRGB1(scanline[0], scanline[1], scanline[2], scanline[3],
1311                            r, g, b);
1312         int gray = 255 - FXRGB2GRAY(r, g, b);
1313         *scanline++ = bc + (fc - bc) * gray / 255;
1314         *scanline++ = bm + (fm - bm) * gray / 255;
1315         *scanline++ = by + (fy - by) * gray / 255;
1316         *scanline++ = bk + (fk - bk) * gray / 255;
1317       }
1318     }
1319   } else {
1320     for (int row = 0; row < m_Height; row++) {
1321       uint8_t* scanline = m_pBuffer + row * m_Pitch;
1322       int gap = m_bpp / 8 - 2;
1323       for (int col = 0; col < m_Width; col++) {
1324         int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
1325         *scanline++ = bb + (fb - bb) * gray / 255;
1326         *scanline++ = bg + (fg - bg) * gray / 255;
1327         *scanline = br + (fr - br) * gray / 255;
1328         scanline += gap;
1329       }
1330     }
1331   }
1332   return TRUE;
1333 }
1334 FX_BOOL CFX_DIBitmap::DitherFS(const FX_DWORD* pPalette,
1335                                int pal_size,
1336                                const FX_RECT* pRect) {
1337   if (m_pBuffer == NULL) {
1338     return FALSE;
1339   }
1340   if (m_bpp != 8 && m_pPalette != NULL && m_AlphaFlag != 0) {
1341     return FALSE;
1342   }
1343   if (m_Width < 4 && m_Height < 4) {
1344     return FALSE;
1345   }
1346   FX_RECT rect(0, 0, m_Width, m_Height);
1347   if (pRect) {
1348     rect.Intersect(*pRect);
1349   }
1350   uint8_t translate[256];
1351   for (int i = 0; i < 256; i++) {
1352     int err2 = 65536;
1353     for (int j = 0; j < pal_size; j++) {
1354       uint8_t entry = (uint8_t)pPalette[j];
1355       int err = (int)entry - i;
1356       if (err * err < err2) {
1357         err2 = err * err;
1358         translate[i] = entry;
1359       }
1360     }
1361   }
1362   for (int row = rect.top; row < rect.bottom; row++) {
1363     uint8_t* scan = m_pBuffer + row * m_Pitch;
1364     uint8_t* next_scan = m_pBuffer + (row + 1) * m_Pitch;
1365     for (int col = rect.left; col < rect.right; col++) {
1366       int src_pixel = scan[col];
1367       int dest_pixel = translate[src_pixel];
1368       scan[col] = (uint8_t)dest_pixel;
1369       int error = -dest_pixel + src_pixel;
1370       if (col < rect.right - 1) {
1371         int src = scan[col + 1];
1372         src += error * 7 / 16;
1373         if (src > 255) {
1374           scan[col + 1] = 255;
1375         } else if (src < 0) {
1376           scan[col + 1] = 0;
1377         } else {
1378           scan[col + 1] = src;
1379         }
1380       }
1381       if (col < rect.right - 1 && row < rect.bottom - 1) {
1382         int src = next_scan[col + 1];
1383         src += error * 1 / 16;
1384         if (src > 255) {
1385           next_scan[col + 1] = 255;
1386         } else if (src < 0) {
1387           next_scan[col + 1] = 0;
1388         } else {
1389           next_scan[col + 1] = src;
1390         }
1391       }
1392       if (row < rect.bottom - 1) {
1393         int src = next_scan[col];
1394         src += error * 5 / 16;
1395         if (src > 255) {
1396           next_scan[col] = 255;
1397         } else if (src < 0) {
1398           next_scan[col] = 0;
1399         } else {
1400           next_scan[col] = src;
1401         }
1402       }
1403       if (col > rect.left && row < rect.bottom - 1) {
1404         int src = next_scan[col - 1];
1405         src += error * 3 / 16;
1406         if (src > 255) {
1407           next_scan[col - 1] = 255;
1408         } else if (src < 0) {
1409           next_scan[col - 1] = 0;
1410         } else {
1411           next_scan[col - 1] = src;
1412         }
1413       }
1414     }
1415   }
1416   return TRUE;
1417 }
1418 CFX_DIBitmap* CFX_DIBSource::FlipImage(FX_BOOL bXFlip, FX_BOOL bYFlip) const {
1419   CFX_DIBitmap* pFlipped = new CFX_DIBitmap;
1420   if (!pFlipped->Create(m_Width, m_Height, GetFormat())) {
1421     delete pFlipped;
1422     return NULL;
1423   }
1424   pFlipped->CopyPalette(m_pPalette);
1425   uint8_t* pDestBuffer = pFlipped->GetBuffer();
1426   int Bpp = m_bpp / 8;
1427   for (int row = 0; row < m_Height; row++) {
1428     const uint8_t* src_scan = GetScanline(row);
1429     uint8_t* dest_scan =
1430         pDestBuffer + m_Pitch * (bYFlip ? (m_Height - row - 1) : row);
1431     if (!bXFlip) {
1432       FXSYS_memcpy(dest_scan, src_scan, m_Pitch);
1433       continue;
1434     }
1435     if (m_bpp == 1) {
1436       FXSYS_memset(dest_scan, 0, m_Pitch);
1437       for (int col = 0; col < m_Width; col++)
1438         if (src_scan[col / 8] & (1 << (7 - col % 8))) {
1439           int dest_col = m_Width - col - 1;
1440           dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8));
1441         }
1442     } else {
1443       dest_scan += (m_Width - 1) * Bpp;
1444       if (Bpp == 1) {
1445         for (int col = 0; col < m_Width; col++) {
1446           *dest_scan = *src_scan;
1447           dest_scan--;
1448           src_scan++;
1449         }
1450       } else if (Bpp == 3) {
1451         for (int col = 0; col < m_Width; col++) {
1452           dest_scan[0] = src_scan[0];
1453           dest_scan[1] = src_scan[1];
1454           dest_scan[2] = src_scan[2];
1455           dest_scan -= 3;
1456           src_scan += 3;
1457         }
1458       } else {
1459         ASSERT(Bpp == 4);
1460         for (int col = 0; col < m_Width; col++) {
1461           *(FX_DWORD*)dest_scan = *(FX_DWORD*)src_scan;
1462           dest_scan -= 4;
1463           src_scan += 4;
1464         }
1465       }
1466     }
1467   }
1468   if (m_pAlphaMask) {
1469     pDestBuffer = pFlipped->m_pAlphaMask->GetBuffer();
1470     FX_DWORD dest_pitch = pFlipped->m_pAlphaMask->GetPitch();
1471     for (int row = 0; row < m_Height; row++) {
1472       const uint8_t* src_scan = m_pAlphaMask->GetScanline(row);
1473       uint8_t* dest_scan =
1474           pDestBuffer + dest_pitch * (bYFlip ? (m_Height - row - 1) : row);
1475       if (!bXFlip) {
1476         FXSYS_memcpy(dest_scan, src_scan, dest_pitch);
1477         continue;
1478       }
1479       dest_scan += (m_Width - 1);
1480       for (int col = 0; col < m_Width; col++) {
1481         *dest_scan = *src_scan;
1482         dest_scan--;
1483         src_scan++;
1484       }
1485     }
1486   }
1487   return pFlipped;
1488 }
1489 CFX_DIBExtractor::CFX_DIBExtractor(const CFX_DIBSource* pSrc) {
1490   m_pBitmap = NULL;
1491   if (pSrc->GetBuffer() == NULL) {
1492     m_pBitmap = pSrc->Clone();
1493   } else {
1494     m_pBitmap = new CFX_DIBitmap;
1495     if (!m_pBitmap->Create(pSrc->GetWidth(), pSrc->GetHeight(),
1496                            pSrc->GetFormat(), pSrc->GetBuffer())) {
1497       delete m_pBitmap;
1498       m_pBitmap = NULL;
1499       return;
1500     }
1501     m_pBitmap->CopyPalette(pSrc->GetPalette());
1502     m_pBitmap->CopyAlphaMask(pSrc->m_pAlphaMask);
1503   }
1504 }
1505 CFX_DIBExtractor::~CFX_DIBExtractor() {
1506   delete m_pBitmap;
1507 }
1508 CFX_FilteredDIB::CFX_FilteredDIB() {
1509   m_pScanline = NULL;
1510   m_pSrc = NULL;
1511 }
1512 CFX_FilteredDIB::~CFX_FilteredDIB() {
1513   if (m_bAutoDropSrc) {
1514     delete m_pSrc;
1515   }
1516   FX_Free(m_pScanline);
1517 }
1518 void CFX_FilteredDIB::LoadSrc(const CFX_DIBSource* pSrc, FX_BOOL bAutoDropSrc) {
1519   m_pSrc = pSrc;
1520   m_bAutoDropSrc = bAutoDropSrc;
1521   m_Width = pSrc->GetWidth();
1522   m_Height = pSrc->GetHeight();
1523   FXDIB_Format format = GetDestFormat();
1524   m_bpp = (uint8_t)format;
1525   m_AlphaFlag = (uint8_t)(format >> 8);
1526   m_Pitch = (m_Width * (format & 0xff) + 31) / 32 * 4;
1527   m_pPalette = GetDestPalette();
1528   m_pScanline = FX_Alloc(uint8_t, m_Pitch);
1529 }
1530 const uint8_t* CFX_FilteredDIB::GetScanline(int line) const {
1531   TranslateScanline(m_pScanline, m_pSrc->GetScanline(line));
1532   return m_pScanline;
1533 }
1534 void CFX_FilteredDIB::DownSampleScanline(int line,
1535                                          uint8_t* dest_scan,
1536                                          int dest_bpp,
1537                                          int dest_width,
1538                                          FX_BOOL bFlipX,
1539                                          int clip_left,
1540                                          int clip_width) const {
1541   m_pSrc->DownSampleScanline(line, dest_scan, dest_bpp, dest_width, bFlipX,
1542                              clip_left, clip_width);
1543   TranslateDownSamples(dest_scan, dest_scan, clip_width, dest_bpp);
1544 }
1545 CFX_ImageRenderer::CFX_ImageRenderer() {
1546   m_Status = 0;
1547   m_pTransformer = NULL;
1548   m_bRgbByteOrder = FALSE;
1549   m_BlendType = FXDIB_BLEND_NORMAL;
1550 }
1551 CFX_ImageRenderer::~CFX_ImageRenderer() {
1552   delete m_pTransformer;
1553 }
1554 extern FX_RECT _FXDIB_SwapClipBox(FX_RECT& clip,
1555                                   int width,
1556                                   int height,
1557                                   FX_BOOL bFlipX,
1558                                   FX_BOOL bFlipY);
1559 FX_BOOL CFX_ImageRenderer::Start(CFX_DIBitmap* pDevice,
1560                                  const CFX_ClipRgn* pClipRgn,
1561                                  const CFX_DIBSource* pSource,
1562                                  int bitmap_alpha,
1563                                  FX_DWORD mask_color,
1564                                  const CFX_AffineMatrix* pMatrix,
1565                                  FX_DWORD dib_flags,
1566                                  FX_BOOL bRgbByteOrder,
1567                                  int alpha_flag,
1568                                  void* pIccTransform,
1569                                  int blend_type) {
1570   m_Matrix = *pMatrix;
1571   CFX_FloatRect image_rect_f = m_Matrix.GetUnitRect();
1572   FX_RECT image_rect = image_rect_f.GetOutterRect();
1573   m_ClipBox = pClipRgn ? pClipRgn->GetBox() : FX_RECT(0, 0, pDevice->GetWidth(),
1574                                                       pDevice->GetHeight());
1575   m_ClipBox.Intersect(image_rect);
1576   if (m_ClipBox.IsEmpty()) {
1577     return FALSE;
1578   }
1579   m_pDevice = pDevice;
1580   m_pClipRgn = pClipRgn;
1581   m_MaskColor = mask_color;
1582   m_BitmapAlpha = bitmap_alpha;
1583   m_Matrix = *pMatrix;
1584   m_Flags = dib_flags;
1585   m_AlphaFlag = alpha_flag;
1586   m_pIccTransform = pIccTransform;
1587   m_bRgbByteOrder = bRgbByteOrder;
1588   m_BlendType = blend_type;
1589   FX_BOOL ret = TRUE;
1590   if ((FXSYS_fabs(m_Matrix.b) >= 0.5f || m_Matrix.a == 0) ||
1591       (FXSYS_fabs(m_Matrix.c) >= 0.5f || m_Matrix.d == 0)) {
1592     if (FXSYS_fabs(m_Matrix.a) < FXSYS_fabs(m_Matrix.b) / 20 &&
1593         FXSYS_fabs(m_Matrix.d) < FXSYS_fabs(m_Matrix.c) / 20 &&
1594         FXSYS_fabs(m_Matrix.a) < 0.5f && FXSYS_fabs(m_Matrix.d) < 0.5f) {
1595       int dest_width = image_rect.Width();
1596       int dest_height = image_rect.Height();
1597       FX_RECT bitmap_clip = m_ClipBox;
1598       bitmap_clip.Offset(-image_rect.left, -image_rect.top);
1599       bitmap_clip = _FXDIB_SwapClipBox(bitmap_clip, dest_width, dest_height,
1600                                        m_Matrix.c > 0, m_Matrix.b < 0);
1601       m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color, m_ClipBox,
1602                          TRUE, m_Matrix.c > 0, m_Matrix.b < 0, m_bRgbByteOrder,
1603                          alpha_flag, pIccTransform, m_BlendType);
1604       if (!m_Stretcher.Start(&m_Composer, pSource, dest_height, dest_width,
1605                              bitmap_clip, dib_flags)) {
1606         return FALSE;
1607       }
1608       m_Status = 1;
1609       return TRUE;
1610     }
1611     m_Status = 2;
1612     m_pTransformer = new CFX_ImageTransformer;
1613     m_pTransformer->Start(pSource, &m_Matrix, dib_flags, &m_ClipBox);
1614     return TRUE;
1615   }
1616   int dest_width = image_rect.Width();
1617   if (m_Matrix.a < 0) {
1618     dest_width = -dest_width;
1619   }
1620   int dest_height = image_rect.Height();
1621   if (m_Matrix.d > 0) {
1622     dest_height = -dest_height;
1623   }
1624   if (dest_width == 0 || dest_height == 0) {
1625     return FALSE;
1626   }
1627   FX_RECT bitmap_clip = m_ClipBox;
1628   bitmap_clip.Offset(-image_rect.left, -image_rect.top);
1629   m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color, m_ClipBox,
1630                      FALSE, FALSE, FALSE, m_bRgbByteOrder, alpha_flag,
1631                      pIccTransform, m_BlendType);
1632   m_Status = 1;
1633   ret = m_Stretcher.Start(&m_Composer, pSource, dest_width, dest_height,
1634                           bitmap_clip, dib_flags);
1635   return ret;
1636 }
1637 FX_BOOL CFX_ImageRenderer::Continue(IFX_Pause* pPause) {
1638   if (m_Status == 1) {
1639     return m_Stretcher.Continue(pPause);
1640   }
1641   if (m_Status == 2) {
1642     if (m_pTransformer->Continue(pPause)) {
1643       return TRUE;
1644     }
1645     CFX_DIBitmap* pBitmap = m_pTransformer->m_Storer.Detach();
1646     if (pBitmap == NULL) {
1647       return FALSE;
1648     }
1649     if (pBitmap->GetBuffer() == NULL) {
1650       delete pBitmap;
1651       return FALSE;
1652     }
1653     if (pBitmap->IsAlphaMask()) {
1654       if (m_BitmapAlpha != 255) {
1655         if (m_AlphaFlag >> 8) {
1656           m_AlphaFlag =
1657               (((uint8_t)((m_AlphaFlag & 0xff) * m_BitmapAlpha / 255)) |
1658                ((m_AlphaFlag >> 8) << 8));
1659         } else {
1660           m_MaskColor = FXARGB_MUL_ALPHA(m_MaskColor, m_BitmapAlpha);
1661         }
1662       }
1663       m_pDevice->CompositeMask(m_pTransformer->m_ResultLeft,
1664                                m_pTransformer->m_ResultTop, pBitmap->GetWidth(),
1665                                pBitmap->GetHeight(), pBitmap, m_MaskColor, 0, 0,
1666                                m_BlendType, m_pClipRgn, m_bRgbByteOrder,
1667                                m_AlphaFlag, m_pIccTransform);
1668     } else {
1669       if (m_BitmapAlpha != 255) {
1670         pBitmap->MultiplyAlpha(m_BitmapAlpha);
1671       }
1672       m_pDevice->CompositeBitmap(
1673           m_pTransformer->m_ResultLeft, m_pTransformer->m_ResultTop,
1674           pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap, 0, 0, m_BlendType,
1675           m_pClipRgn, m_bRgbByteOrder, m_pIccTransform);
1676     }
1677     delete pBitmap;
1678     return FALSE;
1679   }
1680   return FALSE;
1681 }
1682 CFX_BitmapStorer::CFX_BitmapStorer() {
1683   m_pBitmap = NULL;
1684 }
1685 CFX_BitmapStorer::~CFX_BitmapStorer() {
1686   delete m_pBitmap;
1687 }
1688 CFX_DIBitmap* CFX_BitmapStorer::Detach() {
1689   CFX_DIBitmap* pBitmap = m_pBitmap;
1690   m_pBitmap = NULL;
1691   return pBitmap;
1692 }
1693 void CFX_BitmapStorer::Replace(CFX_DIBitmap* pBitmap) {
1694   delete m_pBitmap;
1695   m_pBitmap = pBitmap;
1696 }
1697 void CFX_BitmapStorer::ComposeScanline(int line,
1698                                        const uint8_t* scanline,
1699                                        const uint8_t* scan_extra_alpha) {
1700   uint8_t* dest_buf = (uint8_t*)m_pBitmap->GetScanline(line);
1701   uint8_t* dest_alpha_buf =
1702       m_pBitmap->m_pAlphaMask
1703           ? (uint8_t*)m_pBitmap->m_pAlphaMask->GetScanline(line)
1704           : NULL;
1705   if (dest_buf) {
1706     FXSYS_memcpy(dest_buf, scanline, m_pBitmap->GetPitch());
1707   }
1708   if (dest_alpha_buf) {
1709     FXSYS_memcpy(dest_alpha_buf, scan_extra_alpha,
1710                  m_pBitmap->m_pAlphaMask->GetPitch());
1711   }
1712 }
1713 FX_BOOL CFX_BitmapStorer::SetInfo(int width,
1714                                   int height,
1715                                   FXDIB_Format src_format,
1716                                   FX_DWORD* pSrcPalette) {
1717   m_pBitmap = new CFX_DIBitmap;
1718   if (!m_pBitmap->Create(width, height, src_format)) {
1719     delete m_pBitmap;
1720     m_pBitmap = NULL;
1721     return FALSE;
1722   }
1723   if (pSrcPalette) {
1724     m_pBitmap->CopyPalette(pSrcPalette);
1725   }
1726   return TRUE;
1727 }