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