Home | History | Annotate | Download | only in dib
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fxge/dib/dib_int.h"
      8 
      9 #include <memory>
     10 #include <utility>
     11 
     12 #include "core/fxge/fx_dib.h"
     13 #include "third_party/base/ptr_util.h"
     14 
     15 namespace {
     16 
     17 uint8_t bilinear_interpol(const uint8_t* buf,
     18                           int row_offset_l,
     19                           int row_offset_r,
     20                           int src_col_l,
     21                           int src_col_r,
     22                           int res_x,
     23                           int res_y,
     24                           int bpp,
     25                           int c_offset) {
     26   int i_resx = 255 - res_x;
     27   int col_bpp_l = src_col_l * bpp;
     28   int col_bpp_r = src_col_r * bpp;
     29   const uint8_t* buf_u = buf + row_offset_l + c_offset;
     30   const uint8_t* buf_d = buf + row_offset_r + c_offset;
     31   const uint8_t* src_pos0 = buf_u + col_bpp_l;
     32   const uint8_t* src_pos1 = buf_u + col_bpp_r;
     33   const uint8_t* src_pos2 = buf_d + col_bpp_l;
     34   const uint8_t* src_pos3 = buf_d + col_bpp_r;
     35   uint8_t r_pos_0 = (*src_pos0 * i_resx + *src_pos1 * res_x) >> 8;
     36   uint8_t r_pos_1 = (*src_pos2 * i_resx + *src_pos3 * res_x) >> 8;
     37   return (r_pos_0 * (255 - res_y) + r_pos_1 * res_y) >> 8;
     38 }
     39 
     40 uint8_t bicubic_interpol(const uint8_t* buf,
     41                          int pitch,
     42                          int pos_pixel[],
     43                          int u_w[],
     44                          int v_w[],
     45                          int res_x,
     46                          int res_y,
     47                          int bpp,
     48                          int c_offset) {
     49   int s_result = 0;
     50   for (int i = 0; i < 4; i++) {
     51     int a_result = 0;
     52     for (int j = 0; j < 4; j++) {
     53       a_result += u_w[j] * (*(uint8_t*)(buf + pos_pixel[i + 4] * pitch +
     54                                         pos_pixel[j] * bpp + c_offset));
     55     }
     56     s_result += a_result * v_w[i];
     57   }
     58   s_result >>= 16;
     59   return (uint8_t)(s_result < 0 ? 0 : s_result > 255 ? 255 : s_result);
     60 }
     61 
     62 void bicubic_get_pos_weight(int pos_pixel[],
     63                             int u_w[],
     64                             int v_w[],
     65                             int src_col_l,
     66                             int src_row_l,
     67                             int res_x,
     68                             int res_y,
     69                             int stretch_width,
     70                             int stretch_height) {
     71   pos_pixel[0] = src_col_l - 1;
     72   pos_pixel[1] = src_col_l;
     73   pos_pixel[2] = src_col_l + 1;
     74   pos_pixel[3] = src_col_l + 2;
     75   pos_pixel[4] = src_row_l - 1;
     76   pos_pixel[5] = src_row_l;
     77   pos_pixel[6] = src_row_l + 1;
     78   pos_pixel[7] = src_row_l + 2;
     79   for (int i = 0; i < 4; i++) {
     80     if (pos_pixel[i] < 0) {
     81       pos_pixel[i] = 0;
     82     }
     83     if (pos_pixel[i] >= stretch_width) {
     84       pos_pixel[i] = stretch_width - 1;
     85     }
     86     if (pos_pixel[i + 4] < 0) {
     87       pos_pixel[i + 4] = 0;
     88     }
     89     if (pos_pixel[i + 4] >= stretch_height) {
     90       pos_pixel[i + 4] = stretch_height - 1;
     91     }
     92   }
     93   u_w[0] = SDP_Table[256 + res_x];
     94   u_w[1] = SDP_Table[res_x];
     95   u_w[2] = SDP_Table[256 - res_x];
     96   u_w[3] = SDP_Table[512 - res_x];
     97   v_w[0] = SDP_Table[256 + res_y];
     98   v_w[1] = SDP_Table[res_y];
     99   v_w[2] = SDP_Table[256 - res_y];
    100   v_w[3] = SDP_Table[512 - res_y];
    101 }
    102 
    103 FXDIB_Format GetTransformedFormat(const CFX_DIBSource* pDrc) {
    104   FXDIB_Format format = pDrc->GetFormat();
    105   if (pDrc->IsAlphaMask()) {
    106     format = FXDIB_8bppMask;
    107   } else if (format >= 1025) {
    108     format = FXDIB_Cmyka;
    109   } else if (format <= 32 || format == FXDIB_Argb) {
    110     format = FXDIB_Argb;
    111   } else {
    112     format = FXDIB_Rgba;
    113   }
    114   return format;
    115 }
    116 
    117 }  // namespace
    118 
    119 const int16_t SDP_Table[513] = {
    120     256, 256, 256, 256, 256, 256, 256, 256, 256, 255, 255, 255, 255, 255, 255,
    121     254, 254, 254, 254, 253, 253, 253, 252, 252, 252, 251, 251, 251, 250, 250,
    122     249, 249, 249, 248, 248, 247, 247, 246, 246, 245, 244, 244, 243, 243, 242,
    123     242, 241, 240, 240, 239, 238, 238, 237, 236, 236, 235, 234, 233, 233, 232,
    124     231, 230, 230, 229, 228, 227, 226, 226, 225, 224, 223, 222, 221, 220, 219,
    125     218, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205,
    126     204, 203, 202, 201, 200, 199, 198, 196, 195, 194, 193, 192, 191, 190, 189,
    127     188, 186, 185, 184, 183, 182, 181, 179, 178, 177, 176, 175, 173, 172, 171,
    128     170, 169, 167, 166, 165, 164, 162, 161, 160, 159, 157, 156, 155, 154, 152,
    129     151, 150, 149, 147, 146, 145, 143, 142, 141, 140, 138, 137, 136, 134, 133,
    130     132, 130, 129, 128, 126, 125, 124, 122, 121, 120, 119, 117, 116, 115, 113,
    131     112, 111, 109, 108, 107, 105, 104, 103, 101, 100, 99,  97,  96,  95,  93,
    132     92,  91,  89,  88,  87,  85,  84,  83,  81,  80,  79,  77,  76,  75,  73,
    133     72,  71,  69,  68,  67,  66,  64,  63,  62,  60,  59,  58,  57,  55,  54,
    134     53,  52,  50,  49,  48,  47,  45,  44,  43,  42,  40,  39,  38,  37,  36,
    135     34,  33,  32,  31,  30,  28,  27,  26,  25,  24,  23,  21,  20,  19,  18,
    136     17,  16,  15,  14,  13,  11,  10,  9,   8,   7,   6,   5,   4,   3,   2,
    137     1,   0,   0,   -1,  -2,  -3,  -4,  -5,  -6,  -7,  -7,  -8,  -9,  -10, -11,
    138     -12, -12, -13, -14, -15, -15, -16, -17, -17, -18, -19, -19, -20, -21, -21,
    139     -22, -22, -23, -24, -24, -25, -25, -26, -26, -27, -27, -27, -28, -28, -29,
    140     -29, -30, -30, -30, -31, -31, -31, -32, -32, -32, -33, -33, -33, -33, -34,
    141     -34, -34, -34, -35, -35, -35, -35, -35, -36, -36, -36, -36, -36, -36, -36,
    142     -36, -36, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, -37,
    143     -37, -37, -37, -37, -37, -37, -37, -37, -36, -36, -36, -36, -36, -36, -36,
    144     -36, -36, -35, -35, -35, -35, -35, -35, -34, -34, -34, -34, -34, -33, -33,
    145     -33, -33, -33, -32, -32, -32, -32, -31, -31, -31, -31, -30, -30, -30, -30,
    146     -29, -29, -29, -29, -28, -28, -28, -27, -27, -27, -27, -26, -26, -26, -25,
    147     -25, -25, -24, -24, -24, -23, -23, -23, -22, -22, -22, -22, -21, -21, -21,
    148     -20, -20, -20, -19, -19, -19, -18, -18, -18, -17, -17, -17, -16, -16, -16,
    149     -15, -15, -15, -14, -14, -14, -13, -13, -13, -12, -12, -12, -11, -11, -11,
    150     -10, -10, -10, -9,  -9,  -9,  -9,  -8,  -8,  -8,  -7,  -7,  -7,  -7,  -6,
    151     -6,  -6,  -6,  -5,  -5,  -5,  -5,  -4,  -4,  -4,  -4,  -3,  -3,  -3,  -3,
    152     -3,  -2,  -2,  -2,  -2,  -2,  -1,  -1,  -1,  -1,  -1,  -1,  0,   0,   0,
    153     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    154     0,   0,   0,
    155 };
    156 
    157 class CFX_BilinearMatrix : public CPDF_FixedMatrix {
    158  public:
    159   CFX_BilinearMatrix(const CFX_Matrix& src, int bits)
    160       : CPDF_FixedMatrix(src, bits) {}
    161   inline void Transform(int x,
    162                         int y,
    163                         int& x1,
    164                         int& y1,
    165                         int& res_x,
    166                         int& res_y) {
    167     x1 = a * x + c * y + e + base / 2;
    168     y1 = b * x + d * y + f + base / 2;
    169     res_x = x1 % base;
    170     res_y = y1 % base;
    171     if (res_x < 0 && res_x > -base) {
    172       res_x = base + res_x;
    173     }
    174     if (res_y < 0 && res_x > -base) {
    175       res_y = base + res_y;
    176     }
    177     x1 /= base;
    178     y1 /= base;
    179   }
    180 };
    181 
    182 std::unique_ptr<CFX_DIBitmap> CFX_DIBSource::SwapXY(
    183     bool bXFlip,
    184     bool bYFlip,
    185     const FX_RECT* pDestClip) const {
    186   FX_RECT dest_clip(0, 0, m_Height, m_Width);
    187   if (pDestClip)
    188     dest_clip.Intersect(*pDestClip);
    189   if (dest_clip.IsEmpty())
    190     return nullptr;
    191 
    192   auto pTransBitmap = pdfium::MakeUnique<CFX_DIBitmap>();
    193   int result_height = dest_clip.Height();
    194   int result_width = dest_clip.Width();
    195   if (!pTransBitmap->Create(result_width, result_height, GetFormat()))
    196     return nullptr;
    197 
    198   pTransBitmap->SetPalette(m_pPalette.get());
    199   int dest_pitch = pTransBitmap->GetPitch();
    200   uint8_t* dest_buf = pTransBitmap->GetBuffer();
    201   int row_start = bXFlip ? m_Height - dest_clip.right : dest_clip.left;
    202   int row_end = bXFlip ? m_Height - dest_clip.left : dest_clip.right;
    203   int col_start = bYFlip ? m_Width - dest_clip.bottom : dest_clip.top;
    204   int col_end = bYFlip ? m_Width - dest_clip.top : dest_clip.bottom;
    205   if (GetBPP() == 1) {
    206     FXSYS_memset(dest_buf, 0xff, dest_pitch * result_height);
    207     for (int row = row_start; row < row_end; row++) {
    208       const uint8_t* src_scan = GetScanline(row);
    209       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
    210                      dest_clip.left;
    211       uint8_t* dest_scan = dest_buf;
    212       if (bYFlip) {
    213         dest_scan += (result_height - 1) * dest_pitch;
    214       }
    215       int dest_step = bYFlip ? -dest_pitch : dest_pitch;
    216       for (int col = col_start; col < col_end; col++) {
    217         if (!(src_scan[col / 8] & (1 << (7 - col % 8)))) {
    218           dest_scan[dest_col / 8] &= ~(1 << (7 - dest_col % 8));
    219         }
    220         dest_scan += dest_step;
    221       }
    222     }
    223   } else {
    224     int nBytes = GetBPP() / 8;
    225     int dest_step = bYFlip ? -dest_pitch : dest_pitch;
    226     if (nBytes == 3) {
    227       dest_step -= 2;
    228     }
    229     for (int row = row_start; row < row_end; row++) {
    230       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
    231                      dest_clip.left;
    232       uint8_t* dest_scan = dest_buf + dest_col * nBytes;
    233       if (bYFlip) {
    234         dest_scan += (result_height - 1) * dest_pitch;
    235       }
    236       if (nBytes == 4) {
    237         uint32_t* src_scan = (uint32_t*)GetScanline(row) + col_start;
    238         for (int col = col_start; col < col_end; col++) {
    239           *(uint32_t*)dest_scan = *src_scan++;
    240           dest_scan += dest_step;
    241         }
    242       } else {
    243         const uint8_t* src_scan = GetScanline(row) + col_start * nBytes;
    244         if (nBytes == 1) {
    245           for (int col = col_start; col < col_end; col++) {
    246             *dest_scan = *src_scan++;
    247             dest_scan += dest_step;
    248           }
    249         } else {
    250           for (int col = col_start; col < col_end; col++) {
    251             *dest_scan++ = *src_scan++;
    252             *dest_scan++ = *src_scan++;
    253             *dest_scan = *src_scan++;
    254             dest_scan += dest_step;
    255           }
    256         }
    257       }
    258     }
    259   }
    260   if (m_pAlphaMask) {
    261     dest_pitch = pTransBitmap->m_pAlphaMask->GetPitch();
    262     dest_buf = pTransBitmap->m_pAlphaMask->GetBuffer();
    263     int dest_step = bYFlip ? -dest_pitch : dest_pitch;
    264     for (int row = row_start; row < row_end; row++) {
    265       int dest_col = (bXFlip ? dest_clip.right - (row - row_start) - 1 : row) -
    266                      dest_clip.left;
    267       uint8_t* dest_scan = dest_buf + dest_col;
    268       if (bYFlip) {
    269         dest_scan += (result_height - 1) * dest_pitch;
    270       }
    271       const uint8_t* src_scan = m_pAlphaMask->GetScanline(row) + col_start;
    272       for (int col = col_start; col < col_end; col++) {
    273         *dest_scan = *src_scan++;
    274         dest_scan += dest_step;
    275       }
    276     }
    277   }
    278   return pTransBitmap;
    279 }
    280 
    281 #define FIX16_005 0.05f
    282 FX_RECT FXDIB_SwapClipBox(FX_RECT& clip,
    283                           int width,
    284                           int height,
    285                           bool bFlipX,
    286                           bool bFlipY) {
    287   FX_RECT rect;
    288   if (bFlipY) {
    289     rect.left = height - clip.top;
    290     rect.right = height - clip.bottom;
    291   } else {
    292     rect.left = clip.top;
    293     rect.right = clip.bottom;
    294   }
    295   if (bFlipX) {
    296     rect.top = width - clip.left;
    297     rect.bottom = width - clip.right;
    298   } else {
    299     rect.top = clip.left;
    300     rect.bottom = clip.right;
    301   }
    302   rect.Normalize();
    303   return rect;
    304 }
    305 
    306 std::unique_ptr<CFX_DIBitmap> CFX_DIBSource::TransformTo(
    307     const CFX_Matrix* pDestMatrix,
    308     int& result_left,
    309     int& result_top,
    310     uint32_t flags,
    311     const FX_RECT* pDestClip) const {
    312   CFX_ImageTransformer transformer(this, pDestMatrix, flags, pDestClip);
    313   transformer.Start();
    314   transformer.Continue(nullptr);
    315   result_left = transformer.result().left;
    316   result_top = transformer.result().top;
    317   return transformer.DetachBitmap();
    318 }
    319 
    320 std::unique_ptr<CFX_DIBitmap> CFX_DIBSource::StretchTo(
    321     int dest_width,
    322     int dest_height,
    323     uint32_t flags,
    324     const FX_RECT* pClip) const {
    325   FX_RECT clip_rect(0, 0, FXSYS_abs(dest_width), FXSYS_abs(dest_height));
    326   if (pClip)
    327     clip_rect.Intersect(*pClip);
    328 
    329   if (clip_rect.IsEmpty())
    330     return nullptr;
    331 
    332   if (dest_width == m_Width && dest_height == m_Height)
    333     return Clone(&clip_rect);
    334 
    335   CFX_BitmapStorer storer;
    336   CFX_ImageStretcher stretcher(&storer, this, dest_width, dest_height,
    337                                clip_rect, flags);
    338   if (stretcher.Start())
    339     stretcher.Continue(nullptr);
    340 
    341   return storer.Detach();
    342 }
    343 
    344 CFX_ImageTransformer::CFX_ImageTransformer(const CFX_DIBSource* pSrc,
    345                                            const CFX_Matrix* pMatrix,
    346                                            int flags,
    347                                            const FX_RECT* pClip)
    348     : m_pSrc(pSrc),
    349       m_pMatrix(pMatrix),
    350       m_pClip(pClip),
    351       m_Flags(flags),
    352       m_Status(0) {}
    353 
    354 CFX_ImageTransformer::~CFX_ImageTransformer() {}
    355 
    356 bool CFX_ImageTransformer::Start() {
    357   CFX_FloatRect unit_rect = m_pMatrix->GetUnitRect();
    358   FX_RECT result_rect = unit_rect.GetClosestRect();
    359   FX_RECT result_clip = result_rect;
    360   if (m_pClip)
    361     result_clip.Intersect(*m_pClip);
    362 
    363   if (result_clip.IsEmpty())
    364     return false;
    365 
    366   m_result = result_clip;
    367   if (FXSYS_fabs(m_pMatrix->a) < FXSYS_fabs(m_pMatrix->b) / 20 &&
    368       FXSYS_fabs(m_pMatrix->d) < FXSYS_fabs(m_pMatrix->c) / 20 &&
    369       FXSYS_fabs(m_pMatrix->a) < 0.5f && FXSYS_fabs(m_pMatrix->d) < 0.5f) {
    370     int dest_width = result_rect.Width();
    371     int dest_height = result_rect.Height();
    372     result_clip.Offset(-result_rect.left, -result_rect.top);
    373     result_clip = FXDIB_SwapClipBox(result_clip, dest_width, dest_height,
    374                                     m_pMatrix->c > 0, m_pMatrix->b < 0);
    375     m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
    376         &m_Storer, m_pSrc, dest_height, dest_width, result_clip, m_Flags);
    377     m_Stretcher->Start();
    378     m_Status = 1;
    379     return true;
    380   }
    381   if (FXSYS_fabs(m_pMatrix->b) < FIX16_005 &&
    382       FXSYS_fabs(m_pMatrix->c) < FIX16_005) {
    383     int dest_width = m_pMatrix->a > 0 ? (int)FXSYS_ceil(m_pMatrix->a)
    384                                       : (int)FXSYS_floor(m_pMatrix->a);
    385     int dest_height = m_pMatrix->d > 0 ? (int)-FXSYS_ceil(m_pMatrix->d)
    386                                        : (int)-FXSYS_floor(m_pMatrix->d);
    387     result_clip.Offset(-result_rect.left, -result_rect.top);
    388     m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
    389         &m_Storer, m_pSrc, dest_width, dest_height, result_clip, m_Flags);
    390     m_Stretcher->Start();
    391     m_Status = 2;
    392     return true;
    393   }
    394   int stretch_width = (int)FXSYS_ceil(FXSYS_sqrt2(m_pMatrix->a, m_pMatrix->b));
    395   int stretch_height = (int)FXSYS_ceil(FXSYS_sqrt2(m_pMatrix->c, m_pMatrix->d));
    396   CFX_Matrix stretch2dest(1.0f, 0.0f, 0.0f, -1.0f, 0.0f,
    397                           (FX_FLOAT)(stretch_height));
    398   stretch2dest.Concat(
    399       CFX_Matrix(m_pMatrix->a / stretch_width, m_pMatrix->b / stretch_width,
    400                  m_pMatrix->c / stretch_height, m_pMatrix->d / stretch_height,
    401                  m_pMatrix->e, m_pMatrix->f));
    402   m_dest2stretch.SetReverse(stretch2dest);
    403 
    404   CFX_FloatRect clip_rect_f(result_clip);
    405   m_dest2stretch.TransformRect(clip_rect_f);
    406   m_StretchClip = clip_rect_f.GetOuterRect();
    407   m_StretchClip.Intersect(0, 0, stretch_width, stretch_height);
    408   m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
    409       &m_Storer, m_pSrc, stretch_width, stretch_height, m_StretchClip, m_Flags);
    410   m_Stretcher->Start();
    411   m_Status = 3;
    412   return true;
    413 }
    414 
    415 bool CFX_ImageTransformer::Continue(IFX_Pause* pPause) {
    416   if (m_Status == 1) {
    417     if (m_Stretcher->Continue(pPause))
    418       return true;
    419 
    420     if (m_Storer.GetBitmap()) {
    421       m_Storer.Replace(
    422           m_Storer.GetBitmap()->SwapXY(m_pMatrix->c > 0, m_pMatrix->b < 0));
    423     }
    424     return false;
    425   }
    426 
    427   if (m_Status == 2)
    428     return m_Stretcher->Continue(pPause);
    429 
    430   if (m_Status != 3)
    431     return false;
    432 
    433   if (m_Stretcher->Continue(pPause))
    434     return true;
    435 
    436   int stretch_width = m_StretchClip.Width();
    437   int stretch_height = m_StretchClip.Height();
    438   if (!m_Storer.GetBitmap())
    439     return false;
    440 
    441   const uint8_t* stretch_buf = m_Storer.GetBitmap()->GetBuffer();
    442   const uint8_t* stretch_buf_mask = nullptr;
    443   if (m_Storer.GetBitmap()->m_pAlphaMask)
    444     stretch_buf_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetBuffer();
    445 
    446   int stretch_pitch = m_Storer.GetBitmap()->GetPitch();
    447   std::unique_ptr<CFX_DIBitmap> pTransformed(new CFX_DIBitmap);
    448   FXDIB_Format transformF = GetTransformedFormat(m_Stretcher->source());
    449   if (!pTransformed->Create(m_result.Width(), m_result.Height(), transformF))
    450     return false;
    451 
    452   pTransformed->Clear(0);
    453   if (pTransformed->m_pAlphaMask)
    454     pTransformed->m_pAlphaMask->Clear(0);
    455 
    456   CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, (FX_FLOAT)(m_result.left),
    457                             (FX_FLOAT)(m_result.top));
    458   result2stretch.Concat(m_dest2stretch);
    459   result2stretch.Translate(-m_StretchClip.left, -m_StretchClip.top);
    460   if (!stretch_buf_mask && pTransformed->m_pAlphaMask) {
    461     pTransformed->m_pAlphaMask->Clear(0xff000000);
    462   } else if (pTransformed->m_pAlphaMask) {
    463     int stretch_pitch_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetPitch();
    464     if (!(m_Flags & FXDIB_DOWNSAMPLE) && !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
    465       CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
    466       for (int row = 0; row < m_result.Height(); row++) {
    467         uint8_t* dest_pos_mask =
    468             (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
    469         for (int col = 0; col < m_result.Width(); col++) {
    470           int src_col_l, src_row_l, res_x, res_y;
    471           result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
    472                                        res_y);
    473           if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
    474               src_row_l <= stretch_height) {
    475             if (src_col_l == stretch_width) {
    476               src_col_l--;
    477             }
    478             if (src_row_l == stretch_height) {
    479               src_row_l--;
    480             }
    481             int src_col_r = src_col_l + 1;
    482             int src_row_r = src_row_l + 1;
    483             if (src_col_r == stretch_width) {
    484               src_col_r--;
    485             }
    486             if (src_row_r == stretch_height) {
    487               src_row_r--;
    488             }
    489             int row_offset_l = src_row_l * stretch_pitch_mask;
    490             int row_offset_r = src_row_r * stretch_pitch_mask;
    491             *dest_pos_mask =
    492                 bilinear_interpol(stretch_buf_mask, row_offset_l, row_offset_r,
    493                                   src_col_l, src_col_r, res_x, res_y, 1, 0);
    494           }
    495           dest_pos_mask++;
    496         }
    497       }
    498     } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    499       CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
    500       for (int row = 0; row < m_result.Height(); row++) {
    501         uint8_t* dest_pos_mask =
    502             (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
    503         for (int col = 0; col < m_result.Width(); col++) {
    504           int src_col_l, src_row_l, res_x, res_y;
    505           result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
    506                                        res_y);
    507           if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
    508               src_row_l <= stretch_height) {
    509             int pos_pixel[8];
    510             int u_w[4], v_w[4];
    511             if (src_col_l == stretch_width) {
    512               src_col_l--;
    513             }
    514             if (src_row_l == stretch_height) {
    515               src_row_l--;
    516             }
    517             bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
    518                                    res_x, res_y, stretch_width, stretch_height);
    519             *dest_pos_mask =
    520                 bicubic_interpol(stretch_buf_mask, stretch_pitch_mask,
    521                                  pos_pixel, u_w, v_w, res_x, res_y, 1, 0);
    522           }
    523           dest_pos_mask++;
    524         }
    525       }
    526     } else {
    527       CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
    528       for (int row = 0; row < m_result.Height(); row++) {
    529         uint8_t* dest_pos_mask =
    530             (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
    531         for (int col = 0; col < m_result.Width(); col++) {
    532           int src_col, src_row;
    533           result2stretch_fix.Transform(col, row, src_col, src_row);
    534           if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
    535               src_row <= stretch_height) {
    536             if (src_col == stretch_width) {
    537               src_col--;
    538             }
    539             if (src_row == stretch_height) {
    540               src_row--;
    541             }
    542             *dest_pos_mask =
    543                 stretch_buf_mask[src_row * stretch_pitch_mask + src_col];
    544           }
    545           dest_pos_mask++;
    546         }
    547       }
    548     }
    549   }
    550   if (m_Storer.GetBitmap()->IsAlphaMask()) {
    551     if (!(m_Flags & FXDIB_DOWNSAMPLE) && !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
    552       CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
    553       for (int row = 0; row < m_result.Height(); row++) {
    554         uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
    555         for (int col = 0; col < m_result.Width(); col++) {
    556           int src_col_l, src_row_l, res_x, res_y;
    557           result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
    558                                        res_y);
    559           if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
    560               src_row_l <= stretch_height) {
    561             if (src_col_l == stretch_width) {
    562               src_col_l--;
    563             }
    564             if (src_row_l == stretch_height) {
    565               src_row_l--;
    566             }
    567             int src_col_r = src_col_l + 1;
    568             int src_row_r = src_row_l + 1;
    569             if (src_col_r == stretch_width) {
    570               src_col_r--;
    571             }
    572             if (src_row_r == stretch_height) {
    573               src_row_r--;
    574             }
    575             int row_offset_l = src_row_l * stretch_pitch;
    576             int row_offset_r = src_row_r * stretch_pitch;
    577             *dest_scan =
    578                 bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
    579                                   src_col_l, src_col_r, res_x, res_y, 1, 0);
    580           }
    581           dest_scan++;
    582         }
    583       }
    584     } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    585       CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
    586       for (int row = 0; row < m_result.Height(); row++) {
    587         uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
    588         for (int col = 0; col < m_result.Width(); col++) {
    589           int src_col_l, src_row_l, res_x, res_y;
    590           result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
    591                                        res_y);
    592           if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
    593               src_row_l <= stretch_height) {
    594             int pos_pixel[8];
    595             int u_w[4], v_w[4];
    596             if (src_col_l == stretch_width) {
    597               src_col_l--;
    598             }
    599             if (src_row_l == stretch_height) {
    600               src_row_l--;
    601             }
    602             bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
    603                                    res_x, res_y, stretch_width, stretch_height);
    604             *dest_scan = bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
    605                                           u_w, v_w, res_x, res_y, 1, 0);
    606           }
    607           dest_scan++;
    608         }
    609       }
    610     } else {
    611       CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
    612       for (int row = 0; row < m_result.Height(); row++) {
    613         uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
    614         for (int col = 0; col < m_result.Width(); col++) {
    615           int src_col, src_row;
    616           result2stretch_fix.Transform(col, row, src_col, src_row);
    617           if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
    618               src_row <= stretch_height) {
    619             if (src_col == stretch_width) {
    620               src_col--;
    621             }
    622             if (src_row == stretch_height) {
    623               src_row--;
    624             }
    625             const uint8_t* src_pixel =
    626                 stretch_buf + stretch_pitch * src_row + src_col;
    627             *dest_scan = *src_pixel;
    628           }
    629           dest_scan++;
    630         }
    631       }
    632     }
    633   } else {
    634     int Bpp = m_Storer.GetBitmap()->GetBPP() / 8;
    635     if (Bpp == 1) {
    636       uint32_t argb[256];
    637       FX_ARGB* pPal = m_Storer.GetBitmap()->GetPalette();
    638       if (pPal) {
    639         for (int i = 0; i < 256; i++) {
    640           argb[i] = pPal[i];
    641         }
    642       } else {
    643         if (m_Storer.GetBitmap()->IsCmykImage()) {
    644           for (int i = 0; i < 256; i++) {
    645             argb[i] = 255 - i;
    646           }
    647         } else {
    648           for (int i = 0; i < 256; i++) {
    649             argb[i] = 0xff000000 | (i * 0x010101);
    650           }
    651         }
    652       }
    653       int destBpp = pTransformed->GetBPP() / 8;
    654       if (!(m_Flags & FXDIB_DOWNSAMPLE) &&
    655           !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
    656         CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
    657         for (int row = 0; row < m_result.Height(); row++) {
    658           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
    659           for (int col = 0; col < m_result.Width(); col++) {
    660             int src_col_l, src_row_l, res_x, res_y;
    661             result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
    662                                          res_y);
    663             if (src_col_l >= 0 && src_col_l <= stretch_width &&
    664                 src_row_l >= 0 && src_row_l <= stretch_height) {
    665               if (src_col_l == stretch_width) {
    666                 src_col_l--;
    667               }
    668               if (src_row_l == stretch_height) {
    669                 src_row_l--;
    670               }
    671               int src_col_r = src_col_l + 1;
    672               int src_row_r = src_row_l + 1;
    673               if (src_col_r == stretch_width) {
    674                 src_col_r--;
    675               }
    676               if (src_row_r == stretch_height) {
    677                 src_row_r--;
    678               }
    679               int row_offset_l = src_row_l * stretch_pitch;
    680               int row_offset_r = src_row_r * stretch_pitch;
    681               uint32_t r_bgra_cmyk = argb[bilinear_interpol(
    682                   stretch_buf, row_offset_l, row_offset_r, src_col_l, src_col_r,
    683                   res_x, res_y, 1, 0)];
    684               if (transformF == FXDIB_Rgba) {
    685                 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
    686                 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
    687                 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
    688               } else {
    689                 *(uint32_t*)dest_pos = r_bgra_cmyk;
    690               }
    691             }
    692             dest_pos += destBpp;
    693           }
    694         }
    695       } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    696         CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
    697         for (int row = 0; row < m_result.Height(); row++) {
    698           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
    699           for (int col = 0; col < m_result.Width(); col++) {
    700             int src_col_l, src_row_l, res_x, res_y;
    701             result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
    702                                          res_y);
    703             if (src_col_l >= 0 && src_col_l <= stretch_width &&
    704                 src_row_l >= 0 && src_row_l <= stretch_height) {
    705               int pos_pixel[8];
    706               int u_w[4], v_w[4];
    707               if (src_col_l == stretch_width) {
    708                 src_col_l--;
    709               }
    710               if (src_row_l == stretch_height) {
    711                 src_row_l--;
    712               }
    713               bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
    714                                      res_x, res_y, stretch_width,
    715                                      stretch_height);
    716               uint32_t r_bgra_cmyk =
    717                   argb[bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
    718                                         u_w, v_w, res_x, res_y, 1, 0)];
    719               if (transformF == FXDIB_Rgba) {
    720                 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
    721                 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
    722                 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
    723               } else {
    724                 *(uint32_t*)dest_pos = r_bgra_cmyk;
    725               }
    726             }
    727             dest_pos += destBpp;
    728           }
    729         }
    730       } else {
    731         CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
    732         for (int row = 0; row < m_result.Height(); row++) {
    733           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
    734           for (int col = 0; col < m_result.Width(); col++) {
    735             int src_col, src_row;
    736             result2stretch_fix.Transform(col, row, src_col, src_row);
    737             if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
    738                 src_row <= stretch_height) {
    739               if (src_col == stretch_width) {
    740                 src_col--;
    741               }
    742               if (src_row == stretch_height) {
    743                 src_row--;
    744               }
    745               uint32_t r_bgra_cmyk =
    746                   argb[stretch_buf[src_row * stretch_pitch + src_col]];
    747               if (transformF == FXDIB_Rgba) {
    748                 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
    749                 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
    750                 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
    751               } else {
    752                 *(uint32_t*)dest_pos = r_bgra_cmyk;
    753               }
    754             }
    755             dest_pos += destBpp;
    756           }
    757         }
    758       }
    759     } else {
    760       bool bHasAlpha = m_Storer.GetBitmap()->HasAlpha();
    761       int destBpp = pTransformed->GetBPP() / 8;
    762       if (!(m_Flags & FXDIB_DOWNSAMPLE) &&
    763           !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
    764         CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
    765         for (int row = 0; row < m_result.Height(); row++) {
    766           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
    767           for (int col = 0; col < m_result.Width(); col++) {
    768             int src_col_l, src_row_l, res_x, res_y, r_pos_k_r = 0;
    769             result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
    770                                          res_y);
    771             if (src_col_l >= 0 && src_col_l <= stretch_width &&
    772                 src_row_l >= 0 && src_row_l <= stretch_height) {
    773               if (src_col_l == stretch_width) {
    774                 src_col_l--;
    775               }
    776               if (src_row_l == stretch_height) {
    777                 src_row_l--;
    778               }
    779               int src_col_r = src_col_l + 1;
    780               int src_row_r = src_row_l + 1;
    781               if (src_col_r == stretch_width) {
    782                 src_col_r--;
    783               }
    784               if (src_row_r == stretch_height) {
    785                 src_row_r--;
    786               }
    787               int row_offset_l = src_row_l * stretch_pitch;
    788               int row_offset_r = src_row_r * stretch_pitch;
    789               uint8_t r_pos_red_y_r =
    790                   bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
    791                                     src_col_l, src_col_r, res_x, res_y, Bpp, 2);
    792               uint8_t r_pos_green_m_r =
    793                   bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
    794                                     src_col_l, src_col_r, res_x, res_y, Bpp, 1);
    795               uint8_t r_pos_blue_c_r =
    796                   bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
    797                                     src_col_l, src_col_r, res_x, res_y, Bpp, 0);
    798               if (bHasAlpha) {
    799                 if (transformF != FXDIB_Argb) {
    800                   if (transformF == FXDIB_Rgba) {
    801                     dest_pos[0] = r_pos_blue_c_r;
    802                     dest_pos[1] = r_pos_green_m_r;
    803                     dest_pos[2] = r_pos_red_y_r;
    804                   } else {
    805                     r_pos_k_r = bilinear_interpol(
    806                         stretch_buf, row_offset_l, row_offset_r, src_col_l,
    807                         src_col_r, res_x, res_y, Bpp, 3);
    808                     *(uint32_t*)dest_pos =
    809                         FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
    810                                                 r_pos_red_y_r, r_pos_k_r));
    811                   }
    812                 } else {
    813                   uint8_t r_pos_a_r = bilinear_interpol(
    814                       stretch_buf, row_offset_l, row_offset_r, src_col_l,
    815                       src_col_r, res_x, res_y, Bpp, 3);
    816                   *(uint32_t*)dest_pos = FXARGB_TODIB(
    817                       FXARGB_MAKE(r_pos_a_r, r_pos_red_y_r, r_pos_green_m_r,
    818                                   r_pos_blue_c_r));
    819                 }
    820               } else {
    821                 r_pos_k_r = 0xff;
    822                 if (transformF == FXDIB_Cmyka) {
    823                   r_pos_k_r = bilinear_interpol(
    824                       stretch_buf, row_offset_l, row_offset_r, src_col_l,
    825                       src_col_r, res_x, res_y, Bpp, 3);
    826                   *(uint32_t*)dest_pos =
    827                       FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
    828                                               r_pos_red_y_r, r_pos_k_r));
    829                 } else {
    830                   *(uint32_t*)dest_pos = FXARGB_TODIB(
    831                       FXARGB_MAKE(r_pos_k_r, r_pos_red_y_r, r_pos_green_m_r,
    832                                   r_pos_blue_c_r));
    833                 }
    834               }
    835             }
    836             dest_pos += destBpp;
    837           }
    838         }
    839       } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    840         CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
    841         for (int row = 0; row < m_result.Height(); row++) {
    842           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
    843           for (int col = 0; col < m_result.Width(); col++) {
    844             int src_col_l, src_row_l, res_x, res_y, r_pos_k_r = 0;
    845             result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
    846                                          res_y);
    847             if (src_col_l >= 0 && src_col_l <= stretch_width &&
    848                 src_row_l >= 0 && src_row_l <= stretch_height) {
    849               int pos_pixel[8];
    850               int u_w[4], v_w[4];
    851               if (src_col_l == stretch_width) {
    852                 src_col_l--;
    853               }
    854               if (src_row_l == stretch_height) {
    855                 src_row_l--;
    856               }
    857               bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
    858                                      res_x, res_y, stretch_width,
    859                                      stretch_height);
    860               uint8_t r_pos_red_y_r =
    861                   bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
    862                                    v_w, res_x, res_y, Bpp, 2);
    863               uint8_t r_pos_green_m_r =
    864                   bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
    865                                    v_w, res_x, res_y, Bpp, 1);
    866               uint8_t r_pos_blue_c_r =
    867                   bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
    868                                    v_w, res_x, res_y, Bpp, 0);
    869               if (bHasAlpha) {
    870                 if (transformF != FXDIB_Argb) {
    871                   if (transformF == FXDIB_Rgba) {
    872                     dest_pos[0] = r_pos_blue_c_r;
    873                     dest_pos[1] = r_pos_green_m_r;
    874                     dest_pos[2] = r_pos_red_y_r;
    875                   } else {
    876                     r_pos_k_r =
    877                         bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
    878                                          u_w, v_w, res_x, res_y, Bpp, 3);
    879                     *(uint32_t*)dest_pos =
    880                         FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
    881                                                 r_pos_red_y_r, r_pos_k_r));
    882                   }
    883                 } else {
    884                   uint8_t r_pos_a_r =
    885                       bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
    886                                        u_w, v_w, res_x, res_y, Bpp, 3);
    887                   *(uint32_t*)dest_pos = FXARGB_TODIB(
    888                       FXARGB_MAKE(r_pos_a_r, r_pos_red_y_r, r_pos_green_m_r,
    889                                   r_pos_blue_c_r));
    890                 }
    891               } else {
    892                 r_pos_k_r = 0xff;
    893                 if (transformF == FXDIB_Cmyka) {
    894                   r_pos_k_r =
    895                       bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
    896                                        u_w, v_w, res_x, res_y, Bpp, 3);
    897                   *(uint32_t*)dest_pos =
    898                       FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
    899                                               r_pos_red_y_r, r_pos_k_r));
    900                 } else {
    901                   *(uint32_t*)dest_pos = FXARGB_TODIB(
    902                       FXARGB_MAKE(r_pos_k_r, r_pos_red_y_r, r_pos_green_m_r,
    903                                   r_pos_blue_c_r));
    904                 }
    905               }
    906             }
    907             dest_pos += destBpp;
    908           }
    909         }
    910       } else {
    911         CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
    912         for (int row = 0; row < m_result.Height(); row++) {
    913           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
    914           for (int col = 0; col < m_result.Width(); col++) {
    915             int src_col, src_row;
    916             result2stretch_fix.Transform(col, row, src_col, src_row);
    917             if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
    918                 src_row <= stretch_height) {
    919               if (src_col == stretch_width) {
    920                 src_col--;
    921               }
    922               if (src_row == stretch_height) {
    923                 src_row--;
    924               }
    925               const uint8_t* src_pos =
    926                   stretch_buf + src_row * stretch_pitch + src_col * Bpp;
    927               if (bHasAlpha) {
    928                 if (transformF != FXDIB_Argb) {
    929                   if (transformF == FXDIB_Rgba) {
    930                     dest_pos[0] = src_pos[0];
    931                     dest_pos[1] = src_pos[1];
    932                     dest_pos[2] = src_pos[2];
    933                   } else {
    934                     *(uint32_t*)dest_pos = FXCMYK_TODIB(CmykEncode(
    935                         src_pos[0], src_pos[1], src_pos[2], src_pos[3]));
    936                   }
    937                 } else {
    938                   *(uint32_t*)dest_pos = FXARGB_TODIB(FXARGB_MAKE(
    939                       src_pos[3], src_pos[2], src_pos[1], src_pos[0]));
    940                 }
    941               } else {
    942                 if (transformF == FXDIB_Cmyka) {
    943                   *(uint32_t*)dest_pos = FXCMYK_TODIB(CmykEncode(
    944                       src_pos[0], src_pos[1], src_pos[2], src_pos[3]));
    945                 } else {
    946                   *(uint32_t*)dest_pos = FXARGB_TODIB(
    947                       FXARGB_MAKE(0xff, src_pos[2], src_pos[1], src_pos[0]));
    948                 }
    949               }
    950             }
    951             dest_pos += destBpp;
    952           }
    953         }
    954       }
    955     }
    956   }
    957   m_Storer.Replace(std::move(pTransformed));
    958   return false;
    959 }
    960 
    961 std::unique_ptr<CFX_DIBitmap> CFX_ImageTransformer::DetachBitmap() {
    962   return m_Storer.Detach();
    963 }
    964