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_dibsource.h"
      8 
      9 #include <algorithm>
     10 #include <memory>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "core/fxcodec/fx_codec.h"
     15 #include "core/fxge/cfx_cliprgn.h"
     16 #include "core/fxge/dib/cfx_bitmapstorer.h"
     17 #include "core/fxge/dib/cfx_dibitmap.h"
     18 #include "core/fxge/dib/cfx_imagestretcher.h"
     19 #include "core/fxge/dib/cfx_imagetransformer.h"
     20 #include "third_party/base/logging.h"
     21 #include "third_party/base/ptr_util.h"
     22 
     23 namespace {
     24 
     25 class CFX_Palette {
     26  public:
     27   explicit CFX_Palette(const RetainPtr<CFX_DIBSource>& pBitmap);
     28   ~CFX_Palette();
     29 
     30   const uint32_t* GetPalette() { return m_Palette.data(); }
     31   const std::pair<uint32_t, uint32_t>* GetLuts() const { return m_Luts.data(); }
     32   int32_t GetLutCount() const { return m_lut; }
     33   void SetAmountLut(int row, uint32_t value) { m_Luts[row].first = value; }
     34 
     35  private:
     36   std::vector<uint32_t> m_Palette;
     37   // (Amount, Color) pairs
     38   std::vector<std::pair<uint32_t, uint32_t>> m_Luts;
     39   int m_lut;
     40 };
     41 
     42 void ColorDecode(uint32_t pal_v, uint8_t* r, uint8_t* g, uint8_t* b) {
     43   *r = static_cast<uint8_t>((pal_v & 0xf00) >> 4);
     44   *g = static_cast<uint8_t>(pal_v & 0x0f0);
     45   *b = static_cast<uint8_t>((pal_v & 0x00f) << 4);
     46 }
     47 
     48 void Obtain_Pal(std::pair<uint32_t, uint32_t>* luts,
     49                 uint32_t* dest_pal,
     50                 uint32_t lut) {
     51   uint32_t lut_1 = lut - 1;
     52   for (int row = 0; row < 256; ++row) {
     53     int lut_offset = lut_1 - row;
     54     if (lut_offset < 0)
     55       lut_offset += 256;
     56     uint32_t color = luts[lut_offset].second;
     57     uint8_t r;
     58     uint8_t g;
     59     uint8_t b;
     60     ColorDecode(color, &r, &g, &b);
     61     dest_pal[row] = (static_cast<uint32_t>(r) << 16) |
     62                     (static_cast<uint32_t>(g) << 8) | b | 0xff000000;
     63     luts[lut_offset].first = row;
     64   }
     65 }
     66 
     67 CFX_Palette::CFX_Palette(const RetainPtr<CFX_DIBSource>& pBitmap)
     68     : m_Palette(256), m_Luts(4096), m_lut(0) {
     69   int bpp = pBitmap->GetBPP() / 8;
     70   int width = pBitmap->GetWidth();
     71   int height = pBitmap->GetHeight();
     72   for (int row = 0; row < height; ++row) {
     73     const uint8_t* scan_line = pBitmap->GetScanline(row);
     74     for (int col = 0; col < width; ++col) {
     75       const uint8_t* src_port = scan_line + col * bpp;
     76       uint32_t b = src_port[0] & 0xf0;
     77       uint32_t g = src_port[1] & 0xf0;
     78       uint32_t r = src_port[2] & 0xf0;
     79       uint32_t index = (r << 4) + g + (b >> 4);
     80       ++m_Luts[index].first;
     81     }
     82   }
     83   // Move non-zeros to the front and count them
     84   for (int row = 0; row < 4096; ++row) {
     85     if (m_Luts[row].first != 0) {
     86       m_Luts[m_lut].first = m_Luts[row].first;
     87       m_Luts[m_lut].second = row;
     88       ++m_lut;
     89     }
     90   }
     91   std::sort(m_Luts.begin(), m_Luts.begin() + m_lut,
     92             [](const std::pair<uint32_t, uint32_t>& arg1,
     93                const std::pair<uint32_t, uint32_t>& arg2) {
     94               return arg1.first < arg2.first;
     95             });
     96   Obtain_Pal(m_Luts.data(), m_Palette.data(), m_lut);
     97 }
     98 
     99 CFX_Palette::~CFX_Palette() {}
    100 
    101 void ConvertBuffer_1bppMask2Gray(uint8_t* dest_buf,
    102                                  int dest_pitch,
    103                                  int width,
    104                                  int height,
    105                                  const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    106                                  int src_left,
    107                                  int src_top) {
    108   uint8_t set_gray, reset_gray;
    109   set_gray = 0xff;
    110   reset_gray = 0x00;
    111   for (int row = 0; row < height; ++row) {
    112     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    113     memset(dest_scan, reset_gray, width);
    114     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    115     for (int col = src_left; col < src_left + width; ++col) {
    116       if (src_scan[col / 8] & (1 << (7 - col % 8)))
    117         *dest_scan = set_gray;
    118       ++dest_scan;
    119     }
    120   }
    121 }
    122 
    123 void ConvertBuffer_8bppMask2Gray(uint8_t* dest_buf,
    124                                  int dest_pitch,
    125                                  int width,
    126                                  int height,
    127                                  const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    128                                  int src_left,
    129                                  int src_top) {
    130   for (int row = 0; row < height; ++row) {
    131     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    132     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
    133     memcpy(dest_scan, src_scan, width);
    134   }
    135 }
    136 
    137 void ConvertBuffer_1bppPlt2Gray(uint8_t* dest_buf,
    138                                 int dest_pitch,
    139                                 int width,
    140                                 int height,
    141                                 const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    142                                 int src_left,
    143                                 int src_top) {
    144   uint32_t* src_plt = pSrcBitmap->GetPalette();
    145   uint8_t gray[2];
    146   uint8_t reset_r;
    147   uint8_t reset_g;
    148   uint8_t reset_b;
    149   uint8_t set_r;
    150   uint8_t set_g;
    151   uint8_t set_b;
    152   if (pSrcBitmap->IsCmykImage()) {
    153     std::tie(reset_r, reset_g, reset_b) = AdobeCMYK_to_sRGB1(
    154         FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]),
    155         FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]));
    156     std::tie(set_r, set_g, set_b) = AdobeCMYK_to_sRGB1(
    157         FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]),
    158         FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]));
    159   } else {
    160     reset_r = FXARGB_R(src_plt[0]);
    161     reset_g = FXARGB_G(src_plt[0]);
    162     reset_b = FXARGB_B(src_plt[0]);
    163     set_r = FXARGB_R(src_plt[1]);
    164     set_g = FXARGB_G(src_plt[1]);
    165     set_b = FXARGB_B(src_plt[1]);
    166   }
    167   gray[0] = FXRGB2GRAY(reset_r, reset_g, reset_b);
    168   gray[1] = FXRGB2GRAY(set_r, set_g, set_b);
    169 
    170   for (int row = 0; row < height; ++row) {
    171     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    172     memset(dest_scan, gray[0], width);
    173     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    174     for (int col = src_left; col < src_left + width; ++col) {
    175       if (src_scan[col / 8] & (1 << (7 - col % 8)))
    176         *dest_scan = gray[1];
    177       ++dest_scan;
    178     }
    179   }
    180 }
    181 
    182 void ConvertBuffer_8bppPlt2Gray(uint8_t* dest_buf,
    183                                 int dest_pitch,
    184                                 int width,
    185                                 int height,
    186                                 const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    187                                 int src_left,
    188                                 int src_top) {
    189   uint32_t* src_plt = pSrcBitmap->GetPalette();
    190   uint8_t gray[256];
    191   if (pSrcBitmap->IsCmykImage()) {
    192     uint8_t r;
    193     uint8_t g;
    194     uint8_t b;
    195     for (size_t i = 0; i < FX_ArraySize(gray); ++i) {
    196       std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
    197           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
    198           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
    199       gray[i] = FXRGB2GRAY(r, g, b);
    200     }
    201   } else {
    202     for (size_t i = 0; i < FX_ArraySize(gray); ++i) {
    203       gray[i] = FXRGB2GRAY(FXARGB_R(src_plt[i]), FXARGB_G(src_plt[i]),
    204                            FXARGB_B(src_plt[i]));
    205     }
    206   }
    207 
    208   for (int row = 0; row < height; ++row) {
    209     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    210     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
    211     for (int col = 0; col < width; ++col)
    212       *dest_scan++ = gray[*src_scan++];
    213   }
    214 }
    215 
    216 void ConvertBuffer_RgbOrCmyk2Gray(uint8_t* dest_buf,
    217                                   int dest_pitch,
    218                                   int width,
    219                                   int height,
    220                                   const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    221                                   int src_left,
    222                                   int src_top) {
    223   int Bpp = pSrcBitmap->GetBPP() / 8;
    224   if (pSrcBitmap->IsCmykImage()) {
    225     for (int row = 0; row < height; ++row) {
    226       uint8_t* dest_scan = dest_buf + row * dest_pitch;
    227       const uint8_t* src_scan =
    228           pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
    229       for (int col = 0; col < width; ++col) {
    230         uint8_t r;
    231         uint8_t g;
    232         uint8_t b;
    233         std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
    234             FXSYS_GetCValue(static_cast<uint32_t>(src_scan[0])),
    235             FXSYS_GetMValue(static_cast<uint32_t>(src_scan[1])),
    236             FXSYS_GetYValue(static_cast<uint32_t>(src_scan[2])),
    237             FXSYS_GetKValue(static_cast<uint32_t>(src_scan[3])));
    238         *dest_scan++ = FXRGB2GRAY(r, g, b);
    239         src_scan += 4;
    240       }
    241     }
    242   } else {
    243     for (int row = 0; row < height; ++row) {
    244       uint8_t* dest_scan = dest_buf + row * dest_pitch;
    245       const uint8_t* src_scan =
    246           pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
    247       for (int col = 0; col < width; ++col) {
    248         *dest_scan++ = FXRGB2GRAY(src_scan[2], src_scan[1], src_scan[0]);
    249         src_scan += Bpp;
    250       }
    251     }
    252   }
    253 }
    254 
    255 void ConvertBuffer_IndexCopy(uint8_t* dest_buf,
    256                              int dest_pitch,
    257                              int width,
    258                              int height,
    259                              const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    260                              int src_left,
    261                              int src_top) {
    262   if (pSrcBitmap->GetBPP() == 1) {
    263     for (int row = 0; row < height; ++row) {
    264       uint8_t* dest_scan = dest_buf + row * dest_pitch;
    265       // Set all destination pixels to be white initially.
    266       memset(dest_scan, 255, width);
    267       const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    268       for (int col = src_left; col < src_left + width; ++col) {
    269         // If the source bit is set, then set the destination pixel to be black.
    270         if (src_scan[col / 8] & (1 << (7 - col % 8)))
    271           *dest_scan = 0;
    272 
    273         ++dest_scan;
    274       }
    275     }
    276   } else {
    277     for (int row = 0; row < height; ++row) {
    278       uint8_t* dest_scan = dest_buf + row * dest_pitch;
    279       const uint8_t* src_scan =
    280           pSrcBitmap->GetScanline(src_top + row) + src_left;
    281       memcpy(dest_scan, src_scan, width);
    282     }
    283   }
    284 }
    285 
    286 void ConvertBuffer_Plt2PltRgb8(uint8_t* dest_buf,
    287                                int dest_pitch,
    288                                int width,
    289                                int height,
    290                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    291                                int src_left,
    292                                int src_top,
    293                                uint32_t* dst_plt) {
    294   ConvertBuffer_IndexCopy(dest_buf, dest_pitch, width, height, pSrcBitmap,
    295                           src_left, src_top);
    296   uint32_t* src_plt = pSrcBitmap->GetPalette();
    297   int plt_size = pSrcBitmap->GetPaletteSize();
    298   if (pSrcBitmap->IsCmykImage()) {
    299     for (int i = 0; i < plt_size; ++i) {
    300       uint8_t r;
    301       uint8_t g;
    302       uint8_t b;
    303       std::tie(r, g, b) = AdobeCMYK_to_sRGB1(
    304           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
    305           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
    306       dst_plt[i] = FXARGB_MAKE(0xff, r, g, b);
    307     }
    308   } else {
    309     memcpy(dst_plt, src_plt, plt_size * 4);
    310   }
    311 }
    312 
    313 void ConvertBuffer_Rgb2PltRgb8(uint8_t* dest_buf,
    314                                int dest_pitch,
    315                                int width,
    316                                int height,
    317                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    318                                int src_left,
    319                                int src_top,
    320                                uint32_t* dst_plt) {
    321   int bpp = pSrcBitmap->GetBPP() / 8;
    322   CFX_Palette palette(pSrcBitmap);
    323   const std::pair<uint32_t, uint32_t>* Luts = palette.GetLuts();
    324   int lut = palette.GetLutCount();
    325   const uint32_t* pal = palette.GetPalette();
    326   if (lut > 256) {
    327     int err;
    328     int min_err;
    329     int lut_256 = lut - 256;
    330     for (int row = 0; row < lut_256; ++row) {
    331       min_err = 1000000;
    332       uint8_t r;
    333       uint8_t g;
    334       uint8_t b;
    335       ColorDecode(Luts[row].second, &r, &g, &b);
    336       uint32_t clrindex = 0;
    337       for (int col = 0; col < 256; ++col) {
    338         uint32_t p_color = pal[col];
    339         int d_r = r - static_cast<uint8_t>(p_color >> 16);
    340         int d_g = g - static_cast<uint8_t>(p_color >> 8);
    341         int d_b = b - static_cast<uint8_t>(p_color);
    342         err = d_r * d_r + d_g * d_g + d_b * d_b;
    343         if (err < min_err) {
    344           min_err = err;
    345           clrindex = col;
    346         }
    347       }
    348       palette.SetAmountLut(row, clrindex);
    349     }
    350   }
    351   int32_t lut_1 = lut - 1;
    352   for (int row = 0; row < height; ++row) {
    353     uint8_t* src_scan =
    354         const_cast<uint8_t*>(pSrcBitmap->GetScanline(src_top + row)) + src_left;
    355     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    356     for (int col = 0; col < width; ++col) {
    357       uint8_t* src_port = src_scan + col * bpp;
    358       int r = src_port[2] & 0xf0;
    359       int g = src_port[1] & 0xf0;
    360       int b = src_port[0] & 0xf0;
    361       uint32_t clrindex = (r << 4) + g + (b >> 4);
    362       for (int i = lut_1; i >= 0; --i)
    363         if (clrindex == Luts[i].second) {
    364           *(dest_scan + col) = static_cast<uint8_t>(Luts[i].first);
    365           break;
    366         }
    367     }
    368   }
    369   memcpy(dst_plt, pal, sizeof(uint32_t) * 256);
    370 }
    371 
    372 void ConvertBuffer_1bppMask2Rgb(FXDIB_Format dst_format,
    373                                 uint8_t* dest_buf,
    374                                 int dest_pitch,
    375                                 int width,
    376                                 int height,
    377                                 const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    378                                 int src_left,
    379                                 int src_top) {
    380   int comps = (dst_format & 0xff) / 8;
    381   uint8_t set_gray, reset_gray;
    382   set_gray = 0xff;
    383   reset_gray = 0x00;
    384   for (int row = 0; row < height; ++row) {
    385     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    386     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    387     for (int col = src_left; col < src_left + width; ++col) {
    388       if (src_scan[col / 8] & (1 << (7 - col % 8))) {
    389         dest_scan[0] = set_gray;
    390         dest_scan[1] = set_gray;
    391         dest_scan[2] = set_gray;
    392       } else {
    393         dest_scan[0] = reset_gray;
    394         dest_scan[1] = reset_gray;
    395         dest_scan[2] = reset_gray;
    396       }
    397       dest_scan += comps;
    398     }
    399   }
    400 }
    401 
    402 void ConvertBuffer_8bppMask2Rgb(FXDIB_Format dst_format,
    403                                 uint8_t* dest_buf,
    404                                 int dest_pitch,
    405                                 int width,
    406                                 int height,
    407                                 const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    408                                 int src_left,
    409                                 int src_top) {
    410   int comps = (dst_format & 0xff) / 8;
    411   for (int row = 0; row < height; ++row) {
    412     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    413     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
    414     uint8_t src_pixel;
    415     for (int col = 0; col < width; ++col) {
    416       src_pixel = *src_scan++;
    417       *dest_scan++ = src_pixel;
    418       *dest_scan++ = src_pixel;
    419       *dest_scan = src_pixel;
    420       dest_scan += comps - 2;
    421     }
    422   }
    423 }
    424 
    425 void ConvertBuffer_1bppPlt2Rgb(FXDIB_Format dst_format,
    426                                uint8_t* dest_buf,
    427                                int dest_pitch,
    428                                int width,
    429                                int height,
    430                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    431                                int src_left,
    432                                int src_top) {
    433   int comps = (dst_format & 0xff) / 8;
    434   uint32_t* src_plt = pSrcBitmap->GetPalette();
    435   uint32_t plt[2];
    436   uint8_t* bgr_ptr = reinterpret_cast<uint8_t*>(plt);
    437   if (pSrcBitmap->IsCmykImage()) {
    438     plt[0] = FXCMYK_TODIB(src_plt[0]);
    439     plt[1] = FXCMYK_TODIB(src_plt[1]);
    440   } else {
    441     bgr_ptr[0] = FXARGB_B(src_plt[0]);
    442     bgr_ptr[1] = FXARGB_G(src_plt[0]);
    443     bgr_ptr[2] = FXARGB_R(src_plt[0]);
    444     bgr_ptr[3] = FXARGB_B(src_plt[1]);
    445     bgr_ptr[4] = FXARGB_G(src_plt[1]);
    446     bgr_ptr[5] = FXARGB_R(src_plt[1]);
    447   }
    448 
    449   if (pSrcBitmap->IsCmykImage()) {
    450     std::tie(bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]) = AdobeCMYK_to_sRGB1(
    451         FXSYS_GetCValue(src_plt[0]), FXSYS_GetMValue(src_plt[0]),
    452         FXSYS_GetYValue(src_plt[0]), FXSYS_GetKValue(src_plt[0]));
    453     std::tie(bgr_ptr[5], bgr_ptr[4], bgr_ptr[3]) = AdobeCMYK_to_sRGB1(
    454         FXSYS_GetCValue(src_plt[1]), FXSYS_GetMValue(src_plt[1]),
    455         FXSYS_GetYValue(src_plt[1]), FXSYS_GetKValue(src_plt[1]));
    456   }
    457 
    458   for (int row = 0; row < height; ++row) {
    459     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    460     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row);
    461     for (int col = src_left; col < src_left + width; ++col) {
    462       if (src_scan[col / 8] & (1 << (7 - col % 8))) {
    463         *dest_scan++ = bgr_ptr[3];
    464         *dest_scan++ = bgr_ptr[4];
    465         *dest_scan = bgr_ptr[5];
    466       } else {
    467         *dest_scan++ = bgr_ptr[0];
    468         *dest_scan++ = bgr_ptr[1];
    469         *dest_scan = bgr_ptr[2];
    470       }
    471       dest_scan += comps - 2;
    472     }
    473   }
    474 }
    475 
    476 void ConvertBuffer_8bppPlt2Rgb(FXDIB_Format dst_format,
    477                                uint8_t* dest_buf,
    478                                int dest_pitch,
    479                                int width,
    480                                int height,
    481                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    482                                int src_left,
    483                                int src_top) {
    484   int comps = (dst_format & 0xff) / 8;
    485   uint32_t* src_plt = pSrcBitmap->GetPalette();
    486   uint32_t plt[256];
    487   uint8_t* bgr_ptr = reinterpret_cast<uint8_t*>(plt);
    488   if (!pSrcBitmap->IsCmykImage()) {
    489     for (int i = 0; i < 256; ++i) {
    490       *bgr_ptr++ = FXARGB_B(src_plt[i]);
    491       *bgr_ptr++ = FXARGB_G(src_plt[i]);
    492       *bgr_ptr++ = FXARGB_R(src_plt[i]);
    493     }
    494     bgr_ptr = reinterpret_cast<uint8_t*>(plt);
    495   }
    496 
    497   if (pSrcBitmap->IsCmykImage()) {
    498     for (int i = 0; i < 256; ++i) {
    499       std::tie(bgr_ptr[2], bgr_ptr[1], bgr_ptr[0]) = AdobeCMYK_to_sRGB1(
    500           FXSYS_GetCValue(src_plt[i]), FXSYS_GetMValue(src_plt[i]),
    501           FXSYS_GetYValue(src_plt[i]), FXSYS_GetKValue(src_plt[i]));
    502       bgr_ptr += 3;
    503     }
    504     bgr_ptr = reinterpret_cast<uint8_t*>(plt);
    505   }
    506 
    507   for (int row = 0; row < height; ++row) {
    508     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    509     const uint8_t* src_scan = pSrcBitmap->GetScanline(src_top + row) + src_left;
    510     for (int col = 0; col < width; ++col) {
    511       uint8_t* src_pixel = bgr_ptr + 3 * (*src_scan++);
    512       *dest_scan++ = *src_pixel++;
    513       *dest_scan++ = *src_pixel++;
    514       *dest_scan = *src_pixel++;
    515       dest_scan += comps - 2;
    516     }
    517   }
    518 }
    519 
    520 void ConvertBuffer_24bppRgb2Rgb24(uint8_t* dest_buf,
    521                                   int dest_pitch,
    522                                   int width,
    523                                   int height,
    524                                   const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    525                                   int src_left,
    526                                   int src_top) {
    527   for (int row = 0; row < height; ++row) {
    528     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    529     const uint8_t* src_scan =
    530         pSrcBitmap->GetScanline(src_top + row) + src_left * 3;
    531     memcpy(dest_scan, src_scan, width * 3);
    532   }
    533 }
    534 
    535 void ConvertBuffer_32bppRgb2Rgb24(uint8_t* dest_buf,
    536                                   int dest_pitch,
    537                                   int width,
    538                                   int height,
    539                                   const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    540                                   int src_left,
    541                                   int src_top) {
    542   for (int row = 0; row < height; ++row) {
    543     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    544     const uint8_t* src_scan =
    545         pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
    546     for (int col = 0; col < width; ++col) {
    547       *dest_scan++ = *src_scan++;
    548       *dest_scan++ = *src_scan++;
    549       *dest_scan++ = *src_scan++;
    550       ++src_scan;
    551     }
    552   }
    553 }
    554 
    555 void ConvertBuffer_Rgb2Rgb32(uint8_t* dest_buf,
    556                              int dest_pitch,
    557                              int width,
    558                              int height,
    559                              const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    560                              int src_left,
    561                              int src_top) {
    562   int comps = pSrcBitmap->GetBPP() / 8;
    563   for (int row = 0; row < height; ++row) {
    564     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    565     const uint8_t* src_scan =
    566         pSrcBitmap->GetScanline(src_top + row) + src_left * comps;
    567     for (int col = 0; col < width; ++col) {
    568       *dest_scan++ = *src_scan++;
    569       *dest_scan++ = *src_scan++;
    570       *dest_scan++ = *src_scan++;
    571       ++dest_scan;
    572       src_scan += comps - 3;
    573     }
    574   }
    575 }
    576 
    577 void ConvertBuffer_32bppCmyk2Rgb32(uint8_t* dest_buf,
    578                                    int dest_pitch,
    579                                    int width,
    580                                    int height,
    581                                    const RetainPtr<CFX_DIBSource>& pSrcBitmap,
    582                                    int src_left,
    583                                    int src_top) {
    584   for (int row = 0; row < height; ++row) {
    585     uint8_t* dest_scan = dest_buf + row * dest_pitch;
    586     const uint8_t* src_scan =
    587         pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
    588     for (int col = 0; col < width; ++col) {
    589       std::tie(dest_scan[2], dest_scan[1], dest_scan[0]) = AdobeCMYK_to_sRGB1(
    590           src_scan[0], src_scan[1], src_scan[2], src_scan[3]);
    591       dest_scan += 4;
    592       src_scan += 4;
    593     }
    594   }
    595 }
    596 
    597 }  // namespace
    598 
    599 CFX_DIBSource::CFX_DIBSource()
    600     : m_Width(0), m_Height(0), m_bpp(0), m_AlphaFlag(0), m_Pitch(0) {}
    601 
    602 CFX_DIBSource::~CFX_DIBSource() {}
    603 
    604 uint8_t* CFX_DIBSource::GetBuffer() const {
    605   return nullptr;
    606 }
    607 
    608 bool CFX_DIBSource::SkipToScanline(int line, IFX_PauseIndicator* pPause) const {
    609   return false;
    610 }
    611 
    612 RetainPtr<CFX_DIBitmap> CFX_DIBSource::Clone(const FX_RECT* pClip) const {
    613   FX_RECT rect(0, 0, m_Width, m_Height);
    614   if (pClip) {
    615     rect.Intersect(*pClip);
    616     if (rect.IsEmpty())
    617       return nullptr;
    618   }
    619   auto pNewBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
    620   if (!pNewBitmap->Create(rect.Width(), rect.Height(), GetFormat()))
    621     return nullptr;
    622 
    623   pNewBitmap->SetPalette(m_pPalette.get());
    624   pNewBitmap->SetAlphaMask(m_pAlphaMask, pClip);
    625   if (GetBPP() == 1 && rect.left % 8 != 0) {
    626     int left_shift = rect.left % 32;
    627     int right_shift = 32 - left_shift;
    628     int dword_count = pNewBitmap->m_Pitch / 4;
    629     for (int row = rect.top; row < rect.bottom; ++row) {
    630       uint32_t* src_scan = (uint32_t*)GetScanline(row) + rect.left / 32;
    631       uint32_t* dest_scan = (uint32_t*)pNewBitmap->GetScanline(row - rect.top);
    632       for (int i = 0; i < dword_count; ++i) {
    633         dest_scan[i] =
    634             (src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift);
    635       }
    636     }
    637   } else {
    638     int copy_len = (pNewBitmap->GetWidth() * pNewBitmap->GetBPP() + 7) / 8;
    639     if (m_Pitch < static_cast<uint32_t>(copy_len))
    640       copy_len = m_Pitch;
    641 
    642     for (int row = rect.top; row < rect.bottom; ++row) {
    643       const uint8_t* src_scan = GetScanline(row) + rect.left * m_bpp / 8;
    644       uint8_t* dest_scan = (uint8_t*)pNewBitmap->GetScanline(row - rect.top);
    645       memcpy(dest_scan, src_scan, copy_len);
    646     }
    647   }
    648   return pNewBitmap;
    649 }
    650 
    651 void CFX_DIBSource::BuildPalette() {
    652   if (m_pPalette)
    653     return;
    654 
    655   if (GetBPP() == 1) {
    656     m_pPalette.reset(FX_Alloc(uint32_t, 2));
    657     if (IsCmykImage()) {
    658       m_pPalette.get()[0] = 0xff;
    659       m_pPalette.get()[1] = 0;
    660     } else {
    661       m_pPalette.get()[0] = 0xff000000;
    662       m_pPalette.get()[1] = 0xffffffff;
    663     }
    664   } else if (GetBPP() == 8) {
    665     m_pPalette.reset(FX_Alloc(uint32_t, 256));
    666     if (IsCmykImage()) {
    667       for (int i = 0; i < 256; ++i)
    668         m_pPalette.get()[i] = 0xff - i;
    669     } else {
    670       for (int i = 0; i < 256; ++i)
    671         m_pPalette.get()[i] = 0xff000000 | (i * 0x10101);
    672     }
    673   }
    674 }
    675 
    676 bool CFX_DIBSource::BuildAlphaMask() {
    677   if (m_pAlphaMask)
    678     return true;
    679 
    680   m_pAlphaMask = pdfium::MakeRetain<CFX_DIBitmap>();
    681   if (!m_pAlphaMask->Create(m_Width, m_Height, FXDIB_8bppMask)) {
    682     m_pAlphaMask = nullptr;
    683     return false;
    684   }
    685   memset(m_pAlphaMask->GetBuffer(), 0xff,
    686          m_pAlphaMask->GetHeight() * m_pAlphaMask->GetPitch());
    687   return true;
    688 }
    689 
    690 uint32_t CFX_DIBSource::GetPaletteArgb(int index) const {
    691   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
    692   if (m_pPalette)
    693     return m_pPalette.get()[index];
    694 
    695   if (IsCmykImage()) {
    696     if (GetBPP() == 1)
    697       return index ? 0 : 0xff;
    698 
    699     return 0xff - index;
    700   }
    701   if (GetBPP() == 1)
    702     return index ? 0xffffffff : 0xff000000;
    703 
    704   return index * 0x10101 | 0xff000000;
    705 }
    706 
    707 void CFX_DIBSource::SetPaletteArgb(int index, uint32_t color) {
    708   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
    709   if (!m_pPalette) {
    710     BuildPalette();
    711   }
    712   m_pPalette.get()[index] = color;
    713 }
    714 
    715 int CFX_DIBSource::FindPalette(uint32_t color) const {
    716   ASSERT((GetBPP() == 1 || GetBPP() == 8) && !IsAlphaMask());
    717   if (!m_pPalette) {
    718     if (IsCmykImage()) {
    719       if (GetBPP() == 1)
    720         return (static_cast<uint8_t>(color) == 0xff) ? 0 : 1;
    721 
    722       return 0xff - static_cast<uint8_t>(color);
    723     }
    724     if (GetBPP() == 1)
    725       return (static_cast<uint8_t>(color) == 0xff) ? 1 : 0;
    726 
    727     return static_cast<uint8_t>(color);
    728   }
    729   int palsize = (1 << GetBPP());
    730   for (int i = 0; i < palsize; ++i) {
    731     if (m_pPalette.get()[i] == color)
    732       return i;
    733   }
    734   return -1;
    735 }
    736 
    737 void CFX_DIBSource::GetOverlapRect(int& dest_left,
    738                                    int& dest_top,
    739                                    int& width,
    740                                    int& height,
    741                                    int src_width,
    742                                    int src_height,
    743                                    int& src_left,
    744                                    int& src_top,
    745                                    const CFX_ClipRgn* pClipRgn) {
    746   if (width == 0 || height == 0)
    747     return;
    748 
    749   ASSERT(width > 0 && height > 0);
    750   if (dest_left > m_Width || dest_top > m_Height) {
    751     width = 0;
    752     height = 0;
    753     return;
    754   }
    755   int x_offset = dest_left - src_left;
    756   int y_offset = dest_top - src_top;
    757   FX_RECT src_rect(src_left, src_top, src_left + width, src_top + height);
    758   FX_RECT src_bound(0, 0, src_width, src_height);
    759   src_rect.Intersect(src_bound);
    760   FX_RECT dest_rect(src_rect.left + x_offset, src_rect.top + y_offset,
    761                     src_rect.right + x_offset, src_rect.bottom + y_offset);
    762   FX_RECT dest_bound(0, 0, m_Width, m_Height);
    763   dest_rect.Intersect(dest_bound);
    764   if (pClipRgn)
    765     dest_rect.Intersect(pClipRgn->GetBox());
    766   dest_left = dest_rect.left;
    767   dest_top = dest_rect.top;
    768   src_left = dest_left - x_offset;
    769   src_top = dest_top - y_offset;
    770   width = dest_rect.right - dest_rect.left;
    771   height = dest_rect.bottom - dest_rect.top;
    772 }
    773 
    774 void CFX_DIBSource::SetPalette(const uint32_t* pSrc) {
    775   static const uint32_t kPaletteSize = 256;
    776   if (!pSrc || GetBPP() > 8) {
    777     m_pPalette.reset();
    778     return;
    779   }
    780   uint32_t pal_size = 1 << GetBPP();
    781   if (!m_pPalette)
    782     m_pPalette.reset(FX_Alloc(uint32_t, pal_size));
    783   pal_size = std::min(pal_size, kPaletteSize);
    784   memcpy(m_pPalette.get(), pSrc, pal_size * sizeof(uint32_t));
    785 }
    786 
    787 void CFX_DIBSource::GetPalette(uint32_t* pal, int alpha) const {
    788   ASSERT(GetBPP() <= 8 && !IsCmykImage());
    789   if (GetBPP() == 1) {
    790     pal[0] = ((m_pPalette ? m_pPalette.get()[0] : 0xff000000) & 0xffffff) |
    791              (alpha << 24);
    792     pal[1] = ((m_pPalette ? m_pPalette.get()[1] : 0xffffffff) & 0xffffff) |
    793              (alpha << 24);
    794     return;
    795   }
    796   if (m_pPalette) {
    797     for (int i = 0; i < 256; ++i)
    798       pal[i] = (m_pPalette.get()[i] & 0x00ffffff) | (alpha << 24);
    799   } else {
    800     for (int i = 0; i < 256; ++i)
    801       pal[i] = (i * 0x10101) | (alpha << 24);
    802   }
    803 }
    804 
    805 RetainPtr<CFX_DIBitmap> CFX_DIBSource::CloneAlphaMask() const {
    806   ASSERT(GetFormat() == FXDIB_Argb);
    807   FX_RECT rect(0, 0, m_Width, m_Height);
    808   auto pMask = pdfium::MakeRetain<CFX_DIBitmap>();
    809   if (!pMask->Create(rect.Width(), rect.Height(), FXDIB_8bppMask))
    810     return nullptr;
    811 
    812   for (int row = rect.top; row < rect.bottom; ++row) {
    813     const uint8_t* src_scan = GetScanline(row) + rect.left * 4 + 3;
    814     uint8_t* dest_scan =
    815         const_cast<uint8_t*>(pMask->GetScanline(row - rect.top));
    816     for (int col = rect.left; col < rect.right; ++col) {
    817       *dest_scan++ = *src_scan;
    818       src_scan += 4;
    819     }
    820   }
    821   return pMask;
    822 }
    823 
    824 bool CFX_DIBSource::SetAlphaMask(const RetainPtr<CFX_DIBSource>& pAlphaMask,
    825                                  const FX_RECT* pClip) {
    826   if (!HasAlpha() || GetFormat() == FXDIB_Argb)
    827     return false;
    828 
    829   if (!pAlphaMask) {
    830     m_pAlphaMask->Clear(0xff000000);
    831     return true;
    832   }
    833   FX_RECT rect(0, 0, pAlphaMask->m_Width, pAlphaMask->m_Height);
    834   if (pClip) {
    835     rect.Intersect(*pClip);
    836     if (rect.IsEmpty() || rect.Width() != m_Width ||
    837         rect.Height() != m_Height) {
    838       return false;
    839     }
    840   } else {
    841     if (pAlphaMask->m_Width != m_Width || pAlphaMask->m_Height != m_Height)
    842       return false;
    843   }
    844   for (int row = 0; row < m_Height; ++row) {
    845     memcpy(const_cast<uint8_t*>(m_pAlphaMask->GetScanline(row)),
    846            pAlphaMask->GetScanline(row + rect.top) + rect.left,
    847            m_pAlphaMask->m_Pitch);
    848   }
    849   return true;
    850 }
    851 
    852 RetainPtr<CFX_DIBitmap> CFX_DIBSource::FlipImage(bool bXFlip,
    853                                                  bool bYFlip) const {
    854   auto pFlipped = pdfium::MakeRetain<CFX_DIBitmap>();
    855   if (!pFlipped->Create(m_Width, m_Height, GetFormat()))
    856     return nullptr;
    857 
    858   pFlipped->SetPalette(m_pPalette.get());
    859   uint8_t* pDestBuffer = pFlipped->GetBuffer();
    860   int Bpp = m_bpp / 8;
    861   for (int row = 0; row < m_Height; ++row) {
    862     const uint8_t* src_scan = GetScanline(row);
    863     uint8_t* dest_scan =
    864         pDestBuffer + m_Pitch * (bYFlip ? (m_Height - row - 1) : row);
    865     if (!bXFlip) {
    866       memcpy(dest_scan, src_scan, m_Pitch);
    867       continue;
    868     }
    869     if (m_bpp == 1) {
    870       memset(dest_scan, 0, m_Pitch);
    871       for (int col = 0; col < m_Width; ++col)
    872         if (src_scan[col / 8] & (1 << (7 - col % 8))) {
    873           int dest_col = m_Width - col - 1;
    874           dest_scan[dest_col / 8] |= (1 << (7 - dest_col % 8));
    875         }
    876     } else {
    877       dest_scan += (m_Width - 1) * Bpp;
    878       if (Bpp == 1) {
    879         for (int col = 0; col < m_Width; ++col) {
    880           *dest_scan = *src_scan;
    881           --dest_scan;
    882           ++src_scan;
    883         }
    884       } else if (Bpp == 3) {
    885         for (int col = 0; col < m_Width; ++col) {
    886           dest_scan[0] = src_scan[0];
    887           dest_scan[1] = src_scan[1];
    888           dest_scan[2] = src_scan[2];
    889           dest_scan -= 3;
    890           src_scan += 3;
    891         }
    892       } else {
    893         ASSERT(Bpp == 4);
    894         for (int col = 0; col < m_Width; ++col) {
    895           *(uint32_t*)dest_scan = *(uint32_t*)src_scan;
    896           dest_scan -= 4;
    897           src_scan += 4;
    898         }
    899       }
    900     }
    901   }
    902   if (m_pAlphaMask) {
    903     pDestBuffer = pFlipped->m_pAlphaMask->GetBuffer();
    904     uint32_t dest_pitch = pFlipped->m_pAlphaMask->GetPitch();
    905     for (int row = 0; row < m_Height; ++row) {
    906       const uint8_t* src_scan = m_pAlphaMask->GetScanline(row);
    907       uint8_t* dest_scan =
    908           pDestBuffer + dest_pitch * (bYFlip ? (m_Height - row - 1) : row);
    909       if (!bXFlip) {
    910         memcpy(dest_scan, src_scan, dest_pitch);
    911         continue;
    912       }
    913       dest_scan += (m_Width - 1);
    914       for (int col = 0; col < m_Width; ++col) {
    915         *dest_scan = *src_scan;
    916         --dest_scan;
    917         ++src_scan;
    918       }
    919     }
    920   }
    921   return pFlipped;
    922 }
    923 
    924 RetainPtr<CFX_DIBitmap> CFX_DIBSource::CloneConvert(FXDIB_Format dest_format) {
    925   if (dest_format == GetFormat())
    926     return Clone(nullptr);
    927 
    928   auto pClone = pdfium::MakeRetain<CFX_DIBitmap>();
    929   if (!pClone->Create(m_Width, m_Height, dest_format))
    930     return nullptr;
    931 
    932   RetainPtr<CFX_DIBitmap> pSrcAlpha;
    933   if (HasAlpha()) {
    934     if (GetFormat() == FXDIB_Argb)
    935       pSrcAlpha = CloneAlphaMask();
    936     else
    937       pSrcAlpha = m_pAlphaMask;
    938 
    939     if (!pSrcAlpha)
    940       return nullptr;
    941   }
    942   bool ret = true;
    943   if (dest_format & 0x0200) {
    944     if (dest_format == FXDIB_Argb) {
    945       ret = pSrcAlpha ? pClone->LoadChannel(FXDIB_Alpha, pSrcAlpha, FXDIB_Alpha)
    946                       : pClone->LoadChannel(FXDIB_Alpha, 0xff);
    947     } else {
    948       ret = pClone->SetAlphaMask(pSrcAlpha, nullptr);
    949     }
    950   }
    951   if (!ret)
    952     return nullptr;
    953 
    954   RetainPtr<CFX_DIBSource> holder(this);
    955   std::unique_ptr<uint32_t, FxFreeDeleter> pal_8bpp;
    956   if (!ConvertBuffer(dest_format, pClone->GetBuffer(), pClone->GetPitch(),
    957                      m_Width, m_Height, holder, 0, 0, &pal_8bpp)) {
    958     return nullptr;
    959   }
    960   if (pal_8bpp)
    961     pClone->SetPalette(pal_8bpp.get());
    962 
    963   return pClone;
    964 }
    965 
    966 RetainPtr<CFX_DIBitmap> CFX_DIBSource::SwapXY(bool bXFlip, bool bYFlip) const {
    967   FX_RECT dest_clip(0, 0, m_Height, m_Width);
    968   if (dest_clip.IsEmpty())
    969     return nullptr;
    970 
    971   auto pTransBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
    972   int result_height = dest_clip.Height();
    973   int result_width = dest_clip.Width();
    974   if (!pTransBitmap->Create(result_width, result_height, GetFormat()))
    975     return nullptr;
    976 
    977   pTransBitmap->SetPalette(m_pPalette.get());
    978   int dest_pitch = pTransBitmap->GetPitch();
    979   uint8_t* dest_buf = pTransBitmap->GetBuffer();
    980   int row_start = bXFlip ? m_Height - dest_clip.right : dest_clip.left;
    981   int row_end = bXFlip ? m_Height - dest_clip.left : dest_clip.right;
    982   int col_start = bYFlip ? m_Width - dest_clip.bottom : dest_clip.top;
    983   int col_end = bYFlip ? m_Width - dest_clip.top : dest_clip.bottom;
    984   if (GetBPP() == 1) {
    985     memset(dest_buf, 0xff, dest_pitch * result_height);
    986     for (int row = row_start; row < row_end; ++row) {
    987       const uint8_t* src_scan = GetScanline(row);
    988       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
    989                      dest_clip.left;
    990       uint8_t* dest_scan = dest_buf;
    991       if (bYFlip)
    992         dest_scan += (result_height - 1) * dest_pitch;
    993       int dest_step = bYFlip ? -dest_pitch : dest_pitch;
    994       for (int col = col_start; col < col_end; ++col) {
    995         if (!(src_scan[col / 8] & (1 << (7 - col % 8))))
    996           dest_scan[dest_col / 8] &= ~(1 << (7 - dest_col % 8));
    997         dest_scan += dest_step;
    998       }
    999     }
   1000   } else {
   1001     int nBytes = GetBPP() / 8;
   1002     int dest_step = bYFlip ? -dest_pitch : dest_pitch;
   1003     if (nBytes == 3)
   1004       dest_step -= 2;
   1005     for (int row = row_start; row < row_end; ++row) {
   1006       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
   1007                      dest_clip.left;
   1008       uint8_t* dest_scan = dest_buf + dest_col * nBytes;
   1009       if (bYFlip)
   1010         dest_scan += (result_height - 1) * dest_pitch;
   1011       if (nBytes == 4) {
   1012         uint32_t* src_scan = (uint32_t*)GetScanline(row) + col_start;
   1013         for (int col = col_start; col < col_end; ++col) {
   1014           *(uint32_t*)dest_scan = *src_scan++;
   1015           dest_scan += dest_step;
   1016         }
   1017       } else {
   1018         const uint8_t* src_scan = GetScanline(row) + col_start * nBytes;
   1019         if (nBytes == 1) {
   1020           for (int col = col_start; col < col_end; ++col) {
   1021             *dest_scan = *src_scan++;
   1022             dest_scan += dest_step;
   1023           }
   1024         } else {
   1025           for (int col = col_start; col < col_end; ++col) {
   1026             *dest_scan++ = *src_scan++;
   1027             *dest_scan++ = *src_scan++;
   1028             *dest_scan = *src_scan++;
   1029             dest_scan += dest_step;
   1030           }
   1031         }
   1032       }
   1033     }
   1034   }
   1035   if (m_pAlphaMask) {
   1036     dest_pitch = pTransBitmap->m_pAlphaMask->GetPitch();
   1037     dest_buf = pTransBitmap->m_pAlphaMask->GetBuffer();
   1038     int dest_step = bYFlip ? -dest_pitch : dest_pitch;
   1039     for (int row = row_start; row < row_end; ++row) {
   1040       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
   1041                      dest_clip.left;
   1042       uint8_t* dest_scan = dest_buf + dest_col;
   1043       if (bYFlip)
   1044         dest_scan += (result_height - 1) * dest_pitch;
   1045       const uint8_t* src_scan = m_pAlphaMask->GetScanline(row) + col_start;
   1046       for (int col = col_start; col < col_end; ++col) {
   1047         *dest_scan = *src_scan++;
   1048         dest_scan += dest_step;
   1049       }
   1050     }
   1051   }
   1052   return pTransBitmap;
   1053 }
   1054 
   1055 RetainPtr<CFX_DIBitmap> CFX_DIBSource::TransformTo(
   1056     const CFX_Matrix* pDestMatrix,
   1057     int* result_left,
   1058     int* result_top) {
   1059   RetainPtr<CFX_DIBSource> holder(this);
   1060   CFX_ImageTransformer transformer(holder, pDestMatrix, 0, nullptr);
   1061   transformer.Continue(nullptr);
   1062   *result_left = transformer.result().left;
   1063   *result_top = transformer.result().top;
   1064   return transformer.DetachBitmap();
   1065 }
   1066 
   1067 RetainPtr<CFX_DIBitmap> CFX_DIBSource::StretchTo(int dest_width,
   1068                                                  int dest_height,
   1069                                                  uint32_t flags,
   1070                                                  const FX_RECT* pClip) {
   1071   RetainPtr<CFX_DIBSource> holder(this);
   1072   FX_RECT clip_rect(0, 0, abs(dest_width), abs(dest_height));
   1073   if (pClip)
   1074     clip_rect.Intersect(*pClip);
   1075 
   1076   if (clip_rect.IsEmpty())
   1077     return nullptr;
   1078 
   1079   if (dest_width == m_Width && dest_height == m_Height)
   1080     return Clone(&clip_rect);
   1081 
   1082   CFX_BitmapStorer storer;
   1083   CFX_ImageStretcher stretcher(&storer, holder, dest_width, dest_height,
   1084                                clip_rect, flags);
   1085   if (stretcher.Start())
   1086     stretcher.Continue(nullptr);
   1087 
   1088   return storer.Detach();
   1089 }
   1090 
   1091 // static
   1092 bool CFX_DIBSource::ConvertBuffer(
   1093     FXDIB_Format dest_format,
   1094     uint8_t* dest_buf,
   1095     int dest_pitch,
   1096     int width,
   1097     int height,
   1098     const RetainPtr<CFX_DIBSource>& pSrcBitmap,
   1099     int src_left,
   1100     int src_top,
   1101     std::unique_ptr<uint32_t, FxFreeDeleter>* p_pal) {
   1102   FXDIB_Format src_format = pSrcBitmap->GetFormat();
   1103   switch (dest_format) {
   1104     case FXDIB_Invalid:
   1105     case FXDIB_1bppCmyk:
   1106     case FXDIB_1bppMask:
   1107     case FXDIB_1bppRgb:
   1108       NOTREACHED();
   1109       return false;
   1110     case FXDIB_8bppMask: {
   1111       if ((src_format & 0xff) == 1) {
   1112         if (pSrcBitmap->GetPalette()) {
   1113           ConvertBuffer_1bppPlt2Gray(dest_buf, dest_pitch, width, height,
   1114                                      pSrcBitmap, src_left, src_top);
   1115           return true;
   1116         }
   1117         ConvertBuffer_1bppMask2Gray(dest_buf, dest_pitch, width, height,
   1118                                     pSrcBitmap, src_left, src_top);
   1119         return true;
   1120       }
   1121       if ((src_format & 0xff) == 8) {
   1122         if (pSrcBitmap->GetPalette()) {
   1123           ConvertBuffer_8bppPlt2Gray(dest_buf, dest_pitch, width, height,
   1124                                      pSrcBitmap, src_left, src_top);
   1125           return true;
   1126         }
   1127         ConvertBuffer_8bppMask2Gray(dest_buf, dest_pitch, width, height,
   1128                                     pSrcBitmap, src_left, src_top);
   1129         return true;
   1130       }
   1131       if ((src_format & 0xff) >= 24) {
   1132         ConvertBuffer_RgbOrCmyk2Gray(dest_buf, dest_pitch, width, height,
   1133                                      pSrcBitmap, src_left, src_top);
   1134         return true;
   1135       }
   1136       return false;
   1137     }
   1138     case FXDIB_8bppRgb:
   1139     case FXDIB_8bppRgba: {
   1140       if ((src_format & 0xff) == 8 && !pSrcBitmap->GetPalette()) {
   1141         return ConvertBuffer(FXDIB_8bppMask, dest_buf, dest_pitch, width,
   1142                              height, pSrcBitmap, src_left, src_top, p_pal);
   1143       }
   1144       p_pal->reset(FX_Alloc(uint32_t, 256));
   1145       if (((src_format & 0xff) == 1 || (src_format & 0xff) == 8) &&
   1146           pSrcBitmap->GetPalette()) {
   1147         ConvertBuffer_Plt2PltRgb8(dest_buf, dest_pitch, width, height,
   1148                                   pSrcBitmap, src_left, src_top, p_pal->get());
   1149         return true;
   1150       }
   1151       if ((src_format & 0xff) >= 24) {
   1152         ConvertBuffer_Rgb2PltRgb8(dest_buf, dest_pitch, width, height,
   1153                                   pSrcBitmap, src_left, src_top, p_pal->get());
   1154         return true;
   1155       }
   1156       return false;
   1157     }
   1158     case FXDIB_Rgb:
   1159     case FXDIB_Rgba: {
   1160       if ((src_format & 0xff) == 1) {
   1161         if (pSrcBitmap->GetPalette()) {
   1162           ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
   1163                                     height, pSrcBitmap, src_left, src_top);
   1164           return true;
   1165         }
   1166         ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
   1167                                    height, pSrcBitmap, src_left, src_top);
   1168         return true;
   1169       }
   1170       if ((src_format & 0xff) == 8) {
   1171         if (pSrcBitmap->GetPalette()) {
   1172           ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
   1173                                     height, pSrcBitmap, src_left, src_top);
   1174           return true;
   1175         }
   1176         ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
   1177                                    height, pSrcBitmap, src_left, src_top);
   1178         return true;
   1179       }
   1180       if ((src_format & 0xff) == 24) {
   1181         ConvertBuffer_24bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
   1182                                      pSrcBitmap, src_left, src_top);
   1183         return true;
   1184       }
   1185       if ((src_format & 0xff) == 32) {
   1186         ConvertBuffer_32bppRgb2Rgb24(dest_buf, dest_pitch, width, height,
   1187                                      pSrcBitmap, src_left, src_top);
   1188         return true;
   1189       }
   1190       return false;
   1191     }
   1192     case FXDIB_Argb:
   1193     case FXDIB_Rgb32: {
   1194       if ((src_format & 0xff) == 1) {
   1195         if (pSrcBitmap->GetPalette()) {
   1196           ConvertBuffer_1bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
   1197                                     height, pSrcBitmap, src_left, src_top);
   1198           return true;
   1199         }
   1200         ConvertBuffer_1bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
   1201                                    height, pSrcBitmap, src_left, src_top);
   1202         return true;
   1203       }
   1204       if ((src_format & 0xff) == 8) {
   1205         if (pSrcBitmap->GetPalette()) {
   1206           ConvertBuffer_8bppPlt2Rgb(dest_format, dest_buf, dest_pitch, width,
   1207                                     height, pSrcBitmap, src_left, src_top);
   1208           return true;
   1209         }
   1210         ConvertBuffer_8bppMask2Rgb(dest_format, dest_buf, dest_pitch, width,
   1211                                    height, pSrcBitmap, src_left, src_top);
   1212         return true;
   1213       }
   1214       if ((src_format & 0xff) >= 24) {
   1215         if (src_format & 0x0400) {
   1216           ConvertBuffer_32bppCmyk2Rgb32(dest_buf, dest_pitch, width, height,
   1217                                         pSrcBitmap, src_left, src_top);
   1218           return true;
   1219         }
   1220         ConvertBuffer_Rgb2Rgb32(dest_buf, dest_pitch, width, height, pSrcBitmap,
   1221                                 src_left, src_top);
   1222         return true;
   1223       }
   1224       return false;
   1225     }
   1226     default:
   1227       return false;
   1228   }
   1229 }
   1230