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