Merge to XFA: 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             if (m_pBuffer == NULL) {
89                 return FALSE;
90             }
91         } else {
92             m_pBuffer = FX_Alloc(FX_BYTE, size);
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(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(IsCmykImage()) {
218             for (int i = 0; i < 256; i ++) {
219                 m_pPalette[i] = 0xff - i;
220             }
221         } else {
222             for (int i = 0; i < 256; i ++) {
223                 m_pPalette[i] = 0xff000000 | (i * 0x10101);
224             }
225         }
226     }
227 }
228 FX_BOOL CFX_DIBSource::BuildAlphaMask()
229 {
230     if (m_pAlphaMask) {
231         return TRUE;
232     }
233     m_pAlphaMask = FX_NEW CFX_DIBitmap;
234     if (!m_pAlphaMask) {
235         return FALSE;
236     }
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 (pal_size > size) {
535             pal_size = size;
536         }
537         FXSYS_memcpy32(m_pPalette, pSrc, pal_size * sizeof(FX_DWORD));
538     }
539 }
540 void CFX_DIBSource::GetPalette(FX_DWORD* pal, int alpha) const
541 {
542     ASSERT(GetBPP() <= 8 && !IsCmykImage());
543     if (GetBPP() == 1) {
544         pal[0] = ((m_pPalette ? m_pPalette[0] : 0xff000000) & 0xffffff) | (alpha << 24);
545         pal[1] = ((m_pPalette ? m_pPalette[1] : 0xffffffff) & 0xffffff) | (alpha << 24);
546         return;
547     }
548     if (m_pPalette) {
549         for (int i = 0; i < 256; i ++) {
550             pal[i] = (m_pPalette[i] & 0x00ffffff) | (alpha << 24);
551         }
552     } else {
553         for (int i = 0; i < 256; i ++) {
554             pal[i] = (i * 0x10101) | (alpha << 24);
555         }
556     }
557 }
558 CFX_DIBitmap* CFX_DIBSource::GetAlphaMask(const FX_RECT* pClip) const
559 {
560     ASSERT(GetFormat() == FXDIB_Argb);
561     FX_RECT rect(0, 0, m_Width, m_Height);
562     if (pClip) {
563         rect.Intersect(*pClip);
564         if (rect.IsEmpty()) {
565             return NULL;
566         }
567     }
568     CFX_DIBitmap* pMask = FX_NEW CFX_DIBitmap;
569     if (!pMask) {
570         return NULL;
571     }
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 = FX_NEW CFX_DIBitmap;
897                 if (!pMask) {
898                     return FALSE;
899                 }
900                 if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
901                     delete pMask;
902                     return FALSE;
903                 }
904                 FXSYS_memset8(pMask->GetBuffer(), gray[0], pMask->GetPitch() * m_Height);
905                 for (int row = 0; row < m_Height; row ++) {
906                     FX_LPBYTE src_pos = m_pBuffer + row * m_Pitch;
907                     FX_LPBYTE dest_pos = (FX_LPBYTE)pMask->GetScanline(row);
908                     for (int col = 0; col < m_Width; col ++) {
909                         if (src_pos[col / 8] & (1 << (7 - col % 8))) {
910                             *dest_pos = gray[1];
911                         }
912                         dest_pos ++;
913                     }
914                 }
915                 TakeOver(pMask);
916                 delete pMask;
917                 break;
918             }
919         case FXDIB_8bppRgb: {
920                 if (m_pPalette == NULL) {
921                     return FALSE;
922                 }
923                 FX_BYTE gray[256];
924                 for (int i = 0; i < 256; i ++) {
925                     int r = (FX_BYTE)(m_pPalette[i] >> 16);
926                     int g = (FX_BYTE)(m_pPalette[i] >> 8);
927                     int b = (FX_BYTE)m_pPalette[i];
928                     gray[i] = (FX_BYTE)FXRGB2GRAY(r, g, b);
929                 }
930                 CFX_DIBitmap* pMask = FX_NEW CFX_DIBitmap;
931                 if (!pMask) {
932                     return FALSE;
933                 }
934                 if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
935                     delete pMask;
936                     return FALSE;
937                 }
938                 for (int row = 0; row < m_Height; row ++) {
939                     FX_LPBYTE dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
940                     FX_LPBYTE src_pos = m_pBuffer + row * m_Pitch;
941                     for (int col = 0; col < m_Width; col ++) {
942                         *dest_pos ++ = gray[*src_pos ++];
943                     }
944                 }
945                 TakeOver(pMask);
946                 delete pMask;
947                 break;
948             }
949         case FXDIB_Rgb: {
950                 CFX_DIBitmap* pMask = FX_NEW CFX_DIBitmap;
951                 if (!pMask) {
952                     return FALSE;
953                 }
954                 if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
955                     delete pMask;
956                     return FALSE;
957                 }
958                 for (int row = 0; row < m_Height; row ++) {
959                     FX_LPBYTE src_pos = m_pBuffer + row * m_Pitch;
960                     FX_LPBYTE dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
961                     for (int col = 0; col < m_Width; col ++) {
962                         *dest_pos ++ = FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos);
963                         src_pos += 3;
964                     }
965                 }
966                 TakeOver(pMask);
967                 delete pMask;
968                 break;
969             }
970         case FXDIB_Rgb32: {
971                 CFX_DIBitmap* pMask = FX_NEW CFX_DIBitmap;
972                 if (!pMask) {
973                     return FALSE;
974                 }
975                 if (!pMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
976                     delete pMask;
977                     return FALSE;
978                 }
979                 for (int row = 0; row < m_Height; row ++) {
980                     FX_LPBYTE src_pos = m_pBuffer + row * m_Pitch;
981                     FX_LPBYTE dest_pos = pMask->GetBuffer() + row * pMask->GetPitch();
982                     for (int col = 0; col < m_Width; col ++) {
983                         *dest_pos ++ = FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos);
984                         src_pos += 4;
985                     }
986                 }
987                 TakeOver(pMask);
988                 delete pMask;
989                 break;
990             }
991         default:
992             return FALSE;
993     }
994     return TRUE;
995 }
996 FX_BOOL CFX_DIBitmap::MultiplyAlpha(int alpha)
997 {
998     if (m_pBuffer == NULL) {
999         return FALSE;
1000     }
1001     switch (GetFormat()) {
1002         case FXDIB_1bppMask:
1003             if (!ConvertFormat(FXDIB_8bppMask)) {
1004                 return FALSE;
1005             }
1006             MultiplyAlpha(alpha);
1007             break;
1008         case FXDIB_8bppMask: {
1009                 for (int row = 0; row < m_Height; row ++) {
1010                     FX_LPBYTE scan_line = m_pBuffer + row * m_Pitch;
1011                     for (int col = 0; col < m_Width; col ++) {
1012                         scan_line[col] = scan_line[col] * alpha / 255;
1013                     }
1014                 }
1015                 break;
1016             }
1017         case FXDIB_Argb: {
1018                 for (int row = 0; row < m_Height; row ++) {
1019                     FX_LPBYTE scan_line = m_pBuffer + row * m_Pitch + 3;
1020                     for (int col = 0; col < m_Width; col ++) {
1021                         *scan_line = (*scan_line) * alpha / 255;
1022                         scan_line += 4;
1023                     }
1024                 }
1025                 break;
1026             }
1027         default:
1028             if (HasAlpha()) {
1029                 m_pAlphaMask->MultiplyAlpha(alpha);
1030             } else if (IsCmykImage()) {
1031                 if (!ConvertFormat((FXDIB_Format)(GetFormat() | 0x0200))) {
1032                     return FALSE;
1033                 }
1034                 m_pAlphaMask->MultiplyAlpha(alpha);
1035             } else {
1036                 if (!ConvertFormat(FXDIB_Argb)) {
1037                     return FALSE;
1038                 }
1039                 MultiplyAlpha(alpha);
1040             }
1041             break;
1042     }
1043     return TRUE;
1044 }
1045 FX_DWORD CFX_DIBitmap::GetPixel(int x, int y) const
1046 {
1047     if (m_pBuffer == NULL) {
1048         return 0;
1049     }
1050     FX_LPBYTE pos = m_pBuffer + y * m_Pitch + x * GetBPP() / 8;
1051     switch (GetFormat()) {
1052         case FXDIB_1bppMask: {
1053                 if ((*pos) & (1 << (7 - x % 8))) {
1054                     return 0xff000000;
1055                 }
1056                 return 0;
1057             }
1058         case FXDIB_1bppRgb: {
1059                 if ((*pos) & (1 << (7 - x % 8))) {
1060                     return m_pPalette ? m_pPalette[1] : 0xffffffff;
1061                 } else {
1062                     return m_pPalette ? m_pPalette[0] : 0xff000000;
1063                 }
1064                 break;
1065             }
1066         case FXDIB_8bppMask:
1067             return (*pos) << 24;
1068         case FXDIB_8bppRgb:
1069             return m_pPalette ? m_pPalette[*pos] : (0xff000000 | ((*pos) * 0x10101));
1070         case FXDIB_Rgb:
1071         case FXDIB_Rgba:
1072         case FXDIB_Rgb32:
1073             return FXARGB_GETDIB(pos) | 0xff000000;
1074         case FXDIB_Argb:
1075             return FXARGB_GETDIB(pos);
1076         default:
1077             break;
1078     }
1079     return 0;
1080 }
1081 void CFX_DIBitmap::SetPixel(int x, int y, FX_DWORD color)
1082 {
1083     if (m_pBuffer == NULL) {
1084         return;
1085     }
1086     if (x < 0 || x >= m_Width || y < 0 || y >= m_Height) {
1087         return;
1088     }
1089     FX_LPBYTE pos = m_pBuffer + y * m_Pitch + x * GetBPP() / 8;
1090     switch (GetFormat()) {
1091         case FXDIB_1bppMask:
1092             if (color >> 24) {
1093                 *pos |= 1 << (7 - x % 8);
1094             } else {
1095                 *pos &= ~(1 << (7 - x % 8));
1096             }
1097             break;
1098         case FXDIB_1bppRgb:
1099             if (m_pPalette) {
1100                 if (color == m_pPalette[1]) {
1101                     *pos |= 1 << (7 - x % 8);
1102                 } else {
1103                     *pos &= ~(1 << (7 - x % 8));
1104                 }
1105             } else {
1106                 if (color == 0xffffffff) {
1107                     *pos |= 1 << (7 - x % 8);
1108                 } else {
1109                     *pos &= ~(1 << (7 - x % 8));
1110                 }
1111             }
1112             break;
1113         case FXDIB_8bppMask:
1114             *pos = (FX_BYTE)(color >> 24);
1115             break;
1116         case FXDIB_8bppRgb: {
1117                 if (m_pPalette) {
1118                     for (int i = 0; i < 256; i ++) {
1119                         if (m_pPalette[i] == color) {
1120                             *pos = (FX_BYTE)i;
1121                             return;
1122                         }
1123                     }
1124                     *pos = 0;
1125                 } else {
1126                     *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
1127                 }
1128                 break;
1129             }
1130         case FXDIB_Rgb:
1131         case FXDIB_Rgb32: {
1132                 int alpha = FXARGB_A(color);
1133                 pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255;
1134                 pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255;
1135                 pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255;
1136                 break;
1137             }
1138         case FXDIB_Rgba: {
1139                 pos[0] = FXARGB_B(color);
1140                 pos[1] = FXARGB_G(color);
1141                 pos[2] = FXARGB_R(color);
1142                 break;
1143             }
1144         case FXDIB_Argb:
1145             FXARGB_SETDIB(pos, color);
1146             break;
1147         default:
1148             break;
1149     }
1150 }
1151 void CFX_DIBitmap::DownSampleScanline(int line, FX_LPBYTE dest_scan, int dest_bpp,
1152                                       int dest_width, FX_BOOL bFlipX, int clip_left, int clip_width) const
1153 {
1154     if (m_pBuffer == NULL) {
1155         return;
1156     }
1157     int src_Bpp = m_bpp / 8;
1158     FX_LPBYTE scanline = m_pBuffer + line * m_Pitch;
1159     if (src_Bpp == 0) {
1160         for (int i = 0; i < clip_width; i ++) {
1161             FX_DWORD dest_x = clip_left + i;
1162             FX_DWORD src_x = dest_x * m_Width / dest_width;
1163             if (bFlipX) {
1164                 src_x = m_Width - src_x - 1;
1165             }
1166             src_x %= m_Width;
1167             dest_scan[i] = (scanline[src_x / 8] & (1 << (7 - src_x % 8))) ? 255 : 0;
1168         }
1169     } else if (src_Bpp == 1) {
1170         for (int i = 0; i < clip_width; i ++) {
1171             FX_DWORD dest_x = clip_left + i;
1172             FX_DWORD src_x = dest_x * m_Width / dest_width;
1173             if (bFlipX) {
1174                 src_x = m_Width - src_x - 1;
1175             }
1176             src_x %= m_Width;
1177             int dest_pos = i;
1178             if (m_pPalette) {
1179                 if (!IsCmykImage()) {
1180                     dest_pos *= 3;
1181                     FX_ARGB argb = m_pPalette[scanline[src_x]];
1182                     dest_scan[dest_pos] = FXARGB_B(argb);
1183                     dest_scan[dest_pos + 1] = FXARGB_G(argb);
1184                     dest_scan[dest_pos + 2] = FXARGB_R(argb);
1185                 } else {
1186                     dest_pos *= 4;
1187                     FX_CMYK cmyk = m_pPalette[scanline[src_x]];
1188                     dest_scan[dest_pos] = FXSYS_GetCValue(cmyk);
1189                     dest_scan[dest_pos + 1] = FXSYS_GetMValue(cmyk);
1190                     dest_scan[dest_pos + 2] = FXSYS_GetYValue(cmyk);
1191                     dest_scan[dest_pos + 3] = FXSYS_GetKValue(cmyk);
1192                 }
1193             } else {
1194                 dest_scan[dest_pos] = scanline[src_x];
1195             }
1196         }
1197     } else {
1198         for (int i = 0; i < clip_width; i ++) {
1199             FX_DWORD dest_x = clip_left + i;
1200             FX_DWORD src_x = bFlipX ? (m_Width - dest_x * m_Width / dest_width - 1) * src_Bpp : (dest_x * m_Width / dest_width) * src_Bpp;
1201             src_x %= m_Width * src_Bpp;
1202             int dest_pos = i * src_Bpp;
1203             for (int b = 0; b < src_Bpp; b ++) {
1204                 dest_scan[dest_pos + b] = scanline[src_x + b];
1205             }
1206         }
1207     }
1208 }
1209 FX_BOOL CFX_DIBitmap::ConvertColorScale(FX_DWORD forecolor, FX_DWORD backcolor)
1210 {
1211     ASSERT(!IsAlphaMask());
1212     if (m_pBuffer == NULL || IsAlphaMask()) {
1213         return FALSE;
1214     }
1215     int fc, fm, fy, fk, bc, bm, by, bk;
1216     int fr, fg, fb, br, bg, bb;
1217     FX_BOOL isCmykImage = IsCmykImage();
1218     if (isCmykImage) {
1219         fc = FXSYS_GetCValue(forecolor);
1220         fm = FXSYS_GetMValue(forecolor);
1221         fy = FXSYS_GetYValue(forecolor);
1222         fk = FXSYS_GetKValue(forecolor);
1223         bc = FXSYS_GetCValue(backcolor);
1224         bm = FXSYS_GetMValue(backcolor);
1225         by = FXSYS_GetYValue(backcolor);
1226         bk = FXSYS_GetKValue(backcolor);
1227     } else {
1228         fr = FXSYS_GetRValue(forecolor);
1229         fg = FXSYS_GetGValue(forecolor);
1230         fb = FXSYS_GetBValue(forecolor);
1231         br = FXSYS_GetRValue(backcolor);
1232         bg = FXSYS_GetGValue(backcolor);
1233         bb = FXSYS_GetBValue(backcolor);
1234     }
1235     if (m_bpp <= 8) {
1236         if (isCmykImage) {
1237             if (forecolor == 0xff && backcolor == 0 && m_pPalette == NULL) {
1238                 return TRUE;
1239             }
1240         } else if (forecolor == 0 && backcolor == 0xffffff && m_pPalette == NULL) {
1241             return TRUE;
1242         }
1243         if (m_pPalette == NULL) {
1244             BuildPalette();
1245         }
1246         int size = 1 << m_bpp;
1247         if (isCmykImage) {
1248             for (int i = 0; i < size; i ++) {
1249                 FX_BYTE b, g, r;
1250                 AdobeCMYK_to_sRGB1(FXSYS_GetCValue(m_pPalette[i]), FXSYS_GetMValue(m_pPalette[i]), FXSYS_GetYValue(m_pPalette[i]), FXSYS_GetKValue(m_pPalette[i]),
1251                                    r, g, b);
1252                 int gray = 255 - FXRGB2GRAY(r, g, b);
1253                 m_pPalette[i] = CmykEncode(bc + (fc - bc) * gray / 255, bm + (fm - bm) * gray / 255,
1254                                            by + (fy - by) * gray / 255, bk + (fk - bk) * gray / 255);
1255             }
1256         } else
1257             for (int i = 0; i < size; i ++) {
1258                 int gray = FXRGB2GRAY(FXARGB_R(m_pPalette[i]), FXARGB_G(m_pPalette[i]), FXARGB_B(m_pPalette[i]));
1259                 m_pPalette[i] = FXARGB_MAKE(0xff, br + (fr - br) * gray / 255, bg + (fg - bg) * gray / 255,
1260                                             bb + (fb - bb) * gray / 255);
1261             }
1262         return TRUE;
1263     }
1264     if (isCmykImage) {
1265         if (forecolor == 0xff && backcolor == 0x00) {
1266             for (int row = 0; row < m_Height; row ++) {
1267                 FX_LPBYTE scanline = m_pBuffer + row * m_Pitch;
1268                 for (int col = 0; col < m_Width; col ++) {
1269                     FX_BYTE b, g, r;
1270                     AdobeCMYK_to_sRGB1(scanline[0], scanline[1], scanline[2], scanline[3],
1271                                        r, g, b);
1272                     *scanline ++ = 0;
1273                     *scanline ++ = 0;
1274                     *scanline ++ = 0;
1275                     *scanline ++ = 255 - FXRGB2GRAY(r, g, b);
1276                 }
1277             }
1278             return TRUE;
1279         }
1280     } else if (forecolor == 0 && backcolor == 0xffffff) {
1281         for (int row = 0; row < m_Height; row ++) {
1282             FX_LPBYTE scanline = m_pBuffer + row * m_Pitch;
1283             int gap = m_bpp / 8 - 2;
1284             for (int col = 0; col < m_Width; col ++) {
1285                 int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
1286                 *scanline ++ = gray;
1287                 *scanline ++ = gray;
1288                 *scanline    = gray;
1289                 scanline += gap;
1290             }
1291         }
1292         return TRUE;
1293     }
1294     if (isCmykImage) {
1295         for (int row = 0; row < m_Height; row ++) {
1296             FX_LPBYTE scanline = m_pBuffer + row * m_Pitch;
1297             for (int col = 0; col < m_Width; col ++) {
1298                 FX_BYTE b, g, r;
1299                 AdobeCMYK_to_sRGB1(scanline[0], scanline[1], scanline[2], scanline[3],
1300                                    r, g, b);
1301                 int gray = 255 - FXRGB2GRAY(r, g, b);
1302                 *scanline ++ = bc + (fc - bc) * gray / 255;
1303                 *scanline ++ = bm + (fm - bm) * gray / 255;
1304                 *scanline ++ = by + (fy - by) * gray / 255;
1305                 *scanline ++ = bk + (fk - bk) * gray / 255;
1306             }
1307         }
1308     } else {
1309         for (int row = 0; row < m_Height; row ++) {
1310             FX_LPBYTE scanline = m_pBuffer + row * m_Pitch;
1311             int gap = m_bpp / 8 - 2;
1312             for (int col = 0; col < m_Width; col ++) {
1313                 int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
1314                 *scanline ++ = bb + (fb - bb) * gray / 255;
1315                 *scanline ++ = bg + (fg - bg) * gray / 255;
1316                 *scanline    = br + (fr - br) * gray / 255;
1317                 scanline += gap;
1318             }
1319         }
1320     }
1321     return TRUE;
1322 }
1323 FX_BOOL CFX_DIBitmap::DitherFS(const FX_DWORD* pPalette, int pal_size, const FX_RECT* pRect)
1324 {
1325     if (m_pBuffer == NULL) {
1326         return FALSE;
1327     }
1328     if (m_bpp != 8 && m_pPalette != NULL && m_AlphaFlag != 0) {
1329         return FALSE;
1330     }
1331     if (m_Width < 4 && m_Height < 4) {
1332         return FALSE;
1333     }
1334     FX_RECT rect(0, 0, m_Width, m_Height);
1335     if (pRect) {
1336         rect.Intersect(*pRect);
1337     }
1338     FX_BYTE translate[256];
1339     for (int i = 0; i < 256; i ++) {
1340         int err2 = 65536;
1341         for (int j = 0; j < pal_size; j ++) {
1342             FX_BYTE entry = (FX_BYTE)pPalette[j];
1343             int err = (int)entry - i;
1344             if (err * err < err2) {
1345                 err2 = err * err;
1346                 translate[i] = entry;
1347             }
1348         }
1349     }
1350     for (int row = rect.top; row < rect.bottom; row ++) {
1351         FX_LPBYTE scan = m_pBuffer + row * m_Pitch;
1352         FX_LPBYTE next_scan = m_pBuffer + (row + 1) * m_Pitch;
1353         for (int col = rect.left; col < rect.right; col ++) {
1354             int src_pixel = scan[col];
1355             int dest_pixel = translate[src_pixel];
1356             scan[col] = (FX_BYTE)dest_pixel;
1357             int error = -dest_pixel + src_pixel;
1358             if (col < rect.right - 1) {
1359                 int src = scan[col + 1];
1360                 src += error * 7 / 16;
1361                 if (src > 255) {
1362                     scan[col + 1] = 255;
1363                 } else if (src < 0) {
1364                     scan[col + 1] = 0;
1365                 } else {
1366                     scan[col + 1] = src;
1367                 }
1368             }
1369             if (col < rect.right - 1 && row < rect.bottom - 1) {
1370                 int src = next_scan[col + 1];
1371                 src += error * 1 / 16;
1372                 if (src > 255) {
1373                     next_scan[col + 1] = 255;
1374                 } else if (src < 0) {
1375                     next_scan[col + 1] = 0;
1376                 } else {
1377                     next_scan[col + 1] = src;
1378                 }
1379             }
1380             if (row < rect.bottom - 1) {
1381                 int src = next_scan[col];
1382                 src += error * 5 / 16;
1383                 if (src > 255) {
1384                     next_scan[col] = 255;
1385                 } else if (src < 0) {
1386                     next_scan[col] = 0;
1387                 } else {
1388                     next_scan[col] = src;
1389                 }
1390             }
1391             if (col > rect.left && row < rect.bottom - 1) {
1392                 int src = next_scan[col - 1];
1393                 src += error * 3 / 16;
1394                 if (src > 255) {
1395                     next_scan[col - 1] = 255;
1396                 } else if (src < 0) {
1397                     next_scan[col - 1] = 0;
1398                 } else {
1399                     next_scan[col - 1] = src;
1400                 }
1401             }
1402         }
1403     }
1404     return TRUE;
1405 }
1406 CFX_DIBitmap* CFX_DIBSource::FlipImage(FX_BOOL bXFlip, FX_BOOL bYFlip) const
1407 {
1408     CFX_DIBitmap* pFlipped = FX_NEW CFX_DIBitmap;
1409     if (!pFlipped) {
1410         return NULL;
1411     }
1412     if (!pFlipped->Create(m_Width, m_Height, GetFormat())) {
1413         delete pFlipped;
1414         return NULL;
1415     }
1416     pFlipped->CopyPalette(m_pPalette);
1417     FX_LPBYTE pDestBuffer = pFlipped->GetBuffer();
1418     int Bpp = m_bpp / 8;
1419     for (int row = 0; row < m_Height; row ++) {
1420         FX_LPCBYTE src_scan = GetScanline(row);
1421         FX_LPBYTE dest_scan = pDestBuffer + m_Pitch * (bYFlip ? (m_Height - row - 1) : row);
1422         if (!bXFlip) {
1423             FXSYS_memcpy32(dest_scan, src_scan, m_Pitch);
1424             continue;
1425         }
1426         if (m_bpp == 1) {
1427             FXSYS_memset32(dest_scan, 0, m_Pitch);
1428             for (int col = 0; col < m_Width; col ++)
1429                 if (src_scan[col / 8] & (1 << (7 - col % 8))) {
1430                     int dest_col = m_Width - col - 1;
1431                     dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8));
1432                 }
1433         } else {
1434             dest_scan += (m_Width - 1) * Bpp;
1435             if (Bpp == 1) {
1436                 for (int col = 0; col < m_Width; col ++) {
1437                     *dest_scan = *src_scan;
1438                     dest_scan --;
1439                     src_scan ++;
1440                 }
1441             } else if (Bpp == 3) {
1442                 for (int col = 0; col < m_Width; col ++) {
1443                     dest_scan[0] = src_scan[0];
1444                     dest_scan[1] = src_scan[1];
1445                     dest_scan[2] = src_scan[2];
1446                     dest_scan -= 3;
1447                     src_scan += 3;
1448                 }
1449             } else {
1450                 ASSERT(Bpp == 4);
1451                 for (int col = 0; col < m_Width; col ++) {
1452                     *(FX_DWORD*)dest_scan = *(FX_DWORD*)src_scan;
1453                     dest_scan -= 4;
1454                     src_scan += 4;
1455                 }
1456             }
1457         }
1458     }
1459     if (m_pAlphaMask) {
1460         pDestBuffer = pFlipped->m_pAlphaMask->GetBuffer();
1461         FX_DWORD dest_pitch = pFlipped->m_pAlphaMask->GetPitch();
1462         for (int row = 0; row < m_Height; row ++) {
1463             FX_LPCBYTE src_scan = m_pAlphaMask->GetScanline(row);
1464             FX_LPBYTE dest_scan = pDestBuffer + dest_pitch * (bYFlip ? (m_Height - row - 1) : row);
1465             if (!bXFlip) {
1466                 FXSYS_memcpy32(dest_scan, src_scan, dest_pitch);
1467                 continue;
1468             }
1469             dest_scan += (m_Width - 1);
1470             for (int col = 0; col < m_Width; col ++) {
1471                 *dest_scan = *src_scan;
1472                 dest_scan --;
1473                 src_scan ++;
1474             }
1475         }
1476     }
1477     return pFlipped;
1478 }
1479 CFX_DIBExtractor::CFX_DIBExtractor(const CFX_DIBSource* pSrc)
1480 {
1481     m_pBitmap = NULL;
1482     if (pSrc->GetBuffer() == NULL) {
1483         m_pBitmap = pSrc->Clone();
1484     } else {
1485         m_pBitmap = FX_NEW CFX_DIBitmap;
1486         if (!m_pBitmap) {
1487             return;
1488         }
1489         if (!m_pBitmap->Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat(), pSrc->GetBuffer())) {
1490             delete m_pBitmap;
1491             m_pBitmap = NULL;
1492             return;
1493         }
1494         m_pBitmap->CopyPalette(pSrc->GetPalette());
1495         m_pBitmap->CopyAlphaMask(pSrc->m_pAlphaMask);
1496     }
1497 }
1498 CFX_DIBExtractor::~CFX_DIBExtractor()
1499 {
1500     if (m_pBitmap) {
1501         delete m_pBitmap;
1502     }
1503 }
1504 CFX_FilteredDIB::CFX_FilteredDIB()
1505 {
1506     m_pScanline = NULL;
1507     m_pSrc = NULL;
1508 }
1509 CFX_FilteredDIB::~CFX_FilteredDIB()
1510 {
1511     if (m_pSrc && m_bAutoDropSrc) {
1512         delete m_pSrc;
1513     }
1514     if (m_pScanline) {
1515         FX_Free(m_pScanline);
1516     }
1517 }
1518 void CFX_FilteredDIB::LoadSrc(const CFX_DIBSource* pSrc, FX_BOOL bAutoDropSrc)
1519 {
1520     m_pSrc = pSrc;
1521     m_bAutoDropSrc = bAutoDropSrc;
1522     m_Width = pSrc->GetWidth();
1523     m_Height = pSrc->GetHeight();
1524     FXDIB_Format format = GetDestFormat();
1525     m_bpp = (FX_BYTE)format;
1526     m_AlphaFlag = (FX_BYTE)(format >> 8);
1527     m_Pitch = (m_Width * (format & 0xff) + 31) / 32 * 4;
1528     m_pPalette = GetDestPalette();
1529     m_pScanline = FX_Alloc(FX_BYTE, m_Pitch);
1530 }
1531 FX_LPCBYTE CFX_FilteredDIB::GetScanline(int line) const
1532 {
1533     TranslateScanline(m_pScanline, m_pSrc->GetScanline(line));
1534     return m_pScanline;
1535 }
1536 void CFX_FilteredDIB::DownSampleScanline(int line, FX_LPBYTE dest_scan, int dest_bpp,
1537         int dest_width, FX_BOOL bFlipX, int clip_left, int clip_width) const
1538 {
1539     m_pSrc->DownSampleScanline(line, dest_scan, dest_bpp, dest_width, bFlipX, clip_left, clip_width);
1540     TranslateDownSamples(dest_scan, dest_scan, clip_width, dest_bpp);
1541 }
1542 CFX_ImageRenderer::CFX_ImageRenderer()
1543 {
1544     m_Status = 0;
1545     m_pTransformer = NULL;
1546     m_bRgbByteOrder = FALSE;
1547     m_BlendType = FXDIB_BLEND_NORMAL;
1548 }
1549 CFX_ImageRenderer::~CFX_ImageRenderer()
1550 {
1551     if (m_pTransformer) {
1552         delete m_pTransformer;
1553     }
1554 }
1555 extern FX_RECT _FXDIB_SwapClipBox(FX_RECT& clip, int width, int height, FX_BOOL bFlipX, FX_BOOL bFlipY);
1556 FX_BOOL CFX_ImageRenderer::Start(CFX_DIBitmap* pDevice, const CFX_ClipRgn* pClipRgn,
1557                                  const CFX_DIBSource* pSource, int bitmap_alpha,
1558                                  FX_DWORD mask_color, const CFX_AffineMatrix* pMatrix,
1559                                  FX_DWORD dib_flags, FX_BOOL bRgbByteOrder,
1560                                  int alpha_flag, void* pIccTransform, int blend_type)
1561 {
1562     m_Matrix = *pMatrix;
1563     CFX_FloatRect image_rect_f = m_Matrix.GetUnitRect();
1564     FX_RECT image_rect = image_rect_f.GetOutterRect();
1565     m_ClipBox = pClipRgn ? pClipRgn->GetBox() : FX_RECT(0, 0, pDevice->GetWidth(), pDevice->GetHeight());
1566     m_ClipBox.Intersect(image_rect);
1567     if (m_ClipBox.IsEmpty()) {
1568         return FALSE;
1569     }
1570     m_pDevice = pDevice;
1571     m_pClipRgn = pClipRgn;
1572     m_MaskColor = mask_color;
1573     m_BitmapAlpha = bitmap_alpha;
1574     m_Matrix = *pMatrix;
1575     m_Flags = dib_flags;
1576     m_AlphaFlag = alpha_flag;
1577     m_pIccTransform = pIccTransform;
1578     m_bRgbByteOrder = bRgbByteOrder;
1579     m_BlendType = blend_type;
1580     FX_BOOL ret = TRUE;
1581     if ((FXSYS_fabs(m_Matrix.b) >= 0.5f || m_Matrix.a == 0) ||
1582             (FXSYS_fabs(m_Matrix.c) >= 0.5f || m_Matrix.d == 0) ) {
1583         if (FXSYS_fabs(m_Matrix.a) < FXSYS_fabs(m_Matrix.b) / 20 && FXSYS_fabs(m_Matrix.d) < FXSYS_fabs(m_Matrix.c) / 20 &&
1584                 FXSYS_fabs(m_Matrix.a) < 0.5f && FXSYS_fabs(m_Matrix.d) < 0.5f) {
1585             int dest_width = image_rect.Width();
1586             int dest_height = image_rect.Height();
1587             FX_RECT bitmap_clip = m_ClipBox;
1588             bitmap_clip.Offset(-image_rect.left, -image_rect.top);
1589             bitmap_clip = _FXDIB_SwapClipBox(bitmap_clip, dest_width, dest_height, m_Matrix.c > 0, m_Matrix.b < 0);
1590             m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color, m_ClipBox, TRUE,
1591                                m_Matrix.c > 0, m_Matrix.b < 0, m_bRgbByteOrder, alpha_flag, pIccTransform, m_BlendType);
1592             if (!m_Stretcher.Start(&m_Composer, pSource, dest_height, dest_width, bitmap_clip, dib_flags)) {
1593                 return FALSE;
1594             }
1595             m_Status = 1;
1596             return TRUE;
1597         }
1598         m_Status = 2;
1599         m_pTransformer = FX_NEW CFX_ImageTransformer;
1600         if (!m_pTransformer) {
1601             return FALSE;
1602         }
1603         m_pTransformer->Start(pSource, &m_Matrix, dib_flags, &m_ClipBox);
1604         return TRUE;
1605     }
1606     int dest_width = image_rect.Width();
1607     if (m_Matrix.a < 0) {
1608         dest_width = -dest_width;
1609     }
1610     int dest_height = image_rect.Height();
1611     if (m_Matrix.d > 0) {
1612         dest_height = -dest_height;
1613     }
1614     if (dest_width == 0 || dest_height == 0) {
1615         return FALSE;
1616     }
1617     FX_RECT bitmap_clip = m_ClipBox;
1618     bitmap_clip.Offset(-image_rect.left, -image_rect.top);
1619     m_Composer.Compose(pDevice, pClipRgn, bitmap_alpha, mask_color,
1620                        m_ClipBox, FALSE, FALSE, FALSE, m_bRgbByteOrder, alpha_flag, pIccTransform, m_BlendType);
1621     m_Status = 1;
1622     ret = m_Stretcher.Start(&m_Composer, pSource, dest_width, dest_height, bitmap_clip, dib_flags);
1623     return ret;
1624 }
1625 FX_BOOL CFX_ImageRenderer::Continue(IFX_Pause* pPause)
1626 {
1627     if (m_Status == 1) {
1628         return m_Stretcher.Continue(pPause);
1629     } else if (m_Status == 2) {
1630         if (m_pTransformer->Continue(pPause)) {
1631             return TRUE;
1632         }
1633         CFX_DIBitmap* pBitmap = m_pTransformer->m_Storer.Detach();
1634         if (pBitmap == NULL) {
1635             return FALSE;
1636         }
1637         if (pBitmap->GetBuffer() == NULL) {
1638             delete pBitmap;
1639             return FALSE;
1640         }
1641         if (pBitmap->IsAlphaMask()) {
1642             if (m_BitmapAlpha != 255) {
1643                 if (m_AlphaFlag >> 8) {
1644                     m_AlphaFlag = (((FX_BYTE)((m_AlphaFlag & 0xff) * m_BitmapAlpha / 255)) | ((m_AlphaFlag >> 8) << 8));
1645                 } else {
1646                     m_MaskColor = FXARGB_MUL_ALPHA(m_MaskColor, m_BitmapAlpha);
1647                 }
1648             }
1649             m_pDevice->CompositeMask(m_pTransformer->m_ResultLeft, m_pTransformer->m_ResultTop,
1650                                      pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap, m_MaskColor,
1651                                      0, 0, m_BlendType, m_pClipRgn, m_bRgbByteOrder, m_AlphaFlag, m_pIccTransform);
1652         } else {
1653             if (m_BitmapAlpha != 255) {
1654                 pBitmap->MultiplyAlpha(m_BitmapAlpha);
1655             }
1656             m_pDevice->CompositeBitmap(m_pTransformer->m_ResultLeft, m_pTransformer->m_ResultTop,
1657                                        pBitmap->GetWidth(), pBitmap->GetHeight(), pBitmap, 0, 0, m_BlendType, m_pClipRgn, m_bRgbByteOrder, m_pIccTransform);
1658         }
1659         delete pBitmap;
1660         return FALSE;
1661     }
1662     return FALSE;
1663 }
1664 CFX_BitmapStorer::CFX_BitmapStorer()
1665 {
1666     m_pBitmap = NULL;
1667 }
1668 CFX_BitmapStorer::~CFX_BitmapStorer()
1669 {
1670     if (m_pBitmap) {
1671         delete m_pBitmap;
1672     }
1673 }
1674 CFX_DIBitmap* CFX_BitmapStorer::Detach()
1675 {
1676     CFX_DIBitmap* pBitmap = m_pBitmap;
1677     m_pBitmap = NULL;
1678     return pBitmap;
1679 }
1680 void CFX_BitmapStorer::Replace(CFX_DIBitmap* pBitmap)
1681 {
1682     if (m_pBitmap) {
1683         delete m_pBitmap;
1684     }
1685     m_pBitmap = pBitmap;
1686 }
1687 void CFX_BitmapStorer::ComposeScanline(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha)
1688 {
1689     FX_LPBYTE dest_buf = (FX_LPBYTE)m_pBitmap->GetScanline(line);
1690     FX_LPBYTE dest_alpha_buf = m_pBitmap->m_pAlphaMask ?
1691                                (FX_LPBYTE)m_pBitmap->m_pAlphaMask->GetScanline(line) : NULL;
1692     if (dest_buf) {
1693         FXSYS_memcpy32(dest_buf, scanline, m_pBitmap->GetPitch());
1694     }
1695     if (dest_alpha_buf) {
1696         FXSYS_memcpy32(dest_alpha_buf, scan_extra_alpha, m_pBitmap->m_pAlphaMask->GetPitch());
1697     }
1698 }
1699 FX_BOOL CFX_BitmapStorer::SetInfo(int width, int height, FXDIB_Format src_format, FX_DWORD* pSrcPalette)
1700 {
1701     m_pBitmap = FX_NEW CFX_DIBitmap;
1702     if (!m_pBitmap) {
1703         return FALSE;
1704     }
1705     if (!m_pBitmap->Create(width, height, src_format)) {
1706         delete m_pBitmap;
1707         m_pBitmap = NULL;
1708         return FALSE;
1709     }
1710     if (pSrcPalette) {
1711         m_pBitmap->CopyPalette(pSrcPalette);
1712     }
1713     return TRUE;
1714 }