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