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