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