Home | History | Annotate | Download | only in dib
      1 // Copyright 2017 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/fxge/dib/cfx_dibitmap.h"
      8 
      9 #include <limits>
     10 #include <memory>
     11 #include <utility>
     12 
     13 #include "core/fxcodec/fx_codec.h"
     14 #include "core/fxge/cfx_cliprgn.h"
     15 #include "core/fxge/dib/cfx_scanlinecompositor.h"
     16 #include "third_party/base/ptr_util.h"
     17 
     18 #define MAX_OOM_LIMIT 12000000
     19 
     20 namespace {
     21 
     22 const int8_t g_ChannelOffset[] = {0, 2, 1, 0, 0, 1, 2, 3, 3};
     23 
     24 }  // namespace
     25 
     26 CFX_DIBitmap::CFX_DIBitmap() {
     27   m_pPalette = nullptr;
     28 #ifdef _SKIA_SUPPORT_PATHS_
     29   m_nFormat = Format::kCleared;
     30 #endif
     31 }
     32 
     33 bool CFX_DIBitmap::Create(int width,
     34                           int height,
     35                           FXDIB_Format format,
     36                           uint8_t* pBuffer,
     37                           uint32_t pitch) {
     38   m_pBuffer = nullptr;
     39   m_bpp = static_cast<uint8_t>(format);
     40   m_AlphaFlag = static_cast<uint8_t>(format >> 8);
     41   m_Width = 0;
     42   m_Height = 0;
     43   m_Pitch = 0;
     44 
     45   uint32_t calculatedSize;
     46   if (!CFX_DIBitmap::CalculatePitchAndSize(height, width, format, &pitch,
     47                                            &calculatedSize))
     48     return false;
     49 
     50   if (pBuffer) {
     51     m_pBuffer.Reset(pBuffer);
     52   } else {
     53     size_t bufferSize = calculatedSize + 4;
     54     size_t oomlimit = MAX_OOM_LIMIT;
     55     if (bufferSize >= oomlimit) {
     56       m_pBuffer = std::unique_ptr<uint8_t, FxFreeDeleter>(
     57           FX_TryAlloc(uint8_t, bufferSize));
     58       if (!m_pBuffer)
     59         return false;
     60     } else {
     61       m_pBuffer = std::unique_ptr<uint8_t, FxFreeDeleter>(
     62           FX_Alloc(uint8_t, bufferSize));
     63     }
     64   }
     65   m_Width = width;
     66   m_Height = height;
     67   m_Pitch = pitch;
     68   if (!HasAlpha() || format == FXDIB_Argb)
     69     return true;
     70 
     71   if (BuildAlphaMask())
     72     return true;
     73 
     74   if (pBuffer)
     75     return true;
     76 
     77   m_pBuffer = nullptr;
     78   m_Width = 0;
     79   m_Height = 0;
     80   m_Pitch = 0;
     81   return false;
     82 }
     83 
     84 bool CFX_DIBitmap::Copy(const RetainPtr<CFX_DIBSource>& pSrc) {
     85   if (m_pBuffer)
     86     return false;
     87 
     88   if (!Create(pSrc->GetWidth(), pSrc->GetHeight(), pSrc->GetFormat()))
     89     return false;
     90 
     91   SetPalette(pSrc->GetPalette());
     92   SetAlphaMask(pSrc->m_pAlphaMask, nullptr);
     93   for (int row = 0; row < pSrc->GetHeight(); row++)
     94     memcpy(m_pBuffer.Get() + row * m_Pitch, pSrc->GetScanline(row), m_Pitch);
     95   return true;
     96 }
     97 
     98 CFX_DIBitmap::~CFX_DIBitmap() {}
     99 
    100 uint8_t* CFX_DIBitmap::GetBuffer() const {
    101   return m_pBuffer.Get();
    102 }
    103 
    104 const uint8_t* CFX_DIBitmap::GetScanline(int line) const {
    105   return m_pBuffer.Get() ? m_pBuffer.Get() + line * m_Pitch : nullptr;
    106 }
    107 
    108 void CFX_DIBitmap::TakeOver(RetainPtr<CFX_DIBitmap>&& pSrcBitmap) {
    109   m_pBuffer = std::move(pSrcBitmap->m_pBuffer);
    110   m_pPalette = std::move(pSrcBitmap->m_pPalette);
    111   m_pAlphaMask = pSrcBitmap->m_pAlphaMask;
    112   pSrcBitmap->m_pBuffer = nullptr;
    113   pSrcBitmap->m_pAlphaMask = nullptr;
    114   m_bpp = pSrcBitmap->m_bpp;
    115   m_AlphaFlag = pSrcBitmap->m_AlphaFlag;
    116   m_Width = pSrcBitmap->m_Width;
    117   m_Height = pSrcBitmap->m_Height;
    118   m_Pitch = pSrcBitmap->m_Pitch;
    119 }
    120 
    121 void CFX_DIBitmap::Clear(uint32_t color) {
    122   if (!m_pBuffer)
    123     return;
    124 
    125   uint8_t* pBuffer = m_pBuffer.Get();
    126   switch (GetFormat()) {
    127     case FXDIB_1bppMask:
    128       memset(pBuffer, (color & 0xff000000) ? 0xff : 0, m_Pitch * m_Height);
    129       break;
    130     case FXDIB_1bppRgb: {
    131       int index = FindPalette(color);
    132       memset(pBuffer, index ? 0xff : 0, m_Pitch * m_Height);
    133       break;
    134     }
    135     case FXDIB_8bppMask:
    136       memset(pBuffer, color >> 24, m_Pitch * m_Height);
    137       break;
    138     case FXDIB_8bppRgb: {
    139       int index = FindPalette(color);
    140       memset(pBuffer, index, m_Pitch * m_Height);
    141       break;
    142     }
    143     case FXDIB_Rgb:
    144     case FXDIB_Rgba: {
    145       int a;
    146       int r;
    147       int g;
    148       int b;
    149       std::tie(a, r, g, b) = ArgbDecode(color);
    150       if (r == g && g == b) {
    151         memset(pBuffer, r, m_Pitch * m_Height);
    152       } else {
    153         int byte_pos = 0;
    154         for (int col = 0; col < m_Width; col++) {
    155           pBuffer[byte_pos++] = b;
    156           pBuffer[byte_pos++] = g;
    157           pBuffer[byte_pos++] = r;
    158         }
    159         for (int row = 1; row < m_Height; row++) {
    160           memcpy(pBuffer + row * m_Pitch, pBuffer, m_Pitch);
    161         }
    162       }
    163       break;
    164     }
    165     case FXDIB_Rgb32:
    166     case FXDIB_Argb: {
    167       color = IsCmykImage() ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
    168 #ifdef _SKIA_SUPPORT_
    169       if (FXDIB_Rgb32 == GetFormat() && !IsCmykImage())
    170         color |= 0xFF000000;
    171 #endif
    172       for (int i = 0; i < m_Width; i++)
    173         reinterpret_cast<uint32_t*>(pBuffer)[i] = color;
    174       for (int row = 1; row < m_Height; row++)
    175         memcpy(pBuffer + row * m_Pitch, pBuffer, m_Pitch);
    176       break;
    177     }
    178     default:
    179       break;
    180   }
    181 }
    182 
    183 bool CFX_DIBitmap::TransferBitmap(int dest_left,
    184                                   int dest_top,
    185                                   int width,
    186                                   int height,
    187                                   const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    188                                   int src_left,
    189                                   int src_top) {
    190   if (!m_pBuffer)
    191     return false;
    192 
    193   GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(),
    194                  pSrcBitmap->GetHeight(), src_left, src_top, nullptr);
    195   if (width == 0 || height == 0)
    196     return true;
    197 
    198   FXDIB_Format dest_format = GetFormat();
    199   FXDIB_Format src_format = pSrcBitmap->GetFormat();
    200   if (dest_format == src_format) {
    201     if (GetBPP() == 1) {
    202       for (int row = 0; row < height; row++) {
    203         uint8_t* dest_scan = m_pBuffer.Get() + (dest_top + row) * m_Pitch;
    204         const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    205         for (int col = 0; col < width; col++) {
    206           if (src_scan[(src_left + col) / 8] &
    207               (1 << (7 - (src_left + col) % 8))) {
    208             dest_scan[(dest_left + col) / 8] |= 1
    209                                                 << (7 - (dest_left + col) % 8);
    210           } else {
    211             dest_scan[(dest_left + col) / 8] &=
    212                 ~(1 << (7 - (dest_left + col) % 8));
    213           }
    214         }
    215       }
    216     } else {
    217       int Bpp = GetBPP() / 8;
    218       for (int row = 0; row < height; row++) {
    219         uint8_t* dest_scan =
    220             m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * Bpp;
    221         const uint8_t* src_scan =
    222             pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
    223         memcpy(dest_scan, src_scan, width * Bpp);
    224       }
    225     }
    226   } else {
    227     if (m_pPalette)
    228       return false;
    229 
    230     if (m_bpp == 8)
    231       dest_format = FXDIB_8bppMask;
    232 
    233     uint8_t* dest_buf =
    234         m_pBuffer.Get() + dest_top * m_Pitch + dest_left * GetBPP() / 8;
    235     std::unique_ptr<uint32_t, FxFreeDeleter> d_plt;
    236     if (!ConvertBuffer(dest_format, dest_buf, m_Pitch, width, height,
    237                        pSrcBitmap, src_left, src_top, &d_plt)) {
    238       return false;
    239     }
    240   }
    241   return true;
    242 }
    243 
    244 bool CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel,
    245                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    246                                FXDIB_Channel srcChannel) {
    247   if (!m_pBuffer)
    248     return false;
    249 
    250   RetainPtr<CFX_DIBSource> pSrcClone = pSrcBitmap;
    251   int srcOffset;
    252   if (srcChannel == FXDIB_Alpha) {
    253     if (!pSrcBitmap->HasAlpha() && !pSrcBitmap->IsAlphaMask())
    254       return false;
    255 
    256     if (pSrcBitmap->GetBPP() == 1) {
    257       pSrcClone = pSrcBitmap->CloneConvert(FXDIB_8bppMask);
    258       if (!pSrcClone)
    259         return false;
    260     }
    261     srcOffset = pSrcBitmap->GetFormat() == FXDIB_Argb ? 3 : 0;
    262   } else {
    263     if (pSrcBitmap->IsAlphaMask())
    264       return false;
    265 
    266     if (pSrcBitmap->GetBPP() < 24) {
    267       if (pSrcBitmap->IsCmykImage()) {
    268         pSrcClone = pSrcBitmap->CloneConvert(static_cast<FXDIB_Format>(
    269             (pSrcBitmap->GetFormat() & 0xff00) | 0x20));
    270       } else {
    271         pSrcClone = pSrcBitmap->CloneConvert(static_cast<FXDIB_Format>(
    272             (pSrcBitmap->GetFormat() & 0xff00) | 0x18));
    273       }
    274       if (!pSrcClone)
    275         return false;
    276     }
    277     srcOffset = g_ChannelOffset[srcChannel];
    278   }
    279   int destOffset = 0;
    280   if (destChannel == FXDIB_Alpha) {
    281     if (IsAlphaMask()) {
    282       if (!ConvertFormat(FXDIB_8bppMask))
    283         return false;
    284     } else {
    285       if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb))
    286         return false;
    287 
    288       if (GetFormat() == FXDIB_Argb)
    289         destOffset = 3;
    290     }
    291   } else {
    292     if (IsAlphaMask())
    293       return false;
    294 
    295     if (GetBPP() < 24) {
    296       if (HasAlpha()) {
    297         if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb))
    298           return false;
    299 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
    300       } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) {
    301 #else
    302       } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) {
    303 #endif
    304         return false;
    305       }
    306     }
    307     destOffset = g_ChannelOffset[destChannel];
    308   }
    309   if (srcChannel == FXDIB_Alpha && pSrcClone->m_pAlphaMask) {
    310     RetainPtr<CFX_DIBSource> pAlphaMask = pSrcClone->m_pAlphaMask;
    311     if (pSrcClone->GetWidth() != m_Width ||
    312         pSrcClone->GetHeight() != m_Height) {
    313       if (pAlphaMask) {
    314         pAlphaMask = pAlphaMask->StretchTo(m_Width, m_Height, 0, nullptr);
    315         if (!pAlphaMask)
    316           return false;
    317       }
    318     }
    319     pSrcClone = std::move(pAlphaMask);
    320     srcOffset = 0;
    321   } else if (pSrcClone->GetWidth() != m_Width ||
    322              pSrcClone->GetHeight() != m_Height) {
    323     RetainPtr<CFX_DIBitmap> pSrcMatched =
    324         pSrcClone->StretchTo(m_Width, m_Height, 0, nullptr);
    325     if (!pSrcMatched)
    326       return false;
    327 
    328     pSrcClone = std::move(pSrcMatched);
    329   }
    330   RetainPtr<CFX_DIBitmap> pDst(this);
    331   if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
    332     pDst = m_pAlphaMask;
    333     destOffset = 0;
    334   }
    335   int srcBytes = pSrcClone->GetBPP() / 8;
    336   int destBytes = pDst->GetBPP() / 8;
    337   for (int row = 0; row < m_Height; row++) {
    338     uint8_t* dest_pos = (uint8_t*)pDst->GetScanline(row) + destOffset;
    339     const uint8_t* src_pos = pSrcClone->GetScanline(row) + srcOffset;
    340     for (int col = 0; col < m_Width; col++) {
    341       *dest_pos = *src_pos;
    342       dest_pos += destBytes;
    343       src_pos += srcBytes;
    344     }
    345   }
    346   return true;
    347 }
    348 
    349 bool CFX_DIBitmap::LoadChannel(FXDIB_Channel destChannel, int value) {
    350   if (!m_pBuffer)
    351     return false;
    352 
    353   int destOffset;
    354   if (destChannel == FXDIB_Alpha) {
    355     if (IsAlphaMask()) {
    356       if (!ConvertFormat(FXDIB_8bppMask)) {
    357         return false;
    358       }
    359       destOffset = 0;
    360     } else {
    361       destOffset = 0;
    362       if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
    363         return false;
    364       }
    365       if (GetFormat() == FXDIB_Argb) {
    366         destOffset = 3;
    367       }
    368     }
    369   } else {
    370     if (IsAlphaMask()) {
    371       return false;
    372     }
    373     if (GetBPP() < 24) {
    374       if (HasAlpha()) {
    375         if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyka : FXDIB_Argb)) {
    376           return false;
    377         }
    378 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
    379       } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb)) {
    380 #else
    381       } else if (!ConvertFormat(IsCmykImage() ? FXDIB_Cmyk : FXDIB_Rgb32)) {
    382 #endif
    383         return false;
    384       }
    385     }
    386     destOffset = g_ChannelOffset[destChannel];
    387   }
    388   int Bpp = GetBPP() / 8;
    389   if (Bpp == 1) {
    390     memset(m_pBuffer.Get(), value, m_Height * m_Pitch);
    391     return true;
    392   }
    393   if (destChannel == FXDIB_Alpha && m_pAlphaMask) {
    394     memset(m_pAlphaMask->GetBuffer(), value,
    395            m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch());
    396     return true;
    397   }
    398   for (int row = 0; row < m_Height; row++) {
    399     uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + destOffset;
    400     for (int col = 0; col < m_Width; col++) {
    401       *scan_line = value;
    402       scan_line += Bpp;
    403     }
    404   }
    405   return true;
    406 }
    407 
    408 bool CFX_DIBitmap::MultiplyAlpha(const RetainPtr<CFX_DIBSource>& pSrcBitmap) {
    409   if (!m_pBuffer)
    410     return false;
    411 
    412   ASSERT(pSrcBitmap->IsAlphaMask());
    413   if (!pSrcBitmap->IsAlphaMask())
    414     return false;
    415 
    416   if (!IsAlphaMask() && !HasAlpha())
    417     return LoadChannel(FXDIB_Alpha, pSrcBitmap, FXDIB_Alpha);
    418 
    419   RetainPtr<CFX_DIBitmap> pSrcClone = pSrcBitmap.As<CFX_DIBitmap>();
    420   if (pSrcBitmap->GetWidth() != m_Width ||
    421       pSrcBitmap->GetHeight() != m_Height) {
    422     pSrcClone = pSrcBitmap->StretchTo(m_Width, m_Height, 0, nullptr);
    423     if (!pSrcClone)
    424       return false;
    425   }
    426   if (IsAlphaMask()) {
    427     if (!ConvertFormat(FXDIB_8bppMask))
    428       return false;
    429 
    430     for (int row = 0; row < m_Height; row++) {
    431       uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row;
    432       uint8_t* src_scan = pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
    433       if (pSrcClone->GetBPP() == 1) {
    434         for (int col = 0; col < m_Width; col++) {
    435           if (!((1 << (7 - col % 8)) & src_scan[col / 8]))
    436             dest_scan[col] = 0;
    437         }
    438       } else {
    439         for (int col = 0; col < m_Width; col++) {
    440           *dest_scan = (*dest_scan) * src_scan[col] / 255;
    441           dest_scan++;
    442         }
    443       }
    444     }
    445   } else {
    446     if (GetFormat() == FXDIB_Argb) {
    447       if (pSrcClone->GetBPP() == 1)
    448         return false;
    449 
    450       for (int row = 0; row < m_Height; row++) {
    451         uint8_t* dest_scan = m_pBuffer.Get() + m_Pitch * row + 3;
    452         uint8_t* src_scan =
    453             pSrcClone->m_pBuffer.Get() + pSrcClone->m_Pitch * row;
    454         for (int col = 0; col < m_Width; col++) {
    455           *dest_scan = (*dest_scan) * src_scan[col] / 255;
    456           dest_scan += 4;
    457         }
    458       }
    459     } else {
    460       m_pAlphaMask->MultiplyAlpha(pSrcClone);
    461     }
    462   }
    463   return true;
    464 }
    465 
    466 bool CFX_DIBitmap::MultiplyAlpha(int alpha) {
    467   if (!m_pBuffer)
    468     return false;
    469 
    470   switch (GetFormat()) {
    471     case FXDIB_1bppMask:
    472       if (!ConvertFormat(FXDIB_8bppMask)) {
    473         return false;
    474       }
    475       MultiplyAlpha(alpha);
    476       break;
    477     case FXDIB_8bppMask: {
    478       for (int row = 0; row < m_Height; row++) {
    479         uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch;
    480         for (int col = 0; col < m_Width; col++) {
    481           scan_line[col] = scan_line[col] * alpha / 255;
    482         }
    483       }
    484       break;
    485     }
    486     case FXDIB_Argb: {
    487       for (int row = 0; row < m_Height; row++) {
    488         uint8_t* scan_line = m_pBuffer.Get() + row * m_Pitch + 3;
    489         for (int col = 0; col < m_Width; col++) {
    490           *scan_line = (*scan_line) * alpha / 255;
    491           scan_line += 4;
    492         }
    493       }
    494       break;
    495     }
    496     default:
    497       if (HasAlpha()) {
    498         m_pAlphaMask->MultiplyAlpha(alpha);
    499       } else if (IsCmykImage()) {
    500         if (!ConvertFormat((FXDIB_Format)(GetFormat() | 0x0200))) {
    501           return false;
    502         }
    503         m_pAlphaMask->MultiplyAlpha(alpha);
    504       } else {
    505         if (!ConvertFormat(FXDIB_Argb)) {
    506           return false;
    507         }
    508         MultiplyAlpha(alpha);
    509       }
    510       break;
    511   }
    512   return true;
    513 }
    514 
    515 uint32_t CFX_DIBitmap::GetPixel(int x, int y) const {
    516   if (!m_pBuffer)
    517     return 0;
    518 
    519   uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + x * GetBPP() / 8;
    520   switch (GetFormat()) {
    521     case FXDIB_1bppMask: {
    522       if ((*pos) & (1 << (7 - x % 8))) {
    523         return 0xff000000;
    524       }
    525       return 0;
    526     }
    527     case FXDIB_1bppRgb: {
    528       if ((*pos) & (1 << (7 - x % 8))) {
    529         return m_pPalette ? m_pPalette.get()[1] : 0xffffffff;
    530       }
    531       return m_pPalette ? m_pPalette.get()[0] : 0xff000000;
    532     }
    533     case FXDIB_8bppMask:
    534       return (*pos) << 24;
    535     case FXDIB_8bppRgb:
    536       return m_pPalette ? m_pPalette.get()[*pos]
    537                         : (0xff000000 | ((*pos) * 0x10101));
    538     case FXDIB_Rgb:
    539     case FXDIB_Rgba:
    540     case FXDIB_Rgb32:
    541       return FXARGB_GETDIB(pos) | 0xff000000;
    542     case FXDIB_Argb:
    543       return FXARGB_GETDIB(pos);
    544     default:
    545       break;
    546   }
    547   return 0;
    548 }
    549 
    550 void CFX_DIBitmap::SetPixel(int x, int y, uint32_t color) {
    551   if (!m_pBuffer)
    552     return;
    553 
    554   if (x < 0 || x >= m_Width || y < 0 || y >= m_Height)
    555     return;
    556 
    557   uint8_t* pos = m_pBuffer.Get() + y * m_Pitch + x * GetBPP() / 8;
    558   switch (GetFormat()) {
    559     case FXDIB_1bppMask:
    560       if (color >> 24) {
    561         *pos |= 1 << (7 - x % 8);
    562       } else {
    563         *pos &= ~(1 << (7 - x % 8));
    564       }
    565       break;
    566     case FXDIB_1bppRgb:
    567       if (m_pPalette) {
    568         if (color == m_pPalette.get()[1]) {
    569           *pos |= 1 << (7 - x % 8);
    570         } else {
    571           *pos &= ~(1 << (7 - x % 8));
    572         }
    573       } else {
    574         if (color == 0xffffffff) {
    575           *pos |= 1 << (7 - x % 8);
    576         } else {
    577           *pos &= ~(1 << (7 - x % 8));
    578         }
    579       }
    580       break;
    581     case FXDIB_8bppMask:
    582       *pos = (uint8_t)(color >> 24);
    583       break;
    584     case FXDIB_8bppRgb: {
    585       if (m_pPalette) {
    586         for (int i = 0; i < 256; i++) {
    587           if (m_pPalette.get()[i] == color) {
    588             *pos = (uint8_t)i;
    589             return;
    590           }
    591         }
    592         *pos = 0;
    593       } else {
    594         *pos = FXRGB2GRAY(FXARGB_R(color), FXARGB_G(color), FXARGB_B(color));
    595       }
    596       break;
    597     }
    598     case FXDIB_Rgb:
    599     case FXDIB_Rgb32: {
    600       int alpha = FXARGB_A(color);
    601       pos[0] = (FXARGB_B(color) * alpha + pos[0] * (255 - alpha)) / 255;
    602       pos[1] = (FXARGB_G(color) * alpha + pos[1] * (255 - alpha)) / 255;
    603       pos[2] = (FXARGB_R(color) * alpha + pos[2] * (255 - alpha)) / 255;
    604       break;
    605     }
    606     case FXDIB_Rgba: {
    607       pos[0] = FXARGB_B(color);
    608       pos[1] = FXARGB_G(color);
    609       pos[2] = FXARGB_R(color);
    610       break;
    611     }
    612     case FXDIB_Argb:
    613       FXARGB_SETDIB(pos, color);
    614       break;
    615     default:
    616       break;
    617   }
    618 }
    619 
    620 void CFX_DIBitmap::DownSampleScanline(int line,
    621                                       uint8_t* dest_scan,
    622                                       int dest_bpp,
    623                                       int dest_width,
    624                                       bool bFlipX,
    625                                       int clip_left,
    626                                       int clip_width) const {
    627   if (!m_pBuffer)
    628     return;
    629 
    630   int src_Bpp = m_bpp / 8;
    631   uint8_t* scanline = m_pBuffer.Get() + line * m_Pitch;
    632   if (src_Bpp == 0) {
    633     for (int i = 0; i < clip_width; i++) {
    634       uint32_t dest_x = clip_left + i;
    635       uint32_t src_x = dest_x * m_Width / dest_width;
    636       if (bFlipX) {
    637         src_x = m_Width - src_x - 1;
    638       }
    639       src_x %= m_Width;
    640       dest_scan[i] = (scanline[src_x / 8] & (1 << (7 - src_x % 8))) ? 255 : 0;
    641     }
    642   } else if (src_Bpp == 1) {
    643     for (int i = 0; i < clip_width; i++) {
    644       uint32_t dest_x = clip_left + i;
    645       uint32_t src_x = dest_x * m_Width / dest_width;
    646       if (bFlipX) {
    647         src_x = m_Width - src_x - 1;
    648       }
    649       src_x %= m_Width;
    650       int dest_pos = i;
    651       if (m_pPalette) {
    652         if (!IsCmykImage()) {
    653           dest_pos *= 3;
    654           FX_ARGB argb = m_pPalette.get()[scanline[src_x]];
    655           dest_scan[dest_pos] = FXARGB_B(argb);
    656           dest_scan[dest_pos + 1] = FXARGB_G(argb);
    657           dest_scan[dest_pos + 2] = FXARGB_R(argb);
    658         } else {
    659           dest_pos *= 4;
    660           FX_CMYK cmyk = m_pPalette.get()[scanline[src_x]];
    661           dest_scan[dest_pos] = FXSYS_GetCValue(cmyk);
    662           dest_scan[dest_pos + 1] = FXSYS_GetMValue(cmyk);
    663           dest_scan[dest_pos + 2] = FXSYS_GetYValue(cmyk);
    664           dest_scan[dest_pos + 3] = FXSYS_GetKValue(cmyk);
    665         }
    666       } else {
    667         dest_scan[dest_pos] = scanline[src_x];
    668       }
    669     }
    670   } else {
    671     for (int i = 0; i < clip_width; i++) {
    672       uint32_t dest_x = clip_left + i;
    673       uint32_t src_x =
    674           bFlipX ? (m_Width - dest_x * m_Width / dest_width - 1) * src_Bpp
    675                  : (dest_x * m_Width / dest_width) * src_Bpp;
    676       src_x %= m_Width * src_Bpp;
    677       int dest_pos = i * src_Bpp;
    678       for (int b = 0; b < src_Bpp; b++) {
    679         dest_scan[dest_pos + b] = scanline[src_x + b];
    680       }
    681     }
    682   }
    683 }
    684 
    685 void CFX_DIBitmap::ConvertRGBColorScale(uint32_t forecolor,
    686                                         uint32_t backcolor) {
    687   int fr = FXSYS_GetRValue(forecolor);
    688   int fg = FXSYS_GetGValue(forecolor);
    689   int fb = FXSYS_GetBValue(forecolor);
    690   int br = FXSYS_GetRValue(backcolor);
    691   int bg = FXSYS_GetGValue(backcolor);
    692   int bb = FXSYS_GetBValue(backcolor);
    693   if (m_bpp <= 8) {
    694     if (forecolor == 0 && backcolor == 0xffffff && !m_pPalette)
    695       return;
    696     if (!m_pPalette)
    697       BuildPalette();
    698     int size = 1 << m_bpp;
    699     for (int i = 0; i < size; ++i) {
    700       int gray = FXRGB2GRAY(FXARGB_R(m_pPalette.get()[i]),
    701                             FXARGB_G(m_pPalette.get()[i]),
    702                             FXARGB_B(m_pPalette.get()[i]));
    703       m_pPalette.get()[i] =
    704           FXARGB_MAKE(0xff, br + (fr - br) * gray / 255,
    705                       bg + (fg - bg) * gray / 255, bb + (fb - bb) * gray / 255);
    706     }
    707     return;
    708   }
    709   if (forecolor == 0 && backcolor == 0xffffff) {
    710     for (int row = 0; row < m_Height; ++row) {
    711       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
    712       int gap = m_bpp / 8 - 2;
    713       for (int col = 0; col < m_Width; ++col) {
    714         int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
    715         *scanline++ = gray;
    716         *scanline++ = gray;
    717         *scanline = gray;
    718         scanline += gap;
    719       }
    720     }
    721     return;
    722   }
    723   for (int row = 0; row < m_Height; ++row) {
    724     uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
    725     int gap = m_bpp / 8 - 2;
    726     for (int col = 0; col < m_Width; ++col) {
    727       int gray = FXRGB2GRAY(scanline[2], scanline[1], scanline[0]);
    728       *scanline++ = bb + (fb - bb) * gray / 255;
    729       *scanline++ = bg + (fg - bg) * gray / 255;
    730       *scanline = br + (fr - br) * gray / 255;
    731       scanline += gap;
    732     }
    733   }
    734 }
    735 
    736 void CFX_DIBitmap::ConvertCMYKColorScale(uint32_t forecolor,
    737                                          uint32_t backcolor) {
    738   int fc = FXSYS_GetCValue(forecolor);
    739   int fm = FXSYS_GetMValue(forecolor);
    740   int fy = FXSYS_GetYValue(forecolor);
    741   int fk = FXSYS_GetKValue(forecolor);
    742   int bc = FXSYS_GetCValue(backcolor);
    743   int bm = FXSYS_GetMValue(backcolor);
    744   int by = FXSYS_GetYValue(backcolor);
    745   int bk = FXSYS_GetKValue(backcolor);
    746   if (m_bpp <= 8) {
    747     if (forecolor == 0xff && backcolor == 0 && !m_pPalette)
    748       return;
    749     if (!m_pPalette)
    750       BuildPalette();
    751     int size = 1 << m_bpp;
    752     for (int i = 0; i < size; ++i) {
    753       uint8_t r;
    754       uint8_t g;
    755       uint8_t b;
    756       std::tie(r, g, b) =
    757           AdobeCMYK_to_sRGB1(FXSYS_GetCValue(m_pPalette.get()[i]),
    758                              FXSYS_GetMValue(m_pPalette.get()[i]),
    759                              FXSYS_GetYValue(m_pPalette.get()[i]),
    760                              FXSYS_GetKValue(m_pPalette.get()[i]));
    761       int gray = 255 - FXRGB2GRAY(r, g, b);
    762       m_pPalette.get()[i] =
    763           CmykEncode(bc + (fc - bc) * gray / 255, bm + (fm - bm) * gray / 255,
    764                      by + (fy - by) * gray / 255, bk + (fk - bk) * gray / 255);
    765     }
    766     return;
    767   }
    768   if (forecolor == 0xff && backcolor == 0x00) {
    769     for (int row = 0; row < m_Height; ++row) {
    770       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
    771       for (int col = 0; col < m_Width; ++col) {
    772         uint8_t r;
    773         uint8_t g;
    774         uint8_t b;
    775         std::tie(r, g, b) = AdobeCMYK_to_sRGB1(scanline[0], scanline[1],
    776                                                scanline[2], scanline[3]);
    777         *scanline++ = 0;
    778         *scanline++ = 0;
    779         *scanline++ = 0;
    780         *scanline++ = 255 - FXRGB2GRAY(r, g, b);
    781       }
    782     }
    783     return;
    784   }
    785   for (int row = 0; row < m_Height; ++row) {
    786     uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch;
    787     for (int col = 0; col < m_Width; ++col) {
    788       uint8_t r;
    789       uint8_t g;
    790       uint8_t b;
    791       std::tie(r, g, b) = AdobeCMYK_to_sRGB1(scanline[0], scanline[1],
    792                                              scanline[2], scanline[3]);
    793       int gray = 255 - FXRGB2GRAY(r, g, b);
    794       *scanline++ = bc + (fc - bc) * gray / 255;
    795       *scanline++ = bm + (fm - bm) * gray / 255;
    796       *scanline++ = by + (fy - by) * gray / 255;
    797       *scanline++ = bk + (fk - bk) * gray / 255;
    798     }
    799   }
    800 }
    801 
    802 bool CFX_DIBitmap::ConvertColorScale(uint32_t forecolor, uint32_t backcolor) {
    803   ASSERT(!IsAlphaMask());
    804   if (!m_pBuffer || IsAlphaMask())
    805     return false;
    806 
    807   if (IsCmykImage())
    808     ConvertCMYKColorScale(forecolor, backcolor);
    809   else
    810     ConvertRGBColorScale(forecolor, backcolor);
    811   return true;
    812 }
    813 
    814 bool CFX_DIBitmap::CalculatePitchAndSize(int height,
    815                                          int width,
    816                                          FXDIB_Format format,
    817                                          uint32_t* pitch,
    818                                          uint32_t* size) {
    819   if (width <= 0 || height <= 0)
    820     return false;
    821 
    822   if ((INT_MAX - 31) / width < (format & 0xFF))
    823     return false;
    824 
    825   if (!*pitch)
    826     *pitch = static_cast<uint32_t>((width * (format & 0xff) + 31) / 32 * 4);
    827 
    828   if ((1 << 30) / *pitch < static_cast<uint32_t>(height))
    829     return false;
    830 
    831   *size = *pitch * static_cast<uint32_t>(height);
    832   return true;
    833 }
    834 
    835 bool CFX_DIBitmap::CompositeBitmap(int dest_left,
    836                                    int dest_top,
    837                                    int width,
    838                                    int height,
    839                                    const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    840                                    int src_left,
    841                                    int src_top,
    842                                    int blend_type,
    843                                    const CFX_ClipRgn* pClipRgn,
    844                                    bool bRgbByteOrder) {
    845   if (!m_pBuffer)
    846     return false;
    847 
    848   ASSERT(!pSrcBitmap->IsAlphaMask());
    849   ASSERT(m_bpp >= 8);
    850   if (pSrcBitmap->IsAlphaMask() || m_bpp < 8) {
    851     return false;
    852   }
    853   GetOverlapRect(dest_left, dest_top, width, height, pSrcBitmap->GetWidth(),
    854                  pSrcBitmap->GetHeight(), src_left, src_top, pClipRgn);
    855   if (width == 0 || height == 0) {
    856     return true;
    857   }
    858   RetainPtr<CFX_DIBitmap> pClipMask;
    859   FX_RECT clip_box;
    860   if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
    861     ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF);
    862     pClipMask = pClipRgn->GetMask();
    863     clip_box = pClipRgn->GetBox();
    864   }
    865   CFX_ScanlineCompositor compositor;
    866   if (!compositor.Init(GetFormat(), pSrcBitmap->GetFormat(), width,
    867                        pSrcBitmap->GetPalette(), 0, blend_type,
    868                        pClipMask != nullptr, bRgbByteOrder, 0)) {
    869     return false;
    870   }
    871   int dest_Bpp = m_bpp / 8;
    872   int src_Bpp = pSrcBitmap->GetBPP() / 8;
    873   bool bRgb = src_Bpp > 1 && !pSrcBitmap->IsCmykImage();
    874   RetainPtr<CFX_DIBitmap> pSrcAlphaMask = pSrcBitmap->m_pAlphaMask;
    875   for (int row = 0; row < height; row++) {
    876     uint8_t* dest_scan =
    877         m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * dest_Bpp;
    878     const uint8_t* src_scan =
    879         pSrcBitmap->GetScanline(src_top + row) + src_left * src_Bpp;
    880     const uint8_t* src_scan_extra_alpha =
    881         pSrcAlphaMask ? pSrcAlphaMask->GetScanline(src_top + row) + src_left
    882                       : nullptr;
    883     uint8_t* dst_scan_extra_alpha =
    884         m_pAlphaMask
    885             ? (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left
    886             : nullptr;
    887     const uint8_t* clip_scan = nullptr;
    888     if (pClipMask) {
    889       clip_scan = pClipMask->m_pBuffer.Get() +
    890                   (dest_top + row - clip_box.top) * pClipMask->m_Pitch +
    891                   (dest_left - clip_box.left);
    892     }
    893     if (bRgb) {
    894       compositor.CompositeRgbBitmapLine(dest_scan, src_scan, width, clip_scan,
    895                                         src_scan_extra_alpha,
    896                                         dst_scan_extra_alpha);
    897     } else {
    898       compositor.CompositePalBitmapLine(dest_scan, src_scan, src_left, width,
    899                                         clip_scan, src_scan_extra_alpha,
    900                                         dst_scan_extra_alpha);
    901     }
    902   }
    903   return true;
    904 }
    905 
    906 bool CFX_DIBitmap::CompositeMask(int dest_left,
    907                                  int dest_top,
    908                                  int width,
    909                                  int height,
    910                                  const RetainPtr<CFX_DIBSource>& pMask,
    911                                  uint32_t color,
    912                                  int src_left,
    913                                  int src_top,
    914                                  int blend_type,
    915                                  const CFX_ClipRgn* pClipRgn,
    916                                  bool bRgbByteOrder,
    917                                  int alpha_flag) {
    918   if (!m_pBuffer)
    919     return false;
    920 
    921   ASSERT(pMask->IsAlphaMask());
    922   ASSERT(m_bpp >= 8);
    923   if (!pMask->IsAlphaMask() || m_bpp < 8)
    924     return false;
    925 
    926   GetOverlapRect(dest_left, dest_top, width, height, pMask->GetWidth(),
    927                  pMask->GetHeight(), src_left, src_top, pClipRgn);
    928   if (width == 0 || height == 0)
    929     return true;
    930 
    931   int src_alpha =
    932       (uint8_t)(alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color);
    933   if (src_alpha == 0)
    934     return true;
    935 
    936   RetainPtr<CFX_DIBitmap> pClipMask;
    937   FX_RECT clip_box;
    938   if (pClipRgn && pClipRgn->GetType() != CFX_ClipRgn::RectI) {
    939     ASSERT(pClipRgn->GetType() == CFX_ClipRgn::MaskF);
    940     pClipMask = pClipRgn->GetMask();
    941     clip_box = pClipRgn->GetBox();
    942   }
    943   int src_bpp = pMask->GetBPP();
    944   int Bpp = GetBPP() / 8;
    945   CFX_ScanlineCompositor compositor;
    946   if (!compositor.Init(GetFormat(), pMask->GetFormat(), width, nullptr, color,
    947                        blend_type, pClipMask != nullptr, bRgbByteOrder,
    948                        alpha_flag)) {
    949     return false;
    950   }
    951   for (int row = 0; row < height; row++) {
    952     uint8_t* dest_scan =
    953         m_pBuffer.Get() + (dest_top + row) * m_Pitch + dest_left * Bpp;
    954     const uint8_t* src_scan = pMask->GetScanline(src_top + row);
    955     uint8_t* dst_scan_extra_alpha =
    956         m_pAlphaMask
    957             ? (uint8_t*)m_pAlphaMask->GetScanline(dest_top + row) + dest_left
    958             : nullptr;
    959     const uint8_t* clip_scan = nullptr;
    960     if (pClipMask) {
    961       clip_scan = pClipMask->m_pBuffer.Get() +
    962                   (dest_top + row - clip_box.top) * pClipMask->m_Pitch +
    963                   (dest_left - clip_box.left);
    964     }
    965     if (src_bpp == 1) {
    966       compositor.CompositeBitMaskLine(dest_scan, src_scan, src_left, width,
    967                                       clip_scan, dst_scan_extra_alpha);
    968     } else {
    969       compositor.CompositeByteMaskLine(dest_scan, src_scan + src_left, width,
    970                                        clip_scan, dst_scan_extra_alpha);
    971     }
    972   }
    973   return true;
    974 }
    975 
    976 bool CFX_DIBitmap::CompositeRect(int left,
    977                                  int top,
    978                                  int width,
    979                                  int height,
    980                                  uint32_t color,
    981                                  int alpha_flag) {
    982   if (!m_pBuffer)
    983     return false;
    984 
    985   int src_alpha = (alpha_flag >> 8) ? (alpha_flag & 0xff) : FXARGB_A(color);
    986   if (src_alpha == 0)
    987     return true;
    988 
    989   FX_RECT rect(left, top, left + width, top + height);
    990   rect.Intersect(0, 0, m_Width, m_Height);
    991   if (rect.IsEmpty())
    992     return true;
    993 
    994   width = rect.Width();
    995   uint32_t dst_color;
    996   if (alpha_flag >> 8)
    997     dst_color = FXCMYK_TODIB(color);
    998   else
    999     dst_color = FXARGB_TODIB(color);
   1000   uint8_t* color_p = (uint8_t*)&dst_color;
   1001   if (m_bpp == 8) {
   1002     uint8_t gray = 255;
   1003     if (!IsAlphaMask()) {
   1004       if (alpha_flag >> 8) {
   1005         uint8_t r;
   1006         uint8_t g;
   1007         uint8_t b;
   1008         std::tie(r, g, b) =
   1009             AdobeCMYK_to_sRGB1(color_p[0], color_p[1], color_p[2], color_p[3]);
   1010         gray = FXRGB2GRAY(r, g, b);
   1011       } else {
   1012         gray = (uint8_t)FXRGB2GRAY((int)color_p[2], color_p[1], color_p[0]);
   1013       }
   1014       if (IsCmykImage()) {
   1015         gray = ~gray;
   1016       }
   1017     }
   1018     for (int row = rect.top; row < rect.bottom; row++) {
   1019       uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left;
   1020       if (src_alpha == 255) {
   1021         memset(dest_scan, gray, width);
   1022       } else {
   1023         for (int col = 0; col < width; col++) {
   1024           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, gray, src_alpha);
   1025           dest_scan++;
   1026         }
   1027       }
   1028     }
   1029     return true;
   1030   }
   1031   if (m_bpp == 1) {
   1032     ASSERT(!IsCmykImage() && static_cast<uint8_t>(alpha_flag >> 8) == 0);
   1033     int left_shift = rect.left % 8;
   1034     int right_shift = rect.right % 8;
   1035     int new_width = rect.right / 8 - rect.left / 8;
   1036     int index = 0;
   1037     if (m_pPalette) {
   1038       for (int i = 0; i < 2; i++) {
   1039         if (m_pPalette.get()[i] == color)
   1040           index = i;
   1041       }
   1042     } else {
   1043       index = (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
   1044     }
   1045     for (int row = rect.top; row < rect.bottom; row++) {
   1046       uint8_t* dest_scan_top =
   1047           const_cast<uint8_t*>(GetScanline(row)) + rect.left / 8;
   1048       uint8_t* dest_scan_top_r =
   1049           const_cast<uint8_t*>(GetScanline(row)) + rect.right / 8;
   1050       uint8_t left_flag = *dest_scan_top & (255 << (8 - left_shift));
   1051       uint8_t right_flag = *dest_scan_top_r & (255 >> right_shift);
   1052       if (new_width) {
   1053         memset(dest_scan_top + 1, index ? 255 : 0, new_width - 1);
   1054         if (!index) {
   1055           *dest_scan_top &= left_flag;
   1056           *dest_scan_top_r &= right_flag;
   1057         } else {
   1058           *dest_scan_top |= ~left_flag;
   1059           *dest_scan_top_r |= ~right_flag;
   1060         }
   1061       } else {
   1062         if (!index) {
   1063           *dest_scan_top &= left_flag | right_flag;
   1064         } else {
   1065           *dest_scan_top |= ~(left_flag | right_flag);
   1066         }
   1067       }
   1068     }
   1069     return true;
   1070   }
   1071   ASSERT(m_bpp >= 24);
   1072   if (m_bpp < 24 || (!(alpha_flag >> 8) && IsCmykImage()))
   1073     return false;
   1074   if (alpha_flag >> 8 && !IsCmykImage()) {
   1075     std::tie(color_p[2], color_p[1], color_p[0]) =
   1076         AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color),
   1077                            FXSYS_GetYValue(color), FXSYS_GetKValue(color));
   1078   }
   1079   if (!IsCmykImage())
   1080     color_p[3] = static_cast<uint8_t>(src_alpha);
   1081   int Bpp = m_bpp / 8;
   1082   bool bAlpha = HasAlpha();
   1083   bool bArgb = GetFormat() == FXDIB_Argb;
   1084   if (src_alpha == 255) {
   1085     for (int row = rect.top; row < rect.bottom; row++) {
   1086       uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
   1087       uint8_t* dest_scan_alpha =
   1088           m_pAlphaMask ? (uint8_t*)m_pAlphaMask->GetScanline(row) + rect.left
   1089                        : nullptr;
   1090       if (dest_scan_alpha) {
   1091         memset(dest_scan_alpha, 0xff, width);
   1092       }
   1093       if (Bpp == 4) {
   1094         uint32_t* scan = (uint32_t*)dest_scan;
   1095         for (int col = 0; col < width; col++) {
   1096           *scan++ = dst_color;
   1097         }
   1098       } else {
   1099         for (int col = 0; col < width; col++) {
   1100           *dest_scan++ = color_p[0];
   1101           *dest_scan++ = color_p[1];
   1102           *dest_scan++ = color_p[2];
   1103         }
   1104       }
   1105     }
   1106     return true;
   1107   }
   1108   for (int row = rect.top; row < rect.bottom; row++) {
   1109     uint8_t* dest_scan = m_pBuffer.Get() + row * m_Pitch + rect.left * Bpp;
   1110     if (bAlpha) {
   1111       if (bArgb) {
   1112         for (int col = 0; col < width; col++) {
   1113           uint8_t back_alpha = dest_scan[3];
   1114           if (back_alpha == 0) {
   1115             FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha, color_p[2],
   1116                                                  color_p[1], color_p[0]));
   1117             dest_scan += 4;
   1118             continue;
   1119           }
   1120           uint8_t dest_alpha =
   1121               back_alpha + src_alpha - back_alpha * src_alpha / 255;
   1122           int alpha_ratio = src_alpha * 255 / dest_alpha;
   1123           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[0], alpha_ratio);
   1124           dest_scan++;
   1125           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[1], alpha_ratio);
   1126           dest_scan++;
   1127           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[2], alpha_ratio);
   1128           dest_scan++;
   1129           *dest_scan++ = dest_alpha;
   1130         }
   1131       } else {
   1132         uint8_t* dest_scan_alpha =
   1133             (uint8_t*)m_pAlphaMask->GetScanline(row) + rect.left;
   1134         for (int col = 0; col < width; col++) {
   1135           uint8_t back_alpha = *dest_scan_alpha;
   1136           if (back_alpha == 0) {
   1137             *dest_scan_alpha++ = src_alpha;
   1138             memcpy(dest_scan, color_p, Bpp);
   1139             dest_scan += Bpp;
   1140             continue;
   1141           }
   1142           uint8_t dest_alpha =
   1143               back_alpha + src_alpha - back_alpha * src_alpha / 255;
   1144           *dest_scan_alpha++ = dest_alpha;
   1145           int alpha_ratio = src_alpha * 255 / dest_alpha;
   1146           for (int comps = 0; comps < Bpp; comps++) {
   1147             *dest_scan =
   1148                 FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], alpha_ratio);
   1149             dest_scan++;
   1150           }
   1151         }
   1152       }
   1153     } else {
   1154       for (int col = 0; col < width; col++) {
   1155         for (int comps = 0; comps < Bpp; comps++) {
   1156           if (comps == 3) {
   1157             *dest_scan++ = 255;
   1158             continue;
   1159           }
   1160           *dest_scan = FXDIB_ALPHA_MERGE(*dest_scan, color_p[comps], src_alpha);
   1161           dest_scan++;
   1162         }
   1163       }
   1164     }
   1165   }
   1166   return true;
   1167 }
   1168 
   1169 bool CFX_DIBitmap::ConvertFormat(FXDIB_Format dest_format) {
   1170   FXDIB_Format src_format = GetFormat();
   1171   if (dest_format == src_format)
   1172     return true;
   1173 
   1174   if (dest_format == FXDIB_8bppMask && src_format == FXDIB_8bppRgb &&
   1175       !m_pPalette) {
   1176     m_AlphaFlag = 1;
   1177     return true;
   1178   }
   1179   if (dest_format == FXDIB_Argb && src_format == FXDIB_Rgb32) {
   1180     m_AlphaFlag = 2;
   1181     for (int row = 0; row < m_Height; row++) {
   1182       uint8_t* scanline = m_pBuffer.Get() + row * m_Pitch + 3;
   1183       for (int col = 0; col < m_Width; col++) {
   1184         *scanline = 0xff;
   1185         scanline += 4;
   1186       }
   1187     }
   1188     return true;
   1189   }
   1190   int dest_bpp = dest_format & 0xff;
   1191   int dest_pitch = (dest_bpp * m_Width + 31) / 32 * 4;
   1192   std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
   1193       FX_TryAlloc(uint8_t, dest_pitch * m_Height + 4));
   1194   if (!dest_buf)
   1195     return false;
   1196 
   1197   RetainPtr<CFX_DIBitmap> pAlphaMask;
   1198   if (dest_format == FXDIB_Argb) {
   1199     memset(dest_buf.get(), 0xff, dest_pitch * m_Height + 4);
   1200     if (m_pAlphaMask) {
   1201       for (int row = 0; row < m_Height; row++) {
   1202         uint8_t* pDstScanline = dest_buf.get() + row * dest_pitch + 3;
   1203         const uint8_t* pSrcScanline = m_pAlphaMask->GetScanline(row);
   1204         for (int col = 0; col < m_Width; col++) {
   1205           *pDstScanline = *pSrcScanline++;
   1206           pDstScanline += 4;
   1207         }
   1208       }
   1209     }
   1210   } else if (dest_format & 0x0200) {
   1211     if (src_format == FXDIB_Argb) {
   1212       pAlphaMask = CloneAlphaMask();
   1213       if (!pAlphaMask)
   1214         return false;
   1215     } else {
   1216       if (!m_pAlphaMask) {
   1217         if (!BuildAlphaMask())
   1218           return false;
   1219         pAlphaMask = std::move(m_pAlphaMask);
   1220       } else {
   1221         pAlphaMask = m_pAlphaMask;
   1222       }
   1223     }
   1224   }
   1225   bool ret = false;
   1226   RetainPtr<CFX_DIBSource> holder(this);
   1227   std::unique_ptr<uint32_t, FxFreeDeleter> pal_8bpp;
   1228   ret = ConvertBuffer(dest_format, dest_buf.get(), dest_pitch, m_Width,
   1229                       m_Height, holder, 0, 0, &pal_8bpp);
   1230   if (!ret)
   1231     return false;
   1232 
   1233   m_pAlphaMask = pAlphaMask;
   1234   m_pPalette = std::move(pal_8bpp);
   1235   m_pBuffer = std::move(dest_buf);
   1236   m_bpp = static_cast<uint8_t>(dest_format);
   1237   m_AlphaFlag = static_cast<uint8_t>(dest_format >> 8);
   1238   m_Pitch = dest_pitch;
   1239   return true;
   1240 }
   1241