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 <limits.h>
      8 
      9 #include <algorithm>
     10 
     11 #include "core/fxge/dib/dib_int.h"
     12 #include "core/fxge/fx_dib.h"
     13 #include "third_party/base/ptr_util.h"
     14 
     15 namespace {
     16 
     17 bool SourceSizeWithinLimit(int width, int height) {
     18   const int kMaxProgressiveStretchPixels = 1000000;
     19   return !height || width < kMaxProgressiveStretchPixels / height;
     20 }
     21 
     22 FXDIB_Format GetStretchedFormat(const CFX_DIBSource& src) {
     23   FXDIB_Format format = src.GetFormat();
     24   if (format == FXDIB_1bppMask)
     25     return FXDIB_8bppMask;
     26   if (format == FXDIB_1bppRgb)
     27     return FXDIB_8bppRgb;
     28   if (format == FXDIB_8bppRgb && src.GetPalette())
     29     return FXDIB_Rgb;
     30   return format;
     31 }
     32 
     33 }  // namespace
     34 
     35 CWeightTable::CWeightTable()
     36     : m_DestMin(0),
     37       m_ItemSize(0),
     38       m_pWeightTables(nullptr),
     39       m_dwWeightTablesSize(0) {}
     40 
     41 CWeightTable::~CWeightTable() {
     42   FX_Free(m_pWeightTables);
     43 }
     44 
     45 size_t CWeightTable::GetPixelWeightSize() const {
     46   return m_ItemSize / sizeof(int) - 2;
     47 }
     48 
     49 bool CWeightTable::Calc(int dest_len,
     50                         int dest_min,
     51                         int dest_max,
     52                         int src_len,
     53                         int src_min,
     54                         int src_max,
     55                         int flags) {
     56   FX_Free(m_pWeightTables);
     57   m_pWeightTables = nullptr;
     58   m_dwWeightTablesSize = 0;
     59   const double scale = (FX_FLOAT)src_len / (FX_FLOAT)dest_len;
     60   const double base = dest_len < 0 ? (FX_FLOAT)(src_len) : 0;
     61   const int ext_size = flags & FXDIB_BICUBIC_INTERPOL ? 3 : 1;
     62   m_ItemSize =
     63       sizeof(int) * 2 +
     64       (int)(sizeof(int) * (FXSYS_ceil(FXSYS_fabs((FX_FLOAT)scale)) + ext_size));
     65   m_DestMin = dest_min;
     66   if ((dest_max - dest_min) > (int)((1U << 30) - 4) / m_ItemSize)
     67     return false;
     68 
     69   m_dwWeightTablesSize = (dest_max - dest_min) * m_ItemSize + 4;
     70   m_pWeightTables = FX_TryAlloc(uint8_t, m_dwWeightTablesSize);
     71   if (!m_pWeightTables)
     72     return false;
     73 
     74   if ((flags & FXDIB_NOSMOOTH) != 0 || FXSYS_fabs((FX_FLOAT)scale) < 1.0f) {
     75     for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel++) {
     76       PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);
     77       double src_pos = dest_pixel * scale + scale / 2 + base;
     78       if (flags & FXDIB_INTERPOL) {
     79         pixel_weights.m_SrcStart =
     80             (int)FXSYS_floor((FX_FLOAT)src_pos - 1.0f / 2);
     81         pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos + 1.0f / 2);
     82         if (pixel_weights.m_SrcStart < src_min) {
     83           pixel_weights.m_SrcStart = src_min;
     84         }
     85         if (pixel_weights.m_SrcEnd >= src_max) {
     86           pixel_weights.m_SrcEnd = src_max - 1;
     87         }
     88         if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
     89           pixel_weights.m_Weights[0] = 65536;
     90         } else {
     91           pixel_weights.m_Weights[1] = FXSYS_round(
     92               (FX_FLOAT)(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) *
     93               65536);
     94           pixel_weights.m_Weights[0] = 65536 - pixel_weights.m_Weights[1];
     95         }
     96       } else if (flags & FXDIB_BICUBIC_INTERPOL) {
     97         pixel_weights.m_SrcStart =
     98             (int)FXSYS_floor((FX_FLOAT)src_pos - 1.0f / 2);
     99         pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos + 1.0f / 2);
    100         int start = pixel_weights.m_SrcStart - 1;
    101         int end = pixel_weights.m_SrcEnd + 1;
    102         if (start < src_min) {
    103           start = src_min;
    104         }
    105         if (end >= src_max) {
    106           end = src_max - 1;
    107         }
    108         if (pixel_weights.m_SrcStart < src_min) {
    109           src_pos += src_min - pixel_weights.m_SrcStart;
    110           pixel_weights.m_SrcStart = src_min;
    111         }
    112         if (pixel_weights.m_SrcEnd >= src_max) {
    113           pixel_weights.m_SrcEnd = src_max - 1;
    114         }
    115         int weight;
    116         weight = FXSYS_round(
    117             (FX_FLOAT)(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * 256);
    118         if (start == end) {
    119           pixel_weights.m_Weights[0] =
    120               (SDP_Table[256 + weight] + SDP_Table[weight] +
    121                SDP_Table[256 - weight] + SDP_Table[512 - weight])
    122               << 8;
    123         } else if ((start == pixel_weights.m_SrcStart &&
    124                     (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd ||
    125                      end == pixel_weights.m_SrcEnd) &&
    126                     start < end) ||
    127                    (start < pixel_weights.m_SrcStart &&
    128                     pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd &&
    129                     end == pixel_weights.m_SrcEnd)) {
    130           if (start < pixel_weights.m_SrcStart) {
    131             pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
    132             pixel_weights.m_Weights[1] =
    133                 (SDP_Table[weight] + SDP_Table[256 - weight] +
    134                  SDP_Table[512 - weight])
    135                 << 8;
    136           } else {
    137             if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
    138               pixel_weights.m_Weights[0] =
    139                   (SDP_Table[256 + weight] + SDP_Table[weight] +
    140                    SDP_Table[256 - weight])
    141                   << 8;
    142               pixel_weights.m_Weights[1] = SDP_Table[512 - weight] << 8;
    143             } else {
    144               pixel_weights.m_Weights[0] =
    145                   (SDP_Table[256 + weight] + SDP_Table[weight]) << 8;
    146               pixel_weights.m_Weights[1] =
    147                   (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;
    148             }
    149           }
    150           if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
    151             pixel_weights.m_SrcEnd = end;
    152           }
    153           if (start < pixel_weights.m_SrcStart) {
    154             pixel_weights.m_SrcStart = start;
    155           }
    156         } else if (start == pixel_weights.m_SrcStart &&
    157                    start < pixel_weights.m_SrcEnd &&
    158                    pixel_weights.m_SrcEnd < end) {
    159           pixel_weights.m_Weights[0] =
    160               (SDP_Table[256 + weight] + SDP_Table[weight]) << 8;
    161           pixel_weights.m_Weights[1] = SDP_Table[256 - weight] << 8;
    162           pixel_weights.m_Weights[2] = SDP_Table[512 - weight] << 8;
    163           pixel_weights.m_SrcEnd = end;
    164         } else if (start < pixel_weights.m_SrcStart &&
    165                    pixel_weights.m_SrcStart < pixel_weights.m_SrcEnd &&
    166                    pixel_weights.m_SrcEnd == end) {
    167           pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
    168           pixel_weights.m_Weights[1] = SDP_Table[weight] << 8;
    169           pixel_weights.m_Weights[2] =
    170               (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;
    171           pixel_weights.m_SrcStart = start;
    172         } else {
    173           pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
    174           pixel_weights.m_Weights[1] = SDP_Table[weight] << 8;
    175           pixel_weights.m_Weights[2] = SDP_Table[256 - weight] << 8;
    176           pixel_weights.m_Weights[3] = SDP_Table[512 - weight] << 8;
    177           pixel_weights.m_SrcStart = start;
    178           pixel_weights.m_SrcEnd = end;
    179         }
    180       } else {
    181         pixel_weights.m_SrcStart = pixel_weights.m_SrcEnd =
    182             (int)FXSYS_floor((FX_FLOAT)src_pos);
    183         if (pixel_weights.m_SrcStart < src_min) {
    184           pixel_weights.m_SrcStart = src_min;
    185         }
    186         if (pixel_weights.m_SrcEnd >= src_max) {
    187           pixel_weights.m_SrcEnd = src_max - 1;
    188         }
    189         pixel_weights.m_Weights[0] = 65536;
    190       }
    191     }
    192     return true;
    193   }
    194 
    195   for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel++) {
    196     PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);
    197     double src_start = dest_pixel * scale + base;
    198     double src_end = src_start + scale;
    199     int start_i, end_i;
    200     if (src_start < src_end) {
    201       start_i = (int)FXSYS_floor((FX_FLOAT)src_start);
    202       end_i = (int)FXSYS_ceil((FX_FLOAT)src_end);
    203     } else {
    204       start_i = (int)FXSYS_floor((FX_FLOAT)src_end);
    205       end_i = (int)FXSYS_ceil((FX_FLOAT)src_start);
    206     }
    207     if (start_i < src_min) {
    208       start_i = src_min;
    209     }
    210     if (end_i >= src_max) {
    211       end_i = src_max - 1;
    212     }
    213     if (start_i > end_i) {
    214       if (start_i >= src_max) {
    215         start_i = src_max - 1;
    216       }
    217       pixel_weights.m_SrcStart = start_i;
    218       pixel_weights.m_SrcEnd = start_i;
    219       continue;
    220     }
    221     pixel_weights.m_SrcStart = start_i;
    222     pixel_weights.m_SrcEnd = end_i;
    223     for (int j = start_i; j <= end_i; j++) {
    224       double dest_start = ((FX_FLOAT)j - base) / scale;
    225       double dest_end = ((FX_FLOAT)(j + 1) - base) / scale;
    226       if (dest_start > dest_end) {
    227         double temp = dest_start;
    228         dest_start = dest_end;
    229         dest_end = temp;
    230       }
    231       double area_start = dest_start > (FX_FLOAT)(dest_pixel)
    232                               ? dest_start
    233                               : (FX_FLOAT)(dest_pixel);
    234       double area_end = dest_end > (FX_FLOAT)(dest_pixel + 1)
    235                             ? (FX_FLOAT)(dest_pixel + 1)
    236                             : dest_end;
    237       double weight = area_start >= area_end ? 0.0f : area_end - area_start;
    238       if (weight == 0 && j == end_i) {
    239         pixel_weights.m_SrcEnd--;
    240         break;
    241       }
    242       size_t idx = j - start_i;
    243       if (idx >= GetPixelWeightSize())
    244         return false;
    245       pixel_weights.m_Weights[idx] = FXSYS_round((FX_FLOAT)(weight * 65536));
    246     }
    247   }
    248   return true;
    249 }
    250 
    251 PixelWeight* CWeightTable::GetPixelWeight(int pixel) const {
    252   ASSERT(pixel >= m_DestMin);
    253   return reinterpret_cast<PixelWeight*>(m_pWeightTables +
    254                                         (pixel - m_DestMin) * m_ItemSize);
    255 }
    256 
    257 int* CWeightTable::GetValueFromPixelWeight(PixelWeight* pWeight,
    258                                            int index) const {
    259   if (index < pWeight->m_SrcStart)
    260     return nullptr;
    261 
    262   size_t idx = index - pWeight->m_SrcStart;
    263   return idx < GetPixelWeightSize() ? &pWeight->m_Weights[idx] : nullptr;
    264 }
    265 
    266 CStretchEngine::CStretchEngine(IFX_ScanlineComposer* pDestBitmap,
    267                                FXDIB_Format dest_format,
    268                                int dest_width,
    269                                int dest_height,
    270                                const FX_RECT& clip_rect,
    271                                const CFX_DIBSource* pSrcBitmap,
    272                                int flags) {
    273   m_State = 0;
    274   m_DestFormat = dest_format;
    275   m_DestBpp = dest_format & 0xff;
    276   m_SrcBpp = pSrcBitmap->GetFormat() & 0xff;
    277   m_bHasAlpha = pSrcBitmap->GetFormat() & 0x200;
    278   m_pSrcPalette = pSrcBitmap->GetPalette();
    279   m_pDestBitmap = pDestBitmap;
    280   m_DestWidth = dest_width;
    281   m_DestHeight = dest_height;
    282   m_pInterBuf = nullptr;
    283   m_pExtraAlphaBuf = nullptr;
    284   m_pDestMaskScanline = nullptr;
    285   m_DestClip = clip_rect;
    286   uint32_t size = clip_rect.Width();
    287   if (size && m_DestBpp > (int)(INT_MAX / size)) {
    288     return;
    289   }
    290   size *= m_DestBpp;
    291   if (size > INT_MAX - 31) {
    292     return;
    293   }
    294   size += 31;
    295   size = size / 32 * 4;
    296   m_pDestScanline = FX_TryAlloc(uint8_t, size);
    297   if (!m_pDestScanline) {
    298     return;
    299   }
    300   if (dest_format == FXDIB_Rgb32) {
    301     FXSYS_memset(m_pDestScanline, 255, size);
    302   }
    303   m_InterPitch = (m_DestClip.Width() * m_DestBpp + 31) / 32 * 4;
    304   m_ExtraMaskPitch = (m_DestClip.Width() * 8 + 31) / 32 * 4;
    305   m_pInterBuf = nullptr;
    306   m_pSource = pSrcBitmap;
    307   m_SrcWidth = pSrcBitmap->GetWidth();
    308   m_SrcHeight = pSrcBitmap->GetHeight();
    309   m_SrcPitch = (m_SrcWidth * m_SrcBpp + 31) / 32 * 4;
    310   if ((flags & FXDIB_NOSMOOTH) == 0) {
    311     bool bInterpol = flags & FXDIB_INTERPOL || flags & FXDIB_BICUBIC_INTERPOL;
    312     if (!bInterpol && FXSYS_abs(dest_width) != 0 &&
    313         FXSYS_abs(dest_height) / 8 < static_cast<long long>(m_SrcWidth) *
    314                                          m_SrcHeight / FXSYS_abs(dest_width)) {
    315       flags = FXDIB_INTERPOL;
    316     }
    317     m_Flags = flags;
    318   } else {
    319     m_Flags = FXDIB_NOSMOOTH;
    320     if (flags & FXDIB_DOWNSAMPLE) {
    321       m_Flags |= FXDIB_DOWNSAMPLE;
    322     }
    323   }
    324   double scale_x = (FX_FLOAT)m_SrcWidth / (FX_FLOAT)m_DestWidth;
    325   double scale_y = (FX_FLOAT)m_SrcHeight / (FX_FLOAT)m_DestHeight;
    326   double base_x = m_DestWidth > 0 ? 0.0f : (FX_FLOAT)(m_DestWidth);
    327   double base_y = m_DestHeight > 0 ? 0.0f : (FX_FLOAT)(m_DestHeight);
    328   double src_left = scale_x * ((FX_FLOAT)(clip_rect.left) + base_x);
    329   double src_right = scale_x * ((FX_FLOAT)(clip_rect.right) + base_x);
    330   double src_top = scale_y * ((FX_FLOAT)(clip_rect.top) + base_y);
    331   double src_bottom = scale_y * ((FX_FLOAT)(clip_rect.bottom) + base_y);
    332   if (src_left > src_right) {
    333     double temp = src_left;
    334     src_left = src_right;
    335     src_right = temp;
    336   }
    337   if (src_top > src_bottom) {
    338     double temp = src_top;
    339     src_top = src_bottom;
    340     src_bottom = temp;
    341   }
    342   m_SrcClip.left = (int)FXSYS_floor((FX_FLOAT)src_left);
    343   m_SrcClip.right = (int)FXSYS_ceil((FX_FLOAT)src_right);
    344   m_SrcClip.top = (int)FXSYS_floor((FX_FLOAT)src_top);
    345   m_SrcClip.bottom = (int)FXSYS_ceil((FX_FLOAT)src_bottom);
    346   FX_RECT src_rect(0, 0, m_SrcWidth, m_SrcHeight);
    347   m_SrcClip.Intersect(src_rect);
    348   if (m_SrcBpp == 1) {
    349     if (m_DestBpp == 8) {
    350       m_TransMethod = 1;
    351     } else {
    352       m_TransMethod = 2;
    353     }
    354   } else if (m_SrcBpp == 8) {
    355     if (m_DestBpp == 8) {
    356       if (!m_bHasAlpha) {
    357         m_TransMethod = 3;
    358       } else {
    359         m_TransMethod = 4;
    360       }
    361     } else {
    362       if (!m_bHasAlpha) {
    363         m_TransMethod = 5;
    364       } else {
    365         m_TransMethod = 6;
    366       }
    367     }
    368   } else {
    369     if (!m_bHasAlpha) {
    370       m_TransMethod = 7;
    371     } else {
    372       m_TransMethod = 8;
    373     }
    374   }
    375 }
    376 
    377 CStretchEngine::~CStretchEngine() {
    378   FX_Free(m_pDestScanline);
    379   FX_Free(m_pInterBuf);
    380   FX_Free(m_pExtraAlphaBuf);
    381   FX_Free(m_pDestMaskScanline);
    382 }
    383 
    384 bool CStretchEngine::Continue(IFX_Pause* pPause) {
    385   while (m_State == 1) {
    386     if (ContinueStretchHorz(pPause)) {
    387       return true;
    388     }
    389     m_State = 2;
    390     StretchVert();
    391   }
    392   return false;
    393 }
    394 
    395 bool CStretchEngine::StartStretchHorz() {
    396   if (m_DestWidth == 0 || m_InterPitch == 0 || !m_pDestScanline)
    397     return false;
    398 
    399   if (m_SrcClip.Height() == 0 ||
    400       m_SrcClip.Height() > (1 << 29) / m_InterPitch) {
    401     return false;
    402   }
    403 
    404   m_pInterBuf = FX_TryAlloc(unsigned char, m_SrcClip.Height() * m_InterPitch);
    405   if (!m_pInterBuf)
    406     return false;
    407 
    408   if (m_pSource && m_bHasAlpha && m_pSource->m_pAlphaMask) {
    409     m_pExtraAlphaBuf =
    410         FX_Alloc2D(unsigned char, m_SrcClip.Height(), m_ExtraMaskPitch);
    411     uint32_t size = (m_DestClip.Width() * 8 + 31) / 32 * 4;
    412     m_pDestMaskScanline = FX_TryAlloc(unsigned char, size);
    413     if (!m_pDestMaskScanline)
    414       return false;
    415   }
    416   bool ret =
    417       m_WeightTable.Calc(m_DestWidth, m_DestClip.left, m_DestClip.right,
    418                          m_SrcWidth, m_SrcClip.left, m_SrcClip.right, m_Flags);
    419   if (!ret)
    420     return false;
    421 
    422   m_CurRow = m_SrcClip.top;
    423   m_State = 1;
    424   return true;
    425 }
    426 
    427 bool CStretchEngine::ContinueStretchHorz(IFX_Pause* pPause) {
    428   if (!m_DestWidth)
    429     return false;
    430 
    431   if (m_pSource->SkipToScanline(m_CurRow, pPause))
    432     return true;
    433 
    434   int Bpp = m_DestBpp / 8;
    435   static const int kStrechPauseRows = 10;
    436   int rows_to_go = kStrechPauseRows;
    437   for (; m_CurRow < m_SrcClip.bottom; m_CurRow++) {
    438     if (rows_to_go == 0) {
    439       if (pPause && pPause->NeedToPauseNow())
    440         return true;
    441 
    442       rows_to_go = kStrechPauseRows;
    443     }
    444 
    445     const uint8_t* src_scan = m_pSource->GetScanline(m_CurRow);
    446     uint8_t* dest_scan =
    447         m_pInterBuf + (m_CurRow - m_SrcClip.top) * m_InterPitch;
    448     const uint8_t* src_scan_mask = nullptr;
    449     uint8_t* dest_scan_mask = nullptr;
    450     if (m_pExtraAlphaBuf) {
    451       src_scan_mask = m_pSource->m_pAlphaMask->GetScanline(m_CurRow);
    452       dest_scan_mask =
    453           m_pExtraAlphaBuf + (m_CurRow - m_SrcClip.top) * m_ExtraMaskPitch;
    454     }
    455     switch (m_TransMethod) {
    456       case 1:
    457       case 2: {
    458         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    459           PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);
    460           int dest_a = 0;
    461           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    462                j++) {
    463             int* pWeight =
    464                 m_WeightTable.GetValueFromPixelWeight(pPixelWeights, j);
    465             if (!pWeight)
    466               return false;
    467 
    468             int pixel_weight = *pWeight;
    469             if (src_scan[j / 8] & (1 << (7 - j % 8))) {
    470               dest_a += pixel_weight * 255;
    471             }
    472           }
    473           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    474             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;
    475           }
    476           *dest_scan++ = (uint8_t)(dest_a >> 16);
    477         }
    478         break;
    479       }
    480       case 3: {
    481         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    482           PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);
    483           int dest_a = 0;
    484           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    485                j++) {
    486             int* pWeight =
    487                 m_WeightTable.GetValueFromPixelWeight(pPixelWeights, j);
    488             if (!pWeight)
    489               return false;
    490 
    491             int pixel_weight = *pWeight;
    492             dest_a += pixel_weight * src_scan[j];
    493           }
    494           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    495             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;
    496           }
    497           *dest_scan++ = (uint8_t)(dest_a >> 16);
    498         }
    499         break;
    500       }
    501       case 4: {
    502         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    503           PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);
    504           int dest_a = 0, dest_r = 0;
    505           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    506                j++) {
    507             int* pWeight =
    508                 m_WeightTable.GetValueFromPixelWeight(pPixelWeights, j);
    509             if (!pWeight)
    510               return false;
    511 
    512             int pixel_weight = *pWeight;
    513             pixel_weight = pixel_weight * src_scan_mask[j] / 255;
    514             dest_r += pixel_weight * src_scan[j];
    515             dest_a += pixel_weight;
    516           }
    517           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    518             dest_r = dest_r < 0 ? 0 : dest_r > 16711680 ? 16711680 : dest_r;
    519             dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a;
    520           }
    521           *dest_scan++ = (uint8_t)(dest_r >> 16);
    522           *dest_scan_mask++ = (uint8_t)((dest_a * 255) >> 16);
    523         }
    524         break;
    525       }
    526       case 5: {
    527         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    528           PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);
    529           int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0;
    530           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    531                j++) {
    532             int* pWeight =
    533                 m_WeightTable.GetValueFromPixelWeight(pPixelWeights, j);
    534             if (!pWeight)
    535               return false;
    536 
    537             int pixel_weight = *pWeight;
    538             unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]];
    539             if (m_DestFormat == FXDIB_Rgb) {
    540               dest_r_y += pixel_weight * (uint8_t)(argb_cmyk >> 16);
    541               dest_g_m += pixel_weight * (uint8_t)(argb_cmyk >> 8);
    542               dest_b_c += pixel_weight * (uint8_t)argb_cmyk;
    543             } else {
    544               dest_b_c += pixel_weight * (uint8_t)(argb_cmyk >> 24);
    545               dest_g_m += pixel_weight * (uint8_t)(argb_cmyk >> 16);
    546               dest_r_y += pixel_weight * (uint8_t)(argb_cmyk >> 8);
    547             }
    548           }
    549           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    550             dest_r_y =
    551                 dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;
    552             dest_g_m =
    553                 dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;
    554             dest_b_c =
    555                 dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;
    556           }
    557           *dest_scan++ = (uint8_t)(dest_b_c >> 16);
    558           *dest_scan++ = (uint8_t)(dest_g_m >> 16);
    559           *dest_scan++ = (uint8_t)(dest_r_y >> 16);
    560         }
    561         break;
    562       }
    563       case 6: {
    564         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    565           PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);
    566           int dest_a = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0;
    567           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    568                j++) {
    569             int* pWeight =
    570                 m_WeightTable.GetValueFromPixelWeight(pPixelWeights, j);
    571             if (!pWeight)
    572               return false;
    573 
    574             int pixel_weight = *pWeight;
    575             pixel_weight = pixel_weight * src_scan_mask[j] / 255;
    576             unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]];
    577             if (m_DestFormat == FXDIB_Rgba) {
    578               dest_r_y += pixel_weight * (uint8_t)(argb_cmyk >> 16);
    579               dest_g_m += pixel_weight * (uint8_t)(argb_cmyk >> 8);
    580               dest_b_c += pixel_weight * (uint8_t)argb_cmyk;
    581             } else {
    582               dest_b_c += pixel_weight * (uint8_t)(argb_cmyk >> 24);
    583               dest_g_m += pixel_weight * (uint8_t)(argb_cmyk >> 16);
    584               dest_r_y += pixel_weight * (uint8_t)(argb_cmyk >> 8);
    585             }
    586             dest_a += pixel_weight;
    587           }
    588           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    589             dest_b_c =
    590                 dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;
    591             dest_g_m =
    592                 dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;
    593             dest_r_y =
    594                 dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;
    595             dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a;
    596           }
    597           *dest_scan++ = (uint8_t)(dest_b_c >> 16);
    598           *dest_scan++ = (uint8_t)(dest_g_m >> 16);
    599           *dest_scan++ = (uint8_t)(dest_r_y >> 16);
    600           *dest_scan_mask++ = (uint8_t)((dest_a * 255) >> 16);
    601         }
    602         break;
    603       }
    604       case 7: {
    605         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    606           PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);
    607           int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0;
    608           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    609                j++) {
    610             int* pWeight =
    611                 m_WeightTable.GetValueFromPixelWeight(pPixelWeights, j);
    612             if (!pWeight)
    613               return false;
    614 
    615             int pixel_weight = *pWeight;
    616             const uint8_t* src_pixel = src_scan + j * Bpp;
    617             dest_b_c += pixel_weight * (*src_pixel++);
    618             dest_g_m += pixel_weight * (*src_pixel++);
    619             dest_r_y += pixel_weight * (*src_pixel);
    620           }
    621           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    622             dest_b_c =
    623                 dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;
    624             dest_g_m =
    625                 dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;
    626             dest_r_y =
    627                 dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;
    628           }
    629           *dest_scan++ = (uint8_t)((dest_b_c) >> 16);
    630           *dest_scan++ = (uint8_t)((dest_g_m) >> 16);
    631           *dest_scan++ = (uint8_t)((dest_r_y) >> 16);
    632           dest_scan += Bpp - 3;
    633         }
    634         break;
    635       }
    636       case 8: {
    637         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    638           PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);
    639           int dest_a = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0;
    640           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    641                j++) {
    642             int* pWeight =
    643                 m_WeightTable.GetValueFromPixelWeight(pPixelWeights, j);
    644             if (!pWeight)
    645               return false;
    646 
    647             int pixel_weight = *pWeight;
    648             const uint8_t* src_pixel = src_scan + j * Bpp;
    649             if (m_DestFormat == FXDIB_Argb) {
    650               pixel_weight = pixel_weight * src_pixel[3] / 255;
    651             } else {
    652               pixel_weight = pixel_weight * src_scan_mask[j] / 255;
    653             }
    654             dest_b_c += pixel_weight * (*src_pixel++);
    655             dest_g_m += pixel_weight * (*src_pixel++);
    656             dest_r_y += pixel_weight * (*src_pixel);
    657             dest_a += pixel_weight;
    658           }
    659           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    660             dest_r_y =
    661                 dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;
    662             dest_g_m =
    663                 dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;
    664             dest_b_c =
    665                 dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;
    666             dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a;
    667           }
    668           *dest_scan++ = (uint8_t)((dest_b_c) >> 16);
    669           *dest_scan++ = (uint8_t)((dest_g_m) >> 16);
    670           *dest_scan++ = (uint8_t)((dest_r_y) >> 16);
    671           if (m_DestFormat == FXDIB_Argb) {
    672             *dest_scan = (uint8_t)((dest_a * 255) >> 16);
    673           }
    674           if (dest_scan_mask) {
    675             *dest_scan_mask++ = (uint8_t)((dest_a * 255) >> 16);
    676           }
    677           dest_scan += Bpp - 3;
    678         }
    679         break;
    680       }
    681     }
    682     rows_to_go--;
    683   }
    684   return false;
    685 }
    686 
    687 void CStretchEngine::StretchVert() {
    688   if (m_DestHeight == 0)
    689     return;
    690 
    691   CWeightTable table;
    692   bool ret = table.Calc(m_DestHeight, m_DestClip.top, m_DestClip.bottom,
    693                         m_SrcHeight, m_SrcClip.top, m_SrcClip.bottom, m_Flags);
    694   if (!ret)
    695     return;
    696 
    697   const int DestBpp = m_DestBpp / 8;
    698   for (int row = m_DestClip.top; row < m_DestClip.bottom; row++) {
    699     unsigned char* dest_scan = m_pDestScanline;
    700     unsigned char* dest_scan_mask = m_pDestMaskScanline;
    701     PixelWeight* pPixelWeights = table.GetPixelWeight(row);
    702     switch (m_TransMethod) {
    703       case 1:
    704       case 2:
    705       case 3: {
    706         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    707           unsigned char* src_scan =
    708               m_pInterBuf + (col - m_DestClip.left) * DestBpp;
    709           int dest_a = 0;
    710           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    711                j++) {
    712             int* pWeight = table.GetValueFromPixelWeight(pPixelWeights, j);
    713             if (!pWeight)
    714               return;
    715 
    716             int pixel_weight = *pWeight;
    717             dest_a +=
    718                 pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];
    719           }
    720           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    721             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;
    722           }
    723           *dest_scan = (uint8_t)(dest_a >> 16);
    724           dest_scan += DestBpp;
    725         }
    726         break;
    727       }
    728       case 4: {
    729         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    730           unsigned char* src_scan =
    731               m_pInterBuf + (col - m_DestClip.left) * DestBpp;
    732           unsigned char* src_scan_mask =
    733               m_pExtraAlphaBuf + (col - m_DestClip.left);
    734           int dest_a = 0, dest_k = 0;
    735           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    736                j++) {
    737             int* pWeight = table.GetValueFromPixelWeight(pPixelWeights, j);
    738             if (!pWeight)
    739               return;
    740 
    741             int pixel_weight = *pWeight;
    742             dest_k +=
    743                 pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];
    744             dest_a += pixel_weight *
    745                       src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch];
    746           }
    747           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    748             dest_k = dest_k < 0 ? 0 : dest_k > 16711680 ? 16711680 : dest_k;
    749             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;
    750           }
    751           *dest_scan = (uint8_t)(dest_k >> 16);
    752           dest_scan += DestBpp;
    753           *dest_scan_mask++ = (uint8_t)(dest_a >> 16);
    754         }
    755         break;
    756       }
    757       case 5:
    758       case 7: {
    759         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    760           unsigned char* src_scan =
    761               m_pInterBuf + (col - m_DestClip.left) * DestBpp;
    762           int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0;
    763           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    764                j++) {
    765             int* pWeight = table.GetValueFromPixelWeight(pPixelWeights, j);
    766             if (!pWeight)
    767               return;
    768 
    769             int pixel_weight = *pWeight;
    770             const uint8_t* src_pixel =
    771                 src_scan + (j - m_SrcClip.top) * m_InterPitch;
    772             dest_b_c += pixel_weight * (*src_pixel++);
    773             dest_g_m += pixel_weight * (*src_pixel++);
    774             dest_r_y += pixel_weight * (*src_pixel);
    775           }
    776           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    777             dest_r_y =
    778                 dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;
    779             dest_g_m =
    780                 dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;
    781             dest_b_c =
    782                 dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;
    783           }
    784           dest_scan[0] = (uint8_t)((dest_b_c) >> 16);
    785           dest_scan[1] = (uint8_t)((dest_g_m) >> 16);
    786           dest_scan[2] = (uint8_t)((dest_r_y) >> 16);
    787           dest_scan += DestBpp;
    788         }
    789         break;
    790       }
    791       case 6:
    792       case 8: {
    793         for (int col = m_DestClip.left; col < m_DestClip.right; col++) {
    794           unsigned char* src_scan =
    795               m_pInterBuf + (col - m_DestClip.left) * DestBpp;
    796           unsigned char* src_scan_mask = nullptr;
    797           if (m_DestFormat != FXDIB_Argb) {
    798             src_scan_mask = m_pExtraAlphaBuf + (col - m_DestClip.left);
    799           }
    800           int dest_a = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0;
    801           for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd;
    802                j++) {
    803             int* pWeight = table.GetValueFromPixelWeight(pPixelWeights, j);
    804             if (!pWeight)
    805               return;
    806 
    807             int pixel_weight = *pWeight;
    808             const uint8_t* src_pixel =
    809                 src_scan + (j - m_SrcClip.top) * m_InterPitch;
    810             int mask_v = 255;
    811             if (src_scan_mask) {
    812               mask_v = src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch];
    813             }
    814             dest_b_c += pixel_weight * (*src_pixel++);
    815             dest_g_m += pixel_weight * (*src_pixel++);
    816             dest_r_y += pixel_weight * (*src_pixel);
    817             if (m_DestFormat == FXDIB_Argb) {
    818               dest_a += pixel_weight * (*(src_pixel + 1));
    819             } else {
    820               dest_a += pixel_weight * mask_v;
    821             }
    822           }
    823           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
    824             dest_r_y =
    825                 dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;
    826             dest_g_m =
    827                 dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;
    828             dest_b_c =
    829                 dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;
    830             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;
    831           }
    832           if (dest_a) {
    833             int r = ((uint32_t)dest_r_y) * 255 / dest_a;
    834             int g = ((uint32_t)dest_g_m) * 255 / dest_a;
    835             int b = ((uint32_t)dest_b_c) * 255 / dest_a;
    836             dest_scan[0] = b > 255 ? 255 : b < 0 ? 0 : b;
    837             dest_scan[1] = g > 255 ? 255 : g < 0 ? 0 : g;
    838             dest_scan[2] = r > 255 ? 255 : r < 0 ? 0 : r;
    839           }
    840           if (m_DestFormat == FXDIB_Argb) {
    841             dest_scan[3] = (uint8_t)((dest_a) >> 16);
    842           } else {
    843             *dest_scan_mask = (uint8_t)((dest_a) >> 16);
    844           }
    845           dest_scan += DestBpp;
    846           if (dest_scan_mask) {
    847             dest_scan_mask++;
    848           }
    849         }
    850         break;
    851       }
    852     }
    853     m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_pDestScanline,
    854                                    m_pDestMaskScanline);
    855   }
    856 }
    857 
    858 CFX_ImageStretcher::CFX_ImageStretcher(IFX_ScanlineComposer* pDest,
    859                                        const CFX_DIBSource* pSource,
    860                                        int dest_width,
    861                                        int dest_height,
    862                                        const FX_RECT& bitmap_rect,
    863                                        uint32_t flags)
    864     : m_pDest(pDest),
    865       m_pSource(pSource),
    866       m_Flags(flags),
    867       m_bFlipX(false),
    868       m_bFlipY(false),
    869       m_DestWidth(dest_width),
    870       m_DestHeight(dest_height),
    871       m_ClipRect(bitmap_rect),
    872       m_DestFormat(GetStretchedFormat(*pSource)),
    873       m_DestBPP(m_DestFormat & 0xff),
    874       m_LineIndex(0) {}
    875 
    876 CFX_ImageStretcher::~CFX_ImageStretcher() {
    877 }
    878 
    879 bool CFX_ImageStretcher::Start() {
    880   if (m_DestWidth == 0 || m_DestHeight == 0)
    881     return false;
    882 
    883   if (m_pSource->GetFormat() == FXDIB_1bppRgb && m_pSource->GetPalette()) {
    884     FX_ARGB pal[256];
    885     int a0, r0, g0, b0, a1, r1, g1, b1;
    886     ArgbDecode(m_pSource->GetPaletteEntry(0), a0, r0, g0, b0);
    887     ArgbDecode(m_pSource->GetPaletteEntry(1), a1, r1, g1, b1);
    888     for (int i = 0; i < 256; i++) {
    889       int a = a0 + (a1 - a0) * i / 255;
    890       int r = r0 + (r1 - r0) * i / 255;
    891       int g = g0 + (g1 - g0) * i / 255;
    892       int b = b0 + (b1 - b0) * i / 255;
    893       pal[i] = ArgbEncode(a, r, g, b);
    894     }
    895     if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat,
    896                           pal)) {
    897       return false;
    898     }
    899   } else if (m_pSource->GetFormat() == FXDIB_1bppCmyk &&
    900              m_pSource->GetPalette()) {
    901     FX_CMYK pal[256];
    902     int c0, m0, y0, k0, c1, m1, y1, k1;
    903     CmykDecode(m_pSource->GetPaletteEntry(0), c0, m0, y0, k0);
    904     CmykDecode(m_pSource->GetPaletteEntry(1), c1, m1, y1, k1);
    905     for (int i = 0; i < 256; i++) {
    906       int c = c0 + (c1 - c0) * i / 255;
    907       int m = m0 + (m1 - m0) * i / 255;
    908       int y = y0 + (y1 - y0) * i / 255;
    909       int k = k0 + (k1 - k0) * i / 255;
    910       pal[i] = CmykEncode(c, m, y, k);
    911     }
    912     if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(), m_DestFormat,
    913                           pal)) {
    914       return false;
    915     }
    916   } else if (!m_pDest->SetInfo(m_ClipRect.Width(), m_ClipRect.Height(),
    917                                m_DestFormat, nullptr)) {
    918     return false;
    919   }
    920 
    921   if (m_Flags & FXDIB_DOWNSAMPLE)
    922     return StartQuickStretch();
    923   return StartStretch();
    924 }
    925 
    926 bool CFX_ImageStretcher::Continue(IFX_Pause* pPause) {
    927   if (m_Flags & FXDIB_DOWNSAMPLE)
    928     return ContinueQuickStretch(pPause);
    929   return ContinueStretch(pPause);
    930 }
    931 
    932 bool CFX_ImageStretcher::StartStretch() {
    933   m_pStretchEngine = pdfium::MakeUnique<CStretchEngine>(
    934       m_pDest, m_DestFormat, m_DestWidth, m_DestHeight, m_ClipRect, m_pSource,
    935       m_Flags);
    936   m_pStretchEngine->StartStretchHorz();
    937   if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) {
    938     m_pStretchEngine->Continue(nullptr);
    939     return false;
    940   }
    941   return true;
    942 }
    943 
    944 bool CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause) {
    945   return m_pStretchEngine && m_pStretchEngine->Continue(pPause);
    946 }
    947 
    948 bool CFX_ImageStretcher::StartQuickStretch() {
    949   if (m_DestWidth < 0) {
    950     m_bFlipX = true;
    951     m_DestWidth = -m_DestWidth;
    952   }
    953   if (m_DestHeight < 0) {
    954     m_bFlipY = true;
    955     m_DestHeight = -m_DestHeight;
    956   }
    957   uint32_t size = m_ClipRect.Width();
    958   if (size && m_DestBPP > (int)(INT_MAX / size)) {
    959     return false;
    960   }
    961   size *= m_DestBPP;
    962   m_pScanline.reset(FX_Alloc(uint8_t, (size / 8 + 3) / 4 * 4));
    963   if (m_pSource->m_pAlphaMask)
    964     m_pMaskScanline.reset(FX_Alloc(uint8_t, (m_ClipRect.Width() + 3) / 4 * 4));
    965 
    966   if (SourceSizeWithinLimit(m_pSource->GetWidth(), m_pSource->GetHeight())) {
    967     ContinueQuickStretch(nullptr);
    968     return false;
    969   }
    970   return true;
    971 }
    972 
    973 bool CFX_ImageStretcher::ContinueQuickStretch(IFX_Pause* pPause) {
    974   if (!m_pScanline)
    975     return false;
    976 
    977   int result_width = m_ClipRect.Width();
    978   int result_height = m_ClipRect.Height();
    979   int src_height = m_pSource->GetHeight();
    980   for (; m_LineIndex < result_height; m_LineIndex++) {
    981     int dest_y;
    982     int src_y;
    983     if (m_bFlipY) {
    984       dest_y = result_height - m_LineIndex - 1;
    985       src_y = (m_DestHeight - (dest_y + m_ClipRect.top) - 1) * src_height /
    986               m_DestHeight;
    987     } else {
    988       dest_y = m_LineIndex;
    989       src_y = (dest_y + m_ClipRect.top) * src_height / m_DestHeight;
    990     }
    991     src_y = std::max(std::min(src_y, src_height - 1), 0);
    992 
    993     if (m_pSource->SkipToScanline(src_y, pPause))
    994       return true;
    995 
    996     m_pSource->DownSampleScanline(src_y, m_pScanline.get(), m_DestBPP,
    997                                   m_DestWidth, m_bFlipX, m_ClipRect.left,
    998                                   result_width);
    999     if (m_pMaskScanline) {
   1000       m_pSource->m_pAlphaMask->DownSampleScanline(
   1001           src_y, m_pMaskScanline.get(), 1, m_DestWidth, m_bFlipX,
   1002           m_ClipRect.left, result_width);
   1003     }
   1004     m_pDest->ComposeScanline(dest_y, m_pScanline.get(), m_pMaskScanline.get());
   1005   }
   1006   return false;
   1007 }
   1008