• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SourceSizeWithinLimit(int width,int height)17 bool SourceSizeWithinLimit(int width, int height) {
18   const int kMaxProgressiveStretchPixels = 1000000;
19   return !height || width < kMaxProgressiveStretchPixels / height;
20 }
21 
GetStretchedFormat(const CFX_DIBSource & src)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 
CWeightTable()35 CWeightTable::CWeightTable()
36     : m_DestMin(0),
37       m_ItemSize(0),
38       m_pWeightTables(nullptr),
39       m_dwWeightTablesSize(0) {}
40 
~CWeightTable()41 CWeightTable::~CWeightTable() {
42   FX_Free(m_pWeightTables);
43 }
44 
GetPixelWeightSize() const45 size_t CWeightTable::GetPixelWeightSize() const {
46   return m_ItemSize / sizeof(int) - 2;
47 }
48 
Calc(int dest_len,int dest_min,int dest_max,int src_len,int src_min,int src_max,int flags)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 
GetPixelWeight(int pixel) const251 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 
GetValueFromPixelWeight(PixelWeight * pWeight,int index) const257 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 
CStretchEngine(IFX_ScanlineComposer * pDestBitmap,FXDIB_Format dest_format,int dest_width,int dest_height,const FX_RECT & clip_rect,const CFX_DIBSource * pSrcBitmap,int flags)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 
~CStretchEngine()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 
Continue(IFX_Pause * pPause)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 
StartStretchHorz()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 
ContinueStretchHorz(IFX_Pause * pPause)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 
StretchVert()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 
CFX_ImageStretcher(IFX_ScanlineComposer * pDest,const CFX_DIBSource * pSource,int dest_width,int dest_height,const FX_RECT & bitmap_rect,uint32_t flags)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 
~CFX_ImageStretcher()876 CFX_ImageStretcher::~CFX_ImageStretcher() {
877 }
878 
Start()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 
Continue(IFX_Pause * pPause)926 bool CFX_ImageStretcher::Continue(IFX_Pause* pPause) {
927   if (m_Flags & FXDIB_DOWNSAMPLE)
928     return ContinueQuickStretch(pPause);
929   return ContinueStretch(pPause);
930 }
931 
StartStretch()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 
ContinueStretch(IFX_Pause * pPause)944 bool CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause) {
945   return m_pStretchEngine && m_pStretchEngine->Continue(pPause);
946 }
947 
StartQuickStretch()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 
ContinueQuickStretch(IFX_Pause * pPause)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