• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fxge/dib/cstretchengine.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fxcrt/ifx_pauseindicator.h"
13 #include "core/fxge/dib/cfx_dibitmap.h"
14 #include "core/fxge/dib/cfx_dibsource.h"
15 #include "core/fxge/dib/ifx_scanlinecomposer.h"
16 #include "core/fxge/fx_dib.h"
17 
18 namespace {
19 
20 const int kMaxDestValue = 16711680;
21 
22 }  // namespace
23 
CWeightTable()24 CStretchEngine::CWeightTable::CWeightTable()
25     : m_DestMin(0),
26       m_ItemSize(0),
27       m_dwWeightTablesSize(0) {}
28 
~CWeightTable()29 CStretchEngine::CWeightTable::~CWeightTable() {}
30 
GetPixelWeightSize() const31 size_t CStretchEngine::CWeightTable::GetPixelWeightSize() const {
32   return m_ItemSize / sizeof(int) - 2;
33 }
34 
Calc(int dest_len,int dest_min,int dest_max,int src_len,int src_min,int src_max,int flags)35 bool CStretchEngine::CWeightTable::Calc(int dest_len,
36                                         int dest_min,
37                                         int dest_max,
38                                         int src_len,
39                                         int src_min,
40                                         int src_max,
41                                         int flags) {
42   m_WeightTables.clear();
43   m_dwWeightTablesSize = 0;
44   const double scale = static_cast<float>(src_len) / dest_len;
45   const double base = dest_len < 0 ? src_len : 0;
46   const int ext_size = flags & FXDIB_BICUBIC_INTERPOL ? 3 : 1;
47   m_ItemSize =
48       sizeof(int) * 2 +
49       static_cast<int>(sizeof(int) *
50                        (ceil(fabs(static_cast<float>(scale))) + ext_size));
51 
52   m_DestMin = dest_min;
53   if (dest_max - dest_min > static_cast<int>((1U << 30) - 4) / m_ItemSize)
54     return false;
55 
56   m_dwWeightTablesSize = (dest_max - dest_min) * m_ItemSize + 4;
57   m_WeightTables.resize(m_dwWeightTablesSize);
58   if ((flags & FXDIB_NOSMOOTH) != 0 || fabs(static_cast<float>(scale)) < 1.0f) {
59     for (int dest_pixel = dest_min; dest_pixel < dest_max; ++dest_pixel) {
60       PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);
61       double src_pos = dest_pixel * scale + scale / 2 + base;
62       if (flags & FXDIB_INTERPOL) {
63         pixel_weights.m_SrcStart =
64             static_cast<int>(floor(static_cast<float>(src_pos) - 1.0f / 2));
65         pixel_weights.m_SrcEnd =
66             static_cast<int>(floor(static_cast<float>(src_pos) + 1.0f / 2));
67         pixel_weights.m_SrcStart = std::max(pixel_weights.m_SrcStart, src_min);
68         pixel_weights.m_SrcEnd = std::min(pixel_weights.m_SrcEnd, src_max - 1);
69         if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
70           pixel_weights.m_Weights[0] = 65536;
71         } else {
72           pixel_weights.m_Weights[1] =
73               FXSYS_round(static_cast<float>(
74                               src_pos - pixel_weights.m_SrcStart - 1.0f / 2) *
75                           65536);
76           pixel_weights.m_Weights[0] = 65536 - pixel_weights.m_Weights[1];
77         }
78       } else if (flags & FXDIB_BICUBIC_INTERPOL) {
79         pixel_weights.m_SrcStart =
80             static_cast<int>(floor(static_cast<float>(src_pos) - 1.0f / 2));
81         pixel_weights.m_SrcEnd =
82             static_cast<int>(floor(static_cast<float>(src_pos) + 1.0f / 2));
83         int start = pixel_weights.m_SrcStart - 1;
84         int end = pixel_weights.m_SrcEnd + 1;
85         start = std::max(start, src_min);
86         end = std::min(end, src_max - 1);
87         if (pixel_weights.m_SrcStart < src_min) {
88           src_pos += src_min - pixel_weights.m_SrcStart;
89           pixel_weights.m_SrcStart = src_min;
90         }
91         pixel_weights.m_SrcEnd = std::min(pixel_weights.m_SrcEnd, src_max - 1);
92         int weight = FXSYS_round(
93             static_cast<float>(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) *
94             256);
95         if (start == end) {
96           pixel_weights.m_Weights[0] =
97               (SDP_Table[256 + weight] + SDP_Table[weight] +
98                SDP_Table[256 - weight] + SDP_Table[512 - weight])
99               << 8;
100         } else if ((start == pixel_weights.m_SrcStart &&
101                     (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd ||
102                      end == pixel_weights.m_SrcEnd) &&
103                     start < end) ||
104                    (start < pixel_weights.m_SrcStart &&
105                     pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd &&
106                     end == pixel_weights.m_SrcEnd)) {
107           if (start < pixel_weights.m_SrcStart) {
108             pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
109             pixel_weights.m_Weights[1] =
110                 (SDP_Table[weight] + SDP_Table[256 - weight] +
111                  SDP_Table[512 - weight])
112                 << 8;
113           } else {
114             if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
115               pixel_weights.m_Weights[0] =
116                   (SDP_Table[256 + weight] + SDP_Table[weight] +
117                    SDP_Table[256 - weight])
118                   << 8;
119               pixel_weights.m_Weights[1] = SDP_Table[512 - weight] << 8;
120             } else {
121               pixel_weights.m_Weights[0] =
122                   (SDP_Table[256 + weight] + SDP_Table[weight]) << 8;
123               pixel_weights.m_Weights[1] =
124                   (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;
125             }
126           }
127           if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
128             pixel_weights.m_SrcEnd = end;
129           }
130           if (start < pixel_weights.m_SrcStart) {
131             pixel_weights.m_SrcStart = start;
132           }
133         } else if (start == pixel_weights.m_SrcStart &&
134                    start < pixel_weights.m_SrcEnd &&
135                    pixel_weights.m_SrcEnd < end) {
136           pixel_weights.m_Weights[0] =
137               (SDP_Table[256 + weight] + SDP_Table[weight]) << 8;
138           pixel_weights.m_Weights[1] = SDP_Table[256 - weight] << 8;
139           pixel_weights.m_Weights[2] = SDP_Table[512 - weight] << 8;
140           pixel_weights.m_SrcEnd = end;
141         } else if (start < pixel_weights.m_SrcStart &&
142                    pixel_weights.m_SrcStart < pixel_weights.m_SrcEnd &&
143                    pixel_weights.m_SrcEnd == end) {
144           pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
145           pixel_weights.m_Weights[1] = SDP_Table[weight] << 8;
146           pixel_weights.m_Weights[2] =
147               (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;
148           pixel_weights.m_SrcStart = start;
149         } else {
150           pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
151           pixel_weights.m_Weights[1] = SDP_Table[weight] << 8;
152           pixel_weights.m_Weights[2] = SDP_Table[256 - weight] << 8;
153           pixel_weights.m_Weights[3] = SDP_Table[512 - weight] << 8;
154           pixel_weights.m_SrcStart = start;
155           pixel_weights.m_SrcEnd = end;
156         }
157       } else {
158         int pixel_pos = static_cast<int>(floor(static_cast<float>(src_pos)));
159         pixel_weights.m_SrcStart = std::max(pixel_pos, src_min);
160         pixel_weights.m_SrcEnd = std::min(pixel_pos, src_max - 1);
161         pixel_weights.m_Weights[0] = 65536;
162       }
163     }
164     return true;
165   }
166 
167   for (int dest_pixel = dest_min; dest_pixel < dest_max; ++dest_pixel) {
168     PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);
169     double src_start = dest_pixel * scale + base;
170     double src_end = src_start + scale;
171     int start_i = floor(std::min(src_start, src_end));
172     int end_i = floor(std::max(src_start, src_end));
173     start_i = std::max(start_i, src_min);
174     end_i = std::min(end_i, src_max - 1);
175     if (start_i > end_i) {
176       start_i = std::min(start_i, src_max - 1);
177       pixel_weights.m_SrcStart = start_i;
178       pixel_weights.m_SrcEnd = start_i;
179       continue;
180     }
181     pixel_weights.m_SrcStart = start_i;
182     pixel_weights.m_SrcEnd = end_i;
183     for (int j = start_i; j <= end_i; ++j) {
184       double dest_start = (j - base) / scale;
185       double dest_end = (j + 1 - base) / scale;
186       if (dest_start > dest_end)
187         std::swap(dest_start, dest_end);
188       double area_start = std::max(dest_start, static_cast<double>(dest_pixel));
189       double area_end = std::min(dest_end, static_cast<double>(dest_pixel + 1));
190       double weight = std::max(0.0, area_end - area_start);
191       if (weight == 0 && j == end_i) {
192         --pixel_weights.m_SrcEnd;
193         break;
194       }
195       size_t idx = j - start_i;
196       if (idx >= GetPixelWeightSize())
197         return false;
198 
199       pixel_weights.m_Weights[idx] = FXSYS_round(weight * 65536);
200     }
201   }
202   return true;
203 }
204 
GetPixelWeight(int pixel) const205 PixelWeight* CStretchEngine::CWeightTable::GetPixelWeight(int pixel) const {
206   ASSERT(pixel >= m_DestMin);
207   return reinterpret_cast<PixelWeight*>(const_cast<uint8_t*>(
208       m_WeightTables.data() + (pixel - m_DestMin) * m_ItemSize));
209 }
210 
GetValueFromPixelWeight(PixelWeight * pWeight,int index) const211 int* CStretchEngine::CWeightTable::GetValueFromPixelWeight(PixelWeight* pWeight,
212                                                            int index) const {
213   if (index < pWeight->m_SrcStart)
214     return nullptr;
215 
216   size_t idx = index - pWeight->m_SrcStart;
217   return idx < GetPixelWeightSize() ? &pWeight->m_Weights[idx] : nullptr;
218 }
219 
CStretchEngine(IFX_ScanlineComposer * pDestBitmap,FXDIB_Format dest_format,int dest_width,int dest_height,const FX_RECT & clip_rect,const RetainPtr<CFX_DIBSource> & pSrcBitmap,int flags)220 CStretchEngine::CStretchEngine(IFX_ScanlineComposer* pDestBitmap,
221                                FXDIB_Format dest_format,
222                                int dest_width,
223                                int dest_height,
224                                const FX_RECT& clip_rect,
225                                const RetainPtr<CFX_DIBSource>& pSrcBitmap,
226                                int flags) {
227   m_State = 0;
228   m_DestFormat = dest_format;
229   m_DestBpp = dest_format & 0xff;
230   m_SrcBpp = pSrcBitmap->GetFormat() & 0xff;
231   m_bHasAlpha = pSrcBitmap->GetFormat() & 0x200;
232   m_pSrcPalette = pSrcBitmap->GetPalette();
233   m_pDestBitmap = pDestBitmap;
234   m_DestWidth = dest_width;
235   m_DestHeight = dest_height;
236   m_DestClip = clip_rect;
237   uint32_t size = clip_rect.Width();
238   if (size && m_DestBpp > static_cast<int>(INT_MAX / size))
239     return;
240 
241   size *= m_DestBpp;
242   if (size > INT_MAX - 31)
243     return;
244 
245   size += 31;
246   size = size / 32 * 4;
247   m_DestScanline.resize(size);
248   if (dest_format == FXDIB_Rgb32)
249     std::fill(m_DestScanline.begin(), m_DestScanline.end(), 255);
250   m_InterPitch = (m_DestClip.Width() * m_DestBpp + 31) / 32 * 4;
251   m_ExtraMaskPitch = (m_DestClip.Width() * 8 + 31) / 32 * 4;
252   m_pSource = pSrcBitmap;
253   m_SrcWidth = pSrcBitmap->GetWidth();
254   m_SrcHeight = pSrcBitmap->GetHeight();
255   m_SrcPitch = (m_SrcWidth * m_SrcBpp + 31) / 32 * 4;
256   if ((flags & FXDIB_NOSMOOTH) == 0) {
257     bool bInterpol = flags & FXDIB_INTERPOL || flags & FXDIB_BICUBIC_INTERPOL;
258     if (!bInterpol && abs(dest_width) != 0 &&
259         abs(dest_height) / 8 < static_cast<long long>(m_SrcWidth) *
260                                    m_SrcHeight / abs(dest_width)) {
261       flags = FXDIB_INTERPOL;
262     }
263     m_Flags = flags;
264   } else {
265     m_Flags = FXDIB_NOSMOOTH;
266     if (flags & FXDIB_DOWNSAMPLE)
267       m_Flags |= FXDIB_DOWNSAMPLE;
268   }
269   double scale_x = static_cast<float>(m_SrcWidth) / m_DestWidth;
270   double scale_y = static_cast<float>(m_SrcHeight) / m_DestHeight;
271   double base_x = m_DestWidth > 0 ? 0.0f : m_DestWidth;
272   double base_y = m_DestHeight > 0 ? 0.0f : m_DestHeight;
273   double src_left = scale_x * (clip_rect.left + base_x);
274   double src_right = scale_x * (clip_rect.right + base_x);
275   double src_top = scale_y * (clip_rect.top + base_y);
276   double src_bottom = scale_y * (clip_rect.bottom + base_y);
277   if (src_left > src_right)
278     std::swap(src_left, src_right);
279   if (src_top > src_bottom)
280     std::swap(src_top, src_bottom);
281   m_SrcClip.left = static_cast<int>(floor(src_left));
282   m_SrcClip.right = static_cast<int>(ceil(src_right));
283   m_SrcClip.top = static_cast<int>(floor(src_top));
284   m_SrcClip.bottom = static_cast<int>(ceil(src_bottom));
285   FX_RECT src_rect(0, 0, m_SrcWidth, m_SrcHeight);
286   m_SrcClip.Intersect(src_rect);
287   if (m_SrcBpp == 1) {
288     if (m_DestBpp == 8)
289       m_TransMethod = 1;
290     else
291       m_TransMethod = 2;
292   } else if (m_SrcBpp == 8) {
293     if (m_DestBpp == 8) {
294       if (!m_bHasAlpha)
295         m_TransMethod = 3;
296       else
297         m_TransMethod = 4;
298     } else {
299       if (!m_bHasAlpha)
300         m_TransMethod = 5;
301       else
302         m_TransMethod = 6;
303     }
304   } else {
305     if (!m_bHasAlpha)
306       m_TransMethod = 7;
307     else
308       m_TransMethod = 8;
309   }
310 }
311 
~CStretchEngine()312 CStretchEngine::~CStretchEngine() {}
313 
Continue(IFX_PauseIndicator * pPause)314 bool CStretchEngine::Continue(IFX_PauseIndicator* pPause) {
315   while (m_State == 1) {
316     if (ContinueStretchHorz(pPause))
317       return true;
318 
319     m_State = 2;
320     StretchVert();
321   }
322   return false;
323 }
324 
StartStretchHorz()325 bool CStretchEngine::StartStretchHorz() {
326   if (m_DestWidth == 0 || m_InterPitch == 0 || m_DestScanline.empty())
327     return false;
328 
329   if (m_SrcClip.Height() == 0 ||
330       m_SrcClip.Height() > (1 << 29) / m_InterPitch) {
331     return false;
332   }
333 
334   m_InterBuf.resize(m_SrcClip.Height() * m_InterPitch);
335   if (m_pSource && m_bHasAlpha && m_pSource->m_pAlphaMask) {
336     m_ExtraAlphaBuf.resize(m_SrcClip.Height(), m_ExtraMaskPitch);
337     uint32_t size = (m_DestClip.Width() * 8 + 31) / 32 * 4;
338     m_DestMaskScanline.resize(size);
339   }
340   bool ret =
341       m_WeightTable.Calc(m_DestWidth, m_DestClip.left, m_DestClip.right,
342                          m_SrcWidth, m_SrcClip.left, m_SrcClip.right, m_Flags);
343   if (!ret)
344     return false;
345 
346   m_CurRow = m_SrcClip.top;
347   m_State = 1;
348   return true;
349 }
350 
ContinueStretchHorz(IFX_PauseIndicator * pPause)351 bool CStretchEngine::ContinueStretchHorz(IFX_PauseIndicator* pPause) {
352   if (!m_DestWidth)
353     return false;
354   if (m_pSource->SkipToScanline(m_CurRow, pPause))
355     return true;
356 
357   int Bpp = m_DestBpp / 8;
358   static const int kStrechPauseRows = 10;
359   int rows_to_go = kStrechPauseRows;
360   for (; m_CurRow < m_SrcClip.bottom; ++m_CurRow) {
361     if (rows_to_go == 0) {
362       if (pPause && pPause->NeedToPauseNow())
363         return true;
364 
365       rows_to_go = kStrechPauseRows;
366     }
367 
368     const uint8_t* src_scan = m_pSource->GetScanline(m_CurRow);
369     uint8_t* dest_scan =
370         m_InterBuf.data() + (m_CurRow - m_SrcClip.top) * m_InterPitch;
371     const uint8_t* src_scan_mask = nullptr;
372     uint8_t* dest_scan_mask = nullptr;
373     if (!m_ExtraAlphaBuf.empty()) {
374       src_scan_mask = m_pSource->m_pAlphaMask->GetScanline(m_CurRow);
375       dest_scan_mask = m_ExtraAlphaBuf.data() +
376                        (m_CurRow - m_SrcClip.top) * m_ExtraMaskPitch;
377     }
378     // TODO(npm): reduce duplicated code here
379     switch (m_TransMethod) {
380       case 1:
381       case 2: {
382         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
383           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
384           int dest_a = 0;
385           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
386             int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
387             if (!pWeight)
388               return false;
389 
390             int pixel_weight = *pWeight;
391             if (src_scan[j / 8] & (1 << (7 - j % 8)))
392               dest_a += pixel_weight * 255;
393           }
394           if (m_Flags & FXDIB_BICUBIC_INTERPOL)
395             dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
396           *dest_scan++ = static_cast<uint8_t>(dest_a >> 16);
397         }
398         break;
399       }
400       case 3: {
401         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
402           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
403           int dest_a = 0;
404           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
405             int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
406             if (!pWeight)
407               return false;
408 
409             int pixel_weight = *pWeight;
410             dest_a += pixel_weight * src_scan[j];
411           }
412           if (m_Flags & FXDIB_BICUBIC_INTERPOL)
413             dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
414           *dest_scan++ = static_cast<uint8_t>(dest_a >> 16);
415         }
416         break;
417       }
418       case 4: {
419         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
420           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
421           int dest_a = 0;
422           int dest_r = 0;
423           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
424             int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
425             if (!pWeight)
426               return false;
427 
428             int pixel_weight = *pWeight;
429             pixel_weight = pixel_weight * src_scan_mask[j] / 255;
430             dest_r += pixel_weight * src_scan[j];
431             dest_a += pixel_weight;
432           }
433           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
434             dest_r = pdfium::clamp(dest_r, 0, kMaxDestValue);
435             dest_a = pdfium::clamp(dest_a, 0, 65536);
436           }
437           *dest_scan++ = static_cast<uint8_t>(dest_r >> 16);
438           *dest_scan_mask++ = static_cast<uint8_t>((dest_a * 255) >> 16);
439         }
440         break;
441       }
442       case 5: {
443         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
444           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
445           int dest_r_y = 0;
446           int dest_g_m = 0;
447           int dest_b_c = 0;
448           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
449             int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
450             if (!pWeight)
451               return false;
452 
453             int pixel_weight = *pWeight;
454             unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]];
455             if (m_DestFormat == FXDIB_Rgb) {
456               dest_r_y += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 16);
457               dest_g_m += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 8);
458               dest_b_c += pixel_weight * static_cast<uint8_t>(argb_cmyk);
459             } else {
460               dest_b_c += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 24);
461               dest_g_m += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 16);
462               dest_r_y += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 8);
463             }
464           }
465           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
466             dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
467             dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
468             dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
469           }
470           *dest_scan++ = static_cast<uint8_t>(dest_b_c >> 16);
471           *dest_scan++ = static_cast<uint8_t>(dest_g_m >> 16);
472           *dest_scan++ = static_cast<uint8_t>(dest_r_y >> 16);
473         }
474         break;
475       }
476       case 6: {
477         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
478           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
479           int dest_a = 0;
480           int dest_r_y = 0;
481           int dest_g_m = 0;
482           int dest_b_c = 0;
483           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
484             int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
485             if (!pWeight)
486               return false;
487 
488             int pixel_weight = *pWeight;
489             pixel_weight = pixel_weight * src_scan_mask[j] / 255;
490             unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]];
491             if (m_DestFormat == FXDIB_Rgba) {
492               dest_r_y += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 16);
493               dest_g_m += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 8);
494               dest_b_c += pixel_weight * static_cast<uint8_t>(argb_cmyk);
495             } else {
496               dest_b_c += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 24);
497               dest_g_m += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 16);
498               dest_r_y += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 8);
499             }
500             dest_a += pixel_weight;
501           }
502           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
503             dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
504             dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
505             dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
506             dest_a = pdfium::clamp(dest_a, 0, 65536);
507           }
508           *dest_scan++ = static_cast<uint8_t>(dest_b_c >> 16);
509           *dest_scan++ = static_cast<uint8_t>(dest_g_m >> 16);
510           *dest_scan++ = static_cast<uint8_t>(dest_r_y >> 16);
511           *dest_scan_mask++ = static_cast<uint8_t>((dest_a * 255) >> 16);
512         }
513         break;
514       }
515       case 7: {
516         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
517           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
518           int dest_r_y = 0;
519           int dest_g_m = 0;
520           int dest_b_c = 0;
521           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
522             int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
523             if (!pWeight)
524               return false;
525 
526             int pixel_weight = *pWeight;
527             const uint8_t* src_pixel = src_scan + j * Bpp;
528             dest_b_c += pixel_weight * (*src_pixel++);
529             dest_g_m += pixel_weight * (*src_pixel++);
530             dest_r_y += pixel_weight * (*src_pixel);
531           }
532           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
533             dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
534             dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
535             dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
536           }
537           *dest_scan++ = static_cast<uint8_t>((dest_b_c) >> 16);
538           *dest_scan++ = static_cast<uint8_t>((dest_g_m) >> 16);
539           *dest_scan++ = static_cast<uint8_t>((dest_r_y) >> 16);
540           dest_scan += Bpp - 3;
541         }
542         break;
543       }
544       case 8: {
545         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
546           PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
547           int dest_a = 0;
548           int dest_r_y = 0;
549           int dest_g_m = 0;
550           int dest_b_c = 0;
551           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
552             int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
553             if (!pWeight)
554               return false;
555 
556             int pixel_weight = *pWeight;
557             const uint8_t* src_pixel = src_scan + j * Bpp;
558             if (m_DestFormat == FXDIB_Argb) {
559               pixel_weight = pixel_weight * src_pixel[3] / 255;
560             } else {
561               pixel_weight = pixel_weight * src_scan_mask[j] / 255;
562             }
563             dest_b_c += pixel_weight * (*src_pixel++);
564             dest_g_m += pixel_weight * (*src_pixel++);
565             dest_r_y += pixel_weight * (*src_pixel);
566             dest_a += pixel_weight;
567           }
568           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
569             dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
570             dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
571             dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
572             dest_a = pdfium::clamp(dest_a, 0, 65536);
573           }
574           *dest_scan++ = static_cast<uint8_t>((dest_b_c) >> 16);
575           *dest_scan++ = static_cast<uint8_t>((dest_g_m) >> 16);
576           *dest_scan++ = static_cast<uint8_t>((dest_r_y) >> 16);
577           if (m_DestFormat == FXDIB_Argb)
578             *dest_scan = static_cast<uint8_t>((dest_a * 255) >> 16);
579           if (dest_scan_mask)
580             *dest_scan_mask++ = static_cast<uint8_t>((dest_a * 255) >> 16);
581           dest_scan += Bpp - 3;
582         }
583         break;
584       }
585     }
586     rows_to_go--;
587   }
588   return false;
589 }
590 
StretchVert()591 void CStretchEngine::StretchVert() {
592   if (m_DestHeight == 0)
593     return;
594 
595   CWeightTable table;
596   bool ret = table.Calc(m_DestHeight, m_DestClip.top, m_DestClip.bottom,
597                         m_SrcHeight, m_SrcClip.top, m_SrcClip.bottom, m_Flags);
598   if (!ret)
599     return;
600 
601   const int DestBpp = m_DestBpp / 8;
602   for (int row = m_DestClip.top; row < m_DestClip.bottom; ++row) {
603     unsigned char* dest_scan = m_DestScanline.data();
604     unsigned char* dest_scan_mask = m_DestMaskScanline.data();
605     PixelWeight* pWeights = table.GetPixelWeight(row);
606     switch (m_TransMethod) {
607       case 1:
608       case 2:
609       case 3: {
610         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
611           unsigned char* src_scan =
612               m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
613           int dest_a = 0;
614           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
615             int* pWeight = table.GetValueFromPixelWeight(pWeights, j);
616             if (!pWeight)
617               return;
618 
619             int pixel_weight = *pWeight;
620             dest_a +=
621                 pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];
622           }
623           if (m_Flags & FXDIB_BICUBIC_INTERPOL)
624             dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
625           *dest_scan = static_cast<uint8_t>(dest_a >> 16);
626           dest_scan += DestBpp;
627         }
628         break;
629       }
630       case 4: {
631         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
632           unsigned char* src_scan =
633               m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
634           unsigned char* src_scan_mask =
635               m_ExtraAlphaBuf.data() + (col - m_DestClip.left);
636           int dest_a = 0;
637           int dest_k = 0;
638           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
639             int* pWeight = table.GetValueFromPixelWeight(pWeights, j);
640             if (!pWeight)
641               return;
642 
643             int pixel_weight = *pWeight;
644             dest_k +=
645                 pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];
646             dest_a += pixel_weight *
647                       src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch];
648           }
649           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
650             dest_k = pdfium::clamp(dest_k, 0, kMaxDestValue);
651             dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
652           }
653           *dest_scan = static_cast<uint8_t>(dest_k >> 16);
654           dest_scan += DestBpp;
655           *dest_scan_mask++ = static_cast<uint8_t>(dest_a >> 16);
656         }
657         break;
658       }
659       case 5:
660       case 7: {
661         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
662           unsigned char* src_scan =
663               m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
664           int dest_r_y = 0;
665           int dest_g_m = 0;
666           int dest_b_c = 0;
667           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
668             int* pWeight = table.GetValueFromPixelWeight(pWeights, j);
669             if (!pWeight)
670               return;
671 
672             int pixel_weight = *pWeight;
673             const uint8_t* src_pixel =
674                 src_scan + (j - m_SrcClip.top) * m_InterPitch;
675             dest_b_c += pixel_weight * (*src_pixel++);
676             dest_g_m += pixel_weight * (*src_pixel++);
677             dest_r_y += pixel_weight * (*src_pixel);
678           }
679           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
680             dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
681             dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
682             dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
683           }
684           dest_scan[0] = static_cast<uint8_t>((dest_b_c) >> 16);
685           dest_scan[1] = static_cast<uint8_t>((dest_g_m) >> 16);
686           dest_scan[2] = static_cast<uint8_t>((dest_r_y) >> 16);
687           dest_scan += DestBpp;
688         }
689         break;
690       }
691       case 6:
692       case 8: {
693         for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
694           unsigned char* src_scan =
695               m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
696           unsigned char* src_scan_mask = nullptr;
697           if (m_DestFormat != FXDIB_Argb)
698             src_scan_mask = m_ExtraAlphaBuf.data() + (col - m_DestClip.left);
699           int dest_a = 0;
700           int dest_r_y = 0;
701           int dest_g_m = 0;
702           int dest_b_c = 0;
703           for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
704             int* pWeight = table.GetValueFromPixelWeight(pWeights, j);
705             if (!pWeight)
706               return;
707 
708             int pixel_weight = *pWeight;
709             const uint8_t* src_pixel =
710                 src_scan + (j - m_SrcClip.top) * m_InterPitch;
711             int mask_v = 255;
712             if (src_scan_mask)
713               mask_v = src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch];
714             dest_b_c += pixel_weight * (*src_pixel++);
715             dest_g_m += pixel_weight * (*src_pixel++);
716             dest_r_y += pixel_weight * (*src_pixel);
717             if (m_DestFormat == FXDIB_Argb)
718               dest_a += pixel_weight * (*(src_pixel + 1));
719             else
720               dest_a += pixel_weight * mask_v;
721           }
722           if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
723             dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
724             dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
725             dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
726             dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
727           }
728           if (dest_a) {
729             int r = static_cast<uint32_t>(dest_r_y) * 255 / dest_a;
730             int g = static_cast<uint32_t>(dest_g_m) * 255 / dest_a;
731             int b = static_cast<uint32_t>(dest_b_c) * 255 / dest_a;
732             dest_scan[0] = pdfium::clamp(b, 0, 255);
733             dest_scan[1] = pdfium::clamp(g, 0, 255);
734             dest_scan[2] = pdfium::clamp(r, 0, 255);
735           }
736           if (m_DestFormat == FXDIB_Argb)
737             dest_scan[3] = static_cast<uint8_t>((dest_a) >> 16);
738           else
739             *dest_scan_mask = static_cast<uint8_t>((dest_a) >> 16);
740           dest_scan += DestBpp;
741           if (dest_scan_mask)
742             dest_scan_mask++;
743         }
744         break;
745       }
746     }
747     m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_DestScanline.data(),
748                                    m_DestMaskScanline.data());
749   }
750 }
751