• 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/cfx_imagetransformer.h"
8 
9 #include <cmath>
10 #include <memory>
11 #include <utility>
12 
13 #include "core/fxge/dib/cfx_imagestretcher.h"
14 #include "core/fxge/fx_dib.h"
15 #include "third_party/base/numerics/safe_conversions.h"
16 #include "third_party/base/ptr_util.h"
17 
18 namespace {
19 
20 constexpr int kBase = 256;
21 constexpr float kFix16 = 0.05f;
22 constexpr uint8_t kOpaqueAlpha = 0xff;
23 
bilinear_interpol(const uint8_t * buf,int row_offset_l,int row_offset_r,int src_col_l,int src_col_r,int res_x,int res_y,int bpp,int c_offset)24 uint8_t bilinear_interpol(const uint8_t* buf,
25                           int row_offset_l,
26                           int row_offset_r,
27                           int src_col_l,
28                           int src_col_r,
29                           int res_x,
30                           int res_y,
31                           int bpp,
32                           int c_offset) {
33   int i_resx = 255 - res_x;
34   int col_bpp_l = src_col_l * bpp;
35   int col_bpp_r = src_col_r * bpp;
36   const uint8_t* buf_u = buf + row_offset_l + c_offset;
37   const uint8_t* buf_d = buf + row_offset_r + c_offset;
38   const uint8_t* src_pos0 = buf_u + col_bpp_l;
39   const uint8_t* src_pos1 = buf_u + col_bpp_r;
40   const uint8_t* src_pos2 = buf_d + col_bpp_l;
41   const uint8_t* src_pos3 = buf_d + col_bpp_r;
42   uint8_t r_pos_0 = (*src_pos0 * i_resx + *src_pos1 * res_x) >> 8;
43   uint8_t r_pos_1 = (*src_pos2 * i_resx + *src_pos3 * res_x) >> 8;
44   return (r_pos_0 * (255 - res_y) + r_pos_1 * res_y) >> 8;
45 }
46 
bicubic_interpol(const uint8_t * buf,uint32_t pitch,const int pos_pixel[],const int u_w[],const int v_w[],int res_x,int res_y,int bpp,int c_offset)47 uint8_t bicubic_interpol(const uint8_t* buf,
48                          uint32_t pitch,
49                          const int pos_pixel[],
50                          const int u_w[],
51                          const int v_w[],
52                          int res_x,
53                          int res_y,
54                          int bpp,
55                          int c_offset) {
56   int s_result = 0;
57   for (int i = 0; i < 4; i++) {
58     int a_result = 0;
59     for (int j = 0; j < 4; j++) {
60       uint8_t val =
61           *(buf + pos_pixel[i + 4] * pitch + pos_pixel[j] * bpp + c_offset);
62       a_result += u_w[j] * val;
63     }
64     s_result += a_result * v_w[i];
65   }
66   s_result >>= 16;
67   return static_cast<uint8_t>(pdfium::clamp(s_result, 0, 255));
68 }
69 
bicubic_get_pos_weight(int pos_pixel[],int u_w[],int v_w[],int src_col_l,int src_row_l,int res_x,int res_y,int stretch_width,int stretch_height)70 void bicubic_get_pos_weight(int pos_pixel[],
71                             int u_w[],
72                             int v_w[],
73                             int src_col_l,
74                             int src_row_l,
75                             int res_x,
76                             int res_y,
77                             int stretch_width,
78                             int stretch_height) {
79   pos_pixel[0] = src_col_l - 1;
80   pos_pixel[1] = src_col_l;
81   pos_pixel[2] = src_col_l + 1;
82   pos_pixel[3] = src_col_l + 2;
83   pos_pixel[4] = src_row_l - 1;
84   pos_pixel[5] = src_row_l;
85   pos_pixel[6] = src_row_l + 1;
86   pos_pixel[7] = src_row_l + 2;
87   for (int i = 0; i < 4; i++) {
88     pos_pixel[i] = pdfium::clamp(pos_pixel[i], 0, stretch_width - 1);
89     pos_pixel[i + 4] = pdfium::clamp(pos_pixel[i + 4], 0, stretch_height - 1);
90   }
91   u_w[0] = SDP_Table[256 + res_x];
92   u_w[1] = SDP_Table[res_x];
93   u_w[2] = SDP_Table[256 - res_x];
94   u_w[3] = SDP_Table[512 - res_x];
95   v_w[0] = SDP_Table[256 + res_y];
96   v_w[1] = SDP_Table[res_y];
97   v_w[2] = SDP_Table[256 - res_y];
98   v_w[3] = SDP_Table[512 - res_y];
99 }
100 
GetTransformedFormat(const RetainPtr<CFX_DIBSource> & pDrc)101 FXDIB_Format GetTransformedFormat(const RetainPtr<CFX_DIBSource>& pDrc) {
102   if (pDrc->IsAlphaMask())
103     return FXDIB_8bppMask;
104 
105   FXDIB_Format format = pDrc->GetFormat();
106   if (format >= 1025)
107     return FXDIB_Cmyka;
108   if (format <= 32 || format == FXDIB_Argb)
109     return FXDIB_Argb;
110   return FXDIB_Rgba;
111 }
112 
NeedAlpha(bool bHasAlpha,FXDIB_Format format)113 bool NeedAlpha(bool bHasAlpha, FXDIB_Format format) {
114   return bHasAlpha || format == FXDIB_Cmyka;
115 }
116 
WriteMonoResult(uint32_t r_bgra_cmyk,FXDIB_Format format,uint8_t * dest)117 void WriteMonoResult(uint32_t r_bgra_cmyk, FXDIB_Format format, uint8_t* dest) {
118   if (format == FXDIB_Rgba) {
119     dest[0] = static_cast<uint8_t>(r_bgra_cmyk >> 24);
120     dest[1] = static_cast<uint8_t>(r_bgra_cmyk >> 16);
121     dest[2] = static_cast<uint8_t>(r_bgra_cmyk >> 8);
122   } else {
123     *reinterpret_cast<uint32_t*>(dest) = r_bgra_cmyk;
124   }
125 }
126 
WriteColorResult(std::function<uint8_t (int offset)> func,bool bHasAlpha,FXDIB_Format format,uint8_t * dest)127 void WriteColorResult(std::function<uint8_t(int offset)> func,
128                       bool bHasAlpha,
129                       FXDIB_Format format,
130                       uint8_t* dest) {
131   uint8_t blue_c = func(0);
132   uint8_t green_m = func(1);
133   uint8_t red_y = func(2);
134   uint8_t alpha_k = NeedAlpha(bHasAlpha, format) ? func(3) : kOpaqueAlpha;
135 
136   uint32_t* dest32 = reinterpret_cast<uint32_t*>(dest);
137   if (bHasAlpha) {
138     if (format == FXDIB_Argb) {
139       *dest32 = FXARGB_TODIB(FXARGB_MAKE(alpha_k, red_y, green_m, blue_c));
140     } else if (format == FXDIB_Rgba) {
141       dest[0] = blue_c;
142       dest[1] = green_m;
143       dest[2] = red_y;
144     } else {
145       *dest32 = FXCMYK_TODIB(CmykEncode(blue_c, green_m, red_y, alpha_k));
146     }
147     return;
148   }
149 
150   if (format == FXDIB_Cmyka) {
151     *dest32 = FXCMYK_TODIB(CmykEncode(blue_c, green_m, red_y, alpha_k));
152   } else {
153     ASSERT(alpha_k == kOpaqueAlpha);
154     *dest32 = FXARGB_TODIB(FXARGB_MAKE(kOpaqueAlpha, red_y, green_m, blue_c));
155   }
156 }
157 
158 class CPDF_FixedMatrix {
159  public:
CPDF_FixedMatrix(const CFX_Matrix & src)160   explicit CPDF_FixedMatrix(const CFX_Matrix& src)
161       : a(FXSYS_round(src.a * kBase)),
162         b(FXSYS_round(src.b * kBase)),
163         c(FXSYS_round(src.c * kBase)),
164         d(FXSYS_round(src.d * kBase)),
165         e(FXSYS_round(src.e * kBase)),
166         f(FXSYS_round(src.f * kBase)) {}
167 
Transform(int x,int y,int * x1,int * y1) const168   void Transform(int x, int y, int* x1, int* y1) const {
169     std::pair<float, float> val = TransformInternal(x, y);
170     *x1 = pdfium::base::saturated_cast<int>(val.first / kBase);
171     *y1 = pdfium::base::saturated_cast<int>(val.second / kBase);
172   }
173 
174  protected:
TransformInternal(float x,float y) const175   std::pair<float, float> TransformInternal(float x, float y) const {
176     return std::make_pair(a * x + c * y + e + kBase / 2,
177                           b * x + d * y + f + kBase / 2);
178   }
179 
180   const int a;
181   const int b;
182   const int c;
183   const int d;
184   const int e;
185   const int f;
186 };
187 
188 class CFX_BilinearMatrix : public CPDF_FixedMatrix {
189  public:
CFX_BilinearMatrix(const CFX_Matrix & src)190   explicit CFX_BilinearMatrix(const CFX_Matrix& src) : CPDF_FixedMatrix(src) {}
191 
Transform(int x,int y,int * x1,int * y1,int * res_x,int * res_y) const192   void Transform(int x, int y, int* x1, int* y1, int* res_x, int* res_y) const {
193     std::pair<float, float> val = TransformInternal(x, y);
194     *x1 = pdfium::base::saturated_cast<int>(val.first / kBase);
195     *y1 = pdfium::base::saturated_cast<int>(val.second / kBase);
196 
197     *res_x = static_cast<int>(fmodf(val.first, kBase));
198     *res_y = static_cast<int>(fmodf(val.second, kBase));
199     if (*res_x < 0 && *res_x > -kBase)
200       *res_x = kBase + *res_x;
201     if (*res_y < 0 && *res_x > -kBase)
202       *res_y = kBase + *res_y;
203   }
204 };
205 
206 }  // namespace
207 
CFX_ImageTransformer(const RetainPtr<CFX_DIBSource> & pSrc,const CFX_Matrix * pMatrix,int flags,const FX_RECT * pClip)208 CFX_ImageTransformer::CFX_ImageTransformer(const RetainPtr<CFX_DIBSource>& pSrc,
209                                            const CFX_Matrix* pMatrix,
210                                            int flags,
211                                            const FX_RECT* pClip)
212     : m_pSrc(pSrc),
213       m_pMatrix(pMatrix),
214       m_pClip(pClip),
215       m_Flags(flags),
216       m_Status(0) {
217   FX_RECT result_rect = m_pMatrix->GetUnitRect().GetClosestRect();
218   FX_RECT result_clip = result_rect;
219   if (m_pClip)
220     result_clip.Intersect(*m_pClip);
221 
222   if (result_clip.IsEmpty())
223     return;
224 
225   m_result = result_clip;
226   if (fabs(m_pMatrix->a) < fabs(m_pMatrix->b) / 20 &&
227       fabs(m_pMatrix->d) < fabs(m_pMatrix->c) / 20 &&
228       fabs(m_pMatrix->a) < 0.5f && fabs(m_pMatrix->d) < 0.5f) {
229     int dest_width = result_rect.Width();
230     int dest_height = result_rect.Height();
231     result_clip.Offset(-result_rect.left, -result_rect.top);
232     result_clip = FXDIB_SwapClipBox(result_clip, dest_width, dest_height,
233                                     m_pMatrix->c > 0, m_pMatrix->b < 0);
234     m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
235         &m_Storer, m_pSrc, dest_height, dest_width, result_clip, m_Flags);
236     m_Stretcher->Start();
237     m_Status = 1;
238     return;
239   }
240   if (fabs(m_pMatrix->b) < kFix16 && fabs(m_pMatrix->c) < kFix16) {
241     int dest_width = static_cast<int>(m_pMatrix->a > 0 ? ceil(m_pMatrix->a)
242                                                        : floor(m_pMatrix->a));
243     int dest_height = static_cast<int>(m_pMatrix->d > 0 ? -ceil(m_pMatrix->d)
244                                                         : -floor(m_pMatrix->d));
245     result_clip.Offset(-result_rect.left, -result_rect.top);
246     m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
247         &m_Storer, m_pSrc, dest_width, dest_height, result_clip, m_Flags);
248     m_Stretcher->Start();
249     m_Status = 2;
250     return;
251   }
252   int stretch_width =
253       static_cast<int>(ceil(FXSYS_sqrt2(m_pMatrix->a, m_pMatrix->b)));
254   int stretch_height =
255       static_cast<int>(ceil(FXSYS_sqrt2(m_pMatrix->c, m_pMatrix->d)));
256   CFX_Matrix stretch2dest(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, stretch_height);
257   stretch2dest.Concat(
258       CFX_Matrix(m_pMatrix->a / stretch_width, m_pMatrix->b / stretch_width,
259                  m_pMatrix->c / stretch_height, m_pMatrix->d / stretch_height,
260                  m_pMatrix->e, m_pMatrix->f));
261   m_dest2stretch = stretch2dest.GetInverse();
262 
263   m_StretchClip =
264       m_dest2stretch.TransformRect(CFX_FloatRect(result_clip)).GetOuterRect();
265   m_StretchClip.Intersect(0, 0, stretch_width, stretch_height);
266   m_Stretcher = pdfium::MakeUnique<CFX_ImageStretcher>(
267       &m_Storer, m_pSrc, stretch_width, stretch_height, m_StretchClip, m_Flags);
268   m_Stretcher->Start();
269   m_Status = 3;
270 }
271 
~CFX_ImageTransformer()272 CFX_ImageTransformer::~CFX_ImageTransformer() {}
273 
Continue(IFX_PauseIndicator * pPause)274 bool CFX_ImageTransformer::Continue(IFX_PauseIndicator* pPause) {
275   if (m_Status == 1) {
276     if (m_Stretcher->Continue(pPause))
277       return true;
278 
279     if (m_Storer.GetBitmap()) {
280       m_Storer.Replace(
281           m_Storer.GetBitmap()->SwapXY(m_pMatrix->c > 0, m_pMatrix->b < 0));
282     }
283     return false;
284   }
285 
286   if (m_Status == 2)
287     return m_Stretcher->Continue(pPause);
288   if (m_Status != 3)
289     return false;
290   if (m_Stretcher->Continue(pPause))
291     return true;
292 
293   if (!m_Storer.GetBitmap())
294     return false;
295 
296   auto pTransformed = pdfium::MakeRetain<CFX_DIBitmap>();
297   FXDIB_Format format = GetTransformedFormat(m_Stretcher->source());
298   if (!pTransformed->Create(m_result.Width(), m_result.Height(), format))
299     return false;
300 
301   const auto& pSrcMask = m_Storer.GetBitmap()->m_pAlphaMask;
302   const uint8_t* pSrcMaskBuf = pSrcMask ? pSrcMask->GetBuffer() : nullptr;
303 
304   pTransformed->Clear(0);
305   auto& pDestMask = pTransformed->m_pAlphaMask;
306   if (pDestMask)
307     pDestMask->Clear(0);
308 
309   CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, m_result.left,
310                             m_result.top);
311   result2stretch.Concat(m_dest2stretch);
312   result2stretch.Translate(-m_StretchClip.left, -m_StretchClip.top);
313   if (!pSrcMaskBuf && pDestMask) {
314     pDestMask->Clear(0xff000000);
315   } else if (pDestMask) {
316     CalcData cdata = {
317         pDestMask.Get(), result2stretch, pSrcMaskBuf,
318         m_Storer.GetBitmap()->m_pAlphaMask->GetPitch(),
319     };
320     CalcMask(cdata);
321   }
322 
323   CalcData cdata = {pTransformed.Get(), result2stretch,
324                     m_Storer.GetBitmap()->GetBuffer(),
325                     m_Storer.GetBitmap()->GetPitch()};
326   if (m_Storer.GetBitmap()->IsAlphaMask()) {
327     CalcAlpha(cdata);
328   } else {
329     int Bpp = m_Storer.GetBitmap()->GetBPP() / 8;
330     if (Bpp == 1)
331       CalcMono(cdata, format);
332     else
333       CalcColor(cdata, format, Bpp);
334   }
335   m_Storer.Replace(std::move(pTransformed));
336   return false;
337 }
338 
DetachBitmap()339 RetainPtr<CFX_DIBitmap> CFX_ImageTransformer::DetachBitmap() {
340   return m_Storer.Detach();
341 }
342 
CalcMask(const CalcData & cdata)343 void CFX_ImageTransformer::CalcMask(const CalcData& cdata) {
344   if (IsBilinear()) {
345     auto func = [&cdata](const BilinearData& data, uint8_t* dest) {
346       *dest = bilinear_interpol(cdata.buf, data.row_offset_l, data.row_offset_r,
347                                 data.src_col_l, data.src_col_r, data.res_x,
348                                 data.res_y, 1, 0);
349     };
350     DoBilinearLoop(cdata, 1, func);
351   } else if (IsBiCubic()) {
352     auto func = [&cdata](const BicubicData& data, uint8_t* dest) {
353       *dest = bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel, data.u_w,
354                                data.v_w, data.res_x, data.res_y, 1, 0);
355     };
356     DoBicubicLoop(cdata, 1, func);
357   } else {
358     auto func = [&cdata](const DownSampleData& data, uint8_t* dest) {
359       *dest = cdata.buf[data.src_row * cdata.pitch + data.src_col];
360     };
361     DoDownSampleLoop(cdata, 1, func);
362   }
363 }
364 
CalcAlpha(const CalcData & cdata)365 void CFX_ImageTransformer::CalcAlpha(const CalcData& cdata) {
366   if (IsBilinear()) {
367     auto func = [&cdata](const BilinearData& data, uint8_t* dest) {
368       *dest = bilinear_interpol(cdata.buf, data.row_offset_l, data.row_offset_r,
369                                 data.src_col_l, data.src_col_r, data.res_x,
370                                 data.res_y, 1, 0);
371     };
372     DoBilinearLoop(cdata, 1, func);
373   } else if (IsBiCubic()) {
374     auto func = [&cdata](const BicubicData& data, uint8_t* dest) {
375       *dest = bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel, data.u_w,
376                                data.v_w, data.res_x, data.res_y, 1, 0);
377     };
378     DoBicubicLoop(cdata, 1, func);
379   } else {
380     auto func = [&cdata](const DownSampleData& data, uint8_t* dest) {
381       const uint8_t* src_pixel =
382           cdata.buf + cdata.pitch * data.src_row + data.src_col;
383       *dest = *src_pixel;
384     };
385     DoDownSampleLoop(cdata, 1, func);
386   }
387 }
388 
CalcMono(const CalcData & cdata,FXDIB_Format format)389 void CFX_ImageTransformer::CalcMono(const CalcData& cdata,
390                                     FXDIB_Format format) {
391   uint32_t argb[256];
392   FX_ARGB* pPal = m_Storer.GetBitmap()->GetPalette();
393   if (pPal) {
394     for (size_t i = 0; i < FX_ArraySize(argb); i++)
395       argb[i] = pPal[i];
396   } else if (m_Storer.GetBitmap()->IsCmykImage()) {
397     for (size_t i = 0; i < FX_ArraySize(argb); i++)
398       argb[i] = 255 - i;
399   } else {
400     for (size_t i = 0; i < FX_ArraySize(argb); i++)
401       argb[i] = 0xff000000 | (i * 0x010101);
402   }
403   int destBpp = cdata.bitmap->GetBPP() / 8;
404   if (IsBilinear()) {
405     auto func = [&cdata, format, &argb](const BilinearData& data,
406                                         uint8_t* dest) {
407       uint8_t idx = bilinear_interpol(
408           cdata.buf, data.row_offset_l, data.row_offset_r, data.src_col_l,
409           data.src_col_r, data.res_x, data.res_y, 1, 0);
410       uint32_t r_bgra_cmyk = argb[idx];
411       WriteMonoResult(r_bgra_cmyk, format, dest);
412     };
413     DoBilinearLoop(cdata, destBpp, func);
414   } else if (IsBiCubic()) {
415     auto func = [&cdata, format, &argb](const BicubicData& data,
416                                         uint8_t* dest) {
417       uint32_t r_bgra_cmyk = argb[bicubic_interpol(
418           cdata.buf, cdata.pitch, data.pos_pixel, data.u_w, data.v_w,
419           data.res_x, data.res_y, 1, 0)];
420       WriteMonoResult(r_bgra_cmyk, format, dest);
421     };
422     DoBicubicLoop(cdata, destBpp, func);
423   } else {
424     auto func = [&cdata, format, &argb](const DownSampleData& data,
425                                         uint8_t* dest) {
426       uint32_t r_bgra_cmyk =
427           argb[cdata.buf[data.src_row * cdata.pitch + data.src_col]];
428       WriteMonoResult(r_bgra_cmyk, format, dest);
429     };
430     DoDownSampleLoop(cdata, destBpp, func);
431   }
432 }
433 
CalcColor(const CalcData & cdata,FXDIB_Format format,int Bpp)434 void CFX_ImageTransformer::CalcColor(const CalcData& cdata,
435                                      FXDIB_Format format,
436                                      int Bpp) {
437   bool bHasAlpha = m_Storer.GetBitmap()->HasAlpha();
438   int destBpp = cdata.bitmap->GetBPP() / 8;
439   if (IsBilinear()) {
440     auto func = [&cdata, format, Bpp, bHasAlpha](const BilinearData& data,
441                                                  uint8_t* dest) {
442       auto bilinear_interpol_func = [&cdata, &data, Bpp](int offset) {
443         return bilinear_interpol(
444             cdata.buf, data.row_offset_l, data.row_offset_r, data.src_col_l,
445             data.src_col_r, data.res_x, data.res_y, Bpp, offset);
446       };
447       WriteColorResult(bilinear_interpol_func, bHasAlpha, format, dest);
448     };
449     DoBilinearLoop(cdata, destBpp, func);
450   } else if (IsBiCubic()) {
451     auto func = [&cdata, format, Bpp, bHasAlpha](const BicubicData& data,
452                                                  uint8_t* dest) {
453       auto bicubic_interpol_func = [&cdata, &data, Bpp](int offset) {
454         return bicubic_interpol(cdata.buf, cdata.pitch, data.pos_pixel,
455                                 data.u_w, data.v_w, data.res_x, data.res_y, Bpp,
456                                 offset);
457       };
458       WriteColorResult(bicubic_interpol_func, bHasAlpha, format, dest);
459     };
460     DoBicubicLoop(cdata, destBpp, func);
461   } else {
462     auto func = [&cdata, format, bHasAlpha, Bpp](const DownSampleData& data,
463                                                  uint8_t* dest) {
464       const uint8_t* src_pos =
465           cdata.buf + data.src_row * cdata.pitch + data.src_col * Bpp;
466       auto sample_func = [src_pos](int offset) { return src_pos[offset]; };
467       WriteColorResult(sample_func, bHasAlpha, format, dest);
468     };
469     DoDownSampleLoop(cdata, destBpp, func);
470   }
471 }
472 
AdjustCoords(int * col,int * row) const473 void CFX_ImageTransformer::AdjustCoords(int* col, int* row) const {
474   int& src_col = *col;
475   int& src_row = *row;
476   if (src_col == stretch_width())
477     src_col--;
478   if (src_row == stretch_height())
479     src_row--;
480 }
481 
DoBilinearLoop(const CalcData & cdata,int increment,std::function<void (const BilinearData &,uint8_t *)> func)482 void CFX_ImageTransformer::DoBilinearLoop(
483     const CalcData& cdata,
484     int increment,
485     std::function<void(const BilinearData&, uint8_t*)> func) {
486   CFX_BilinearMatrix matrix_fix(cdata.matrix);
487   for (int row = 0; row < m_result.Height(); row++) {
488     uint8_t* dest = const_cast<uint8_t*>(cdata.bitmap->GetScanline(row));
489     for (int col = 0; col < m_result.Width(); col++) {
490       BilinearData d;
491       d.res_x = 0;
492       d.res_y = 0;
493       d.src_col_l = 0;
494       d.src_row_l = 0;
495       matrix_fix.Transform(col, row, &d.src_col_l, &d.src_row_l, &d.res_x,
496                            &d.res_y);
497       if (InStretchBounds(d.src_col_l, d.src_row_l)) {
498         AdjustCoords(&d.src_col_l, &d.src_row_l);
499         d.src_col_r = d.src_col_l + 1;
500         d.src_row_r = d.src_row_l + 1;
501         AdjustCoords(&d.src_col_r, &d.src_row_r);
502         d.row_offset_l = d.src_row_l * cdata.pitch;
503         d.row_offset_r = d.src_row_r * cdata.pitch;
504         func(d, dest);
505       }
506       dest += increment;
507     }
508   }
509 }
510 
DoBicubicLoop(const CalcData & cdata,int increment,std::function<void (const BicubicData &,uint8_t *)> func)511 void CFX_ImageTransformer::DoBicubicLoop(
512     const CalcData& cdata,
513     int increment,
514     std::function<void(const BicubicData&, uint8_t*)> func) {
515   CFX_BilinearMatrix matrix_fix(cdata.matrix);
516   for (int row = 0; row < m_result.Height(); row++) {
517     uint8_t* dest = const_cast<uint8_t*>(cdata.bitmap->GetScanline(row));
518     for (int col = 0; col < m_result.Width(); col++) {
519       BicubicData d;
520       d.res_x = 0;
521       d.res_y = 0;
522       d.src_col_l = 0;
523       d.src_row_l = 0;
524       matrix_fix.Transform(col, row, &d.src_col_l, &d.src_row_l, &d.res_x,
525                            &d.res_y);
526       if (InStretchBounds(d.src_col_l, d.src_row_l)) {
527         AdjustCoords(&d.src_col_l, &d.src_row_l);
528         bicubic_get_pos_weight(d.pos_pixel, d.u_w, d.v_w, d.src_col_l,
529                                d.src_row_l, d.res_x, d.res_y, stretch_width(),
530                                stretch_height());
531         func(d, dest);
532       }
533       dest += increment;
534     }
535   }
536 }
537 
DoDownSampleLoop(const CalcData & cdata,int increment,std::function<void (const DownSampleData &,uint8_t *)> func)538 void CFX_ImageTransformer::DoDownSampleLoop(
539     const CalcData& cdata,
540     int increment,
541     std::function<void(const DownSampleData&, uint8_t*)> func) {
542   CPDF_FixedMatrix matrix_fix(cdata.matrix);
543   for (int row = 0; row < m_result.Height(); row++) {
544     uint8_t* dest = const_cast<uint8_t*>(cdata.bitmap->GetScanline(row));
545     for (int col = 0; col < m_result.Width(); col++) {
546       DownSampleData d;
547       d.src_col = 0;
548       d.src_row = 0;
549       matrix_fix.Transform(col, row, &d.src_col, &d.src_row);
550       if (InStretchBounds(d.src_col, d.src_row)) {
551         AdjustCoords(&d.src_col, &d.src_row);
552         func(d, dest);
553       }
554       dest += increment;
555     }
556   }
557 }
558