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