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