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 "core/fxge/dib/dib_int.h"
8 
9 #include "core/fxge/include/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 nullptr;
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 nullptr;
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         uint32_t* src_scan = (uint32_t*)GetScanline(row) + col_start;
233         for (int col = col_start; col < col_end; col++) {
234           *(uint32_t*)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 }
299 
TransformTo(const CFX_Matrix * pDestMatrix,int & result_left,int & result_top,uint32_t flags,const FX_RECT * pDestClip) const300 CFX_DIBitmap* CFX_DIBSource::TransformTo(const CFX_Matrix* pDestMatrix,
301                                          int& result_left,
302                                          int& result_top,
303                                          uint32_t flags,
304                                          const FX_RECT* pDestClip) const {
305   CFX_ImageTransformer transformer(this, pDestMatrix, flags, pDestClip);
306   transformer.Start();
307   transformer.Continue(nullptr);
308   result_left = transformer.result().left;
309   result_top = transformer.result().top;
310   return transformer.DetachBitmap().release();
311 }
312 
StretchTo(int dest_width,int dest_height,uint32_t flags,const FX_RECT * pClip) const313 CFX_DIBitmap* CFX_DIBSource::StretchTo(int dest_width,
314                                        int dest_height,
315                                        uint32_t flags,
316                                        const FX_RECT* pClip) const {
317   FX_RECT clip_rect(0, 0, FXSYS_abs(dest_width), FXSYS_abs(dest_height));
318   if (pClip)
319     clip_rect.Intersect(*pClip);
320 
321   if (clip_rect.IsEmpty())
322     return nullptr;
323 
324   if (dest_width == m_Width && dest_height == m_Height)
325     return Clone(&clip_rect);
326 
327   CFX_BitmapStorer storer;
328   CFX_ImageStretcher stretcher(&storer, this, dest_width, dest_height,
329                                clip_rect, flags);
330   if (stretcher.Start())
331     stretcher.Continue(nullptr);
332   return storer.Detach().release();
333 }
334 
CFX_ImageTransformer(const CFX_DIBSource * pSrc,const CFX_Matrix * pMatrix,int flags,const FX_RECT * pClip)335 CFX_ImageTransformer::CFX_ImageTransformer(const CFX_DIBSource* pSrc,
336                                            const CFX_Matrix* pMatrix,
337                                            int flags,
338                                            const FX_RECT* pClip)
339     : m_pSrc(pSrc),
340       m_pMatrix(pMatrix),
341       m_pClip(pClip),
342       m_Flags(flags),
343       m_Status(0) {}
344 
~CFX_ImageTransformer()345 CFX_ImageTransformer::~CFX_ImageTransformer() {}
346 
Start()347 FX_BOOL CFX_ImageTransformer::Start() {
348   CFX_FloatRect unit_rect = m_pMatrix->GetUnitRect();
349   FX_RECT result_rect = unit_rect.GetClosestRect();
350   FX_RECT result_clip = result_rect;
351   if (m_pClip)
352     result_clip.Intersect(*m_pClip);
353 
354   if (result_clip.IsEmpty())
355     return FALSE;
356 
357   m_result = result_clip;
358   if (FXSYS_fabs(m_pMatrix->a) < FXSYS_fabs(m_pMatrix->b) / 20 &&
359       FXSYS_fabs(m_pMatrix->d) < FXSYS_fabs(m_pMatrix->c) / 20 &&
360       FXSYS_fabs(m_pMatrix->a) < 0.5f && FXSYS_fabs(m_pMatrix->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                                     m_pMatrix->c > 0, m_pMatrix->b < 0);
366     m_Stretcher.reset(new CFX_ImageStretcher(&m_Storer, m_pSrc, dest_height,
367                                              dest_width, result_clip, m_Flags));
368     m_Stretcher->Start();
369     m_Status = 1;
370     return TRUE;
371   }
372   if (FXSYS_fabs(m_pMatrix->b) < FIX16_005 &&
373       FXSYS_fabs(m_pMatrix->c) < FIX16_005) {
374     int dest_width = m_pMatrix->a > 0 ? (int)FXSYS_ceil(m_pMatrix->a)
375                                       : (int)FXSYS_floor(m_pMatrix->a);
376     int dest_height = m_pMatrix->d > 0 ? (int)-FXSYS_ceil(m_pMatrix->d)
377                                        : (int)-FXSYS_floor(m_pMatrix->d);
378     result_clip.Offset(-result_rect.left, -result_rect.top);
379     m_Stretcher.reset(new CFX_ImageStretcher(
380         &m_Storer, m_pSrc, dest_width, dest_height, result_clip, m_Flags));
381     m_Stretcher->Start();
382     m_Status = 2;
383     return TRUE;
384   }
385   int stretch_width = (int)FXSYS_ceil(FXSYS_sqrt2(m_pMatrix->a, m_pMatrix->b));
386   int stretch_height = (int)FXSYS_ceil(FXSYS_sqrt2(m_pMatrix->c, m_pMatrix->d));
387   CFX_Matrix stretch2dest(1.0f, 0.0f, 0.0f, -1.0f, 0.0f,
388                           (FX_FLOAT)(stretch_height));
389   stretch2dest.Concat(
390       m_pMatrix->a / stretch_width, m_pMatrix->b / stretch_width,
391       m_pMatrix->c / stretch_height, m_pMatrix->d / stretch_height,
392       m_pMatrix->e, m_pMatrix->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.reset(new CFX_ImageStretcher(&m_Storer, m_pSrc, stretch_width,
399                                            stretch_height, m_StretchClip,
400                                            m_Flags));
401   m_Stretcher->Start();
402   m_Status = 3;
403   return TRUE;
404 }
405 
Continue(IFX_Pause * pPause)406 FX_BOOL CFX_ImageTransformer::Continue(IFX_Pause* pPause) {
407   if (m_Status == 1) {
408     if (m_Stretcher->Continue(pPause))
409       return TRUE;
410 
411     if (m_Storer.GetBitmap()) {
412       std::unique_ptr<CFX_DIBitmap> swapped(
413           m_Storer.GetBitmap()->SwapXY(m_pMatrix->c > 0, m_pMatrix->b < 0));
414       m_Storer.Replace(std::move(swapped));
415     }
416     return FALSE;
417   }
418 
419   if (m_Status == 2)
420     return m_Stretcher->Continue(pPause);
421 
422   if (m_Status != 3)
423     return FALSE;
424 
425   if (m_Stretcher->Continue(pPause))
426     return TRUE;
427 
428   int stretch_width = m_StretchClip.Width();
429   int stretch_height = m_StretchClip.Height();
430   if (!m_Storer.GetBitmap())
431     return FALSE;
432 
433   const uint8_t* stretch_buf = m_Storer.GetBitmap()->GetBuffer();
434   const uint8_t* stretch_buf_mask = nullptr;
435   if (m_Storer.GetBitmap()->m_pAlphaMask)
436     stretch_buf_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetBuffer();
437 
438   int stretch_pitch = m_Storer.GetBitmap()->GetPitch();
439   std::unique_ptr<CFX_DIBitmap> pTransformed(new CFX_DIBitmap);
440   FXDIB_Format transformF = GetTransformedFormat(m_Stretcher->source());
441   if (!pTransformed->Create(m_result.Width(), m_result.Height(), transformF))
442     return FALSE;
443 
444   pTransformed->Clear(0);
445   if (pTransformed->m_pAlphaMask)
446     pTransformed->m_pAlphaMask->Clear(0);
447 
448   CFX_Matrix result2stretch(1.0f, 0.0f, 0.0f, 1.0f, (FX_FLOAT)(m_result.left),
449                             (FX_FLOAT)(m_result.top));
450   result2stretch.Concat(m_dest2stretch);
451   result2stretch.TranslateI(-m_StretchClip.left, -m_StretchClip.top);
452   if (!stretch_buf_mask && pTransformed->m_pAlphaMask) {
453     pTransformed->m_pAlphaMask->Clear(0xff000000);
454   } else if (pTransformed->m_pAlphaMask) {
455     int stretch_pitch_mask = m_Storer.GetBitmap()->m_pAlphaMask->GetPitch();
456     if (!(m_Flags & FXDIB_DOWNSAMPLE) && !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
457       CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
458       for (int row = 0; row < m_result.Height(); row++) {
459         uint8_t* dest_pos_mask =
460             (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
461         for (int col = 0; col < m_result.Width(); col++) {
462           int src_col_l, src_row_l, res_x, res_y;
463           result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
464                                        res_y);
465           if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
466               src_row_l <= stretch_height) {
467             if (src_col_l == stretch_width) {
468               src_col_l--;
469             }
470             if (src_row_l == stretch_height) {
471               src_row_l--;
472             }
473             int src_col_r = src_col_l + 1;
474             int src_row_r = src_row_l + 1;
475             if (src_col_r == stretch_width) {
476               src_col_r--;
477             }
478             if (src_row_r == stretch_height) {
479               src_row_r--;
480             }
481             int row_offset_l = src_row_l * stretch_pitch_mask;
482             int row_offset_r = src_row_r * stretch_pitch_mask;
483             *dest_pos_mask =
484                 bilinear_interpol(stretch_buf_mask, row_offset_l, row_offset_r,
485                                   src_col_l, src_col_r, res_x, res_y, 1, 0);
486           }
487           dest_pos_mask++;
488         }
489       }
490     } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
491       CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
492       for (int row = 0; row < m_result.Height(); row++) {
493         uint8_t* dest_pos_mask =
494             (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
495         for (int col = 0; col < m_result.Width(); col++) {
496           int src_col_l, src_row_l, res_x, res_y;
497           result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
498                                        res_y);
499           if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
500               src_row_l <= stretch_height) {
501             int pos_pixel[8];
502             int u_w[4], v_w[4];
503             if (src_col_l == stretch_width) {
504               src_col_l--;
505             }
506             if (src_row_l == stretch_height) {
507               src_row_l--;
508             }
509             bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
510                                    res_x, res_y, stretch_width, stretch_height);
511             *dest_pos_mask =
512                 bicubic_interpol(stretch_buf_mask, stretch_pitch_mask,
513                                  pos_pixel, u_w, v_w, res_x, res_y, 1, 0);
514           }
515           dest_pos_mask++;
516         }
517       }
518     } else {
519       CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
520       for (int row = 0; row < m_result.Height(); row++) {
521         uint8_t* dest_pos_mask =
522             (uint8_t*)pTransformed->m_pAlphaMask->GetScanline(row);
523         for (int col = 0; col < m_result.Width(); col++) {
524           int src_col, src_row;
525           result2stretch_fix.Transform(col, row, src_col, src_row);
526           if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
527               src_row <= stretch_height) {
528             if (src_col == stretch_width) {
529               src_col--;
530             }
531             if (src_row == stretch_height) {
532               src_row--;
533             }
534             *dest_pos_mask =
535                 stretch_buf_mask[src_row * stretch_pitch_mask + src_col];
536           }
537           dest_pos_mask++;
538         }
539       }
540     }
541   }
542   if (m_Storer.GetBitmap()->IsAlphaMask()) {
543     if (!(m_Flags & FXDIB_DOWNSAMPLE) && !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
544       CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
545       for (int row = 0; row < m_result.Height(); row++) {
546         uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
547         for (int col = 0; col < m_result.Width(); col++) {
548           int src_col_l, src_row_l, res_x, res_y;
549           result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
550                                        res_y);
551           if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
552               src_row_l <= stretch_height) {
553             if (src_col_l == stretch_width) {
554               src_col_l--;
555             }
556             if (src_row_l == stretch_height) {
557               src_row_l--;
558             }
559             int src_col_r = src_col_l + 1;
560             int src_row_r = src_row_l + 1;
561             if (src_col_r == stretch_width) {
562               src_col_r--;
563             }
564             if (src_row_r == stretch_height) {
565               src_row_r--;
566             }
567             int row_offset_l = src_row_l * stretch_pitch;
568             int row_offset_r = src_row_r * stretch_pitch;
569             *dest_scan =
570                 bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
571                                   src_col_l, src_col_r, res_x, res_y, 1, 0);
572           }
573           dest_scan++;
574         }
575       }
576     } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
577       CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
578       for (int row = 0; row < m_result.Height(); row++) {
579         uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
580         for (int col = 0; col < m_result.Width(); col++) {
581           int src_col_l, src_row_l, res_x, res_y;
582           result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
583                                        res_y);
584           if (src_col_l >= 0 && src_col_l <= stretch_width && src_row_l >= 0 &&
585               src_row_l <= stretch_height) {
586             int pos_pixel[8];
587             int u_w[4], v_w[4];
588             if (src_col_l == stretch_width) {
589               src_col_l--;
590             }
591             if (src_row_l == stretch_height) {
592               src_row_l--;
593             }
594             bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
595                                    res_x, res_y, stretch_width, stretch_height);
596             *dest_scan = bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
597                                           u_w, v_w, res_x, res_y, 1, 0);
598           }
599           dest_scan++;
600         }
601       }
602     } else {
603       CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
604       for (int row = 0; row < m_result.Height(); row++) {
605         uint8_t* dest_scan = (uint8_t*)pTransformed->GetScanline(row);
606         for (int col = 0; col < m_result.Width(); col++) {
607           int src_col, src_row;
608           result2stretch_fix.Transform(col, row, src_col, src_row);
609           if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
610               src_row <= stretch_height) {
611             if (src_col == stretch_width) {
612               src_col--;
613             }
614             if (src_row == stretch_height) {
615               src_row--;
616             }
617             const uint8_t* src_pixel =
618                 stretch_buf + stretch_pitch * src_row + src_col;
619             *dest_scan = *src_pixel;
620           }
621           dest_scan++;
622         }
623       }
624     }
625   } else {
626     int Bpp = m_Storer.GetBitmap()->GetBPP() / 8;
627     if (Bpp == 1) {
628       uint32_t argb[256];
629       FX_ARGB* pPal = m_Storer.GetBitmap()->GetPalette();
630       if (pPal) {
631         for (int i = 0; i < 256; i++) {
632           argb[i] = pPal[i];
633         }
634       } else {
635         if (m_Storer.GetBitmap()->IsCmykImage()) {
636           for (int i = 0; i < 256; i++) {
637             argb[i] = 255 - i;
638           }
639         } else {
640           for (int i = 0; i < 256; i++) {
641             argb[i] = 0xff000000 | (i * 0x010101);
642           }
643         }
644       }
645       int destBpp = pTransformed->GetBPP() / 8;
646       if (!(m_Flags & FXDIB_DOWNSAMPLE) &&
647           !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
648         CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
649         for (int row = 0; row < m_result.Height(); row++) {
650           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
651           for (int col = 0; col < m_result.Width(); col++) {
652             int src_col_l, src_row_l, res_x, res_y;
653             result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
654                                          res_y);
655             if (src_col_l >= 0 && src_col_l <= stretch_width &&
656                 src_row_l >= 0 && src_row_l <= stretch_height) {
657               if (src_col_l == stretch_width) {
658                 src_col_l--;
659               }
660               if (src_row_l == stretch_height) {
661                 src_row_l--;
662               }
663               int src_col_r = src_col_l + 1;
664               int src_row_r = src_row_l + 1;
665               if (src_col_r == stretch_width) {
666                 src_col_r--;
667               }
668               if (src_row_r == stretch_height) {
669                 src_row_r--;
670               }
671               int row_offset_l = src_row_l * stretch_pitch;
672               int row_offset_r = src_row_r * stretch_pitch;
673               uint32_t r_bgra_cmyk = argb[bilinear_interpol(
674                   stretch_buf, row_offset_l, row_offset_r, src_col_l, src_col_r,
675                   res_x, res_y, 1, 0)];
676               if (transformF == FXDIB_Rgba) {
677                 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
678                 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
679                 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
680               } else {
681                 *(uint32_t*)dest_pos = r_bgra_cmyk;
682               }
683             }
684             dest_pos += destBpp;
685           }
686         }
687       } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
688         CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
689         for (int row = 0; row < m_result.Height(); row++) {
690           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
691           for (int col = 0; col < m_result.Width(); col++) {
692             int src_col_l, src_row_l, res_x, res_y;
693             result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
694                                          res_y);
695             if (src_col_l >= 0 && src_col_l <= stretch_width &&
696                 src_row_l >= 0 && src_row_l <= stretch_height) {
697               int pos_pixel[8];
698               int u_w[4], v_w[4];
699               if (src_col_l == stretch_width) {
700                 src_col_l--;
701               }
702               if (src_row_l == stretch_height) {
703                 src_row_l--;
704               }
705               bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
706                                      res_x, res_y, stretch_width,
707                                      stretch_height);
708               uint32_t r_bgra_cmyk =
709                   argb[bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
710                                         u_w, v_w, res_x, res_y, 1, 0)];
711               if (transformF == FXDIB_Rgba) {
712                 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
713                 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
714                 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
715               } else {
716                 *(uint32_t*)dest_pos = r_bgra_cmyk;
717               }
718             }
719             dest_pos += destBpp;
720           }
721         }
722       } else {
723         CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
724         for (int row = 0; row < m_result.Height(); row++) {
725           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
726           for (int col = 0; col < m_result.Width(); col++) {
727             int src_col, src_row;
728             result2stretch_fix.Transform(col, row, src_col, src_row);
729             if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
730                 src_row <= stretch_height) {
731               if (src_col == stretch_width) {
732                 src_col--;
733               }
734               if (src_row == stretch_height) {
735                 src_row--;
736               }
737               uint32_t r_bgra_cmyk =
738                   argb[stretch_buf[src_row * stretch_pitch + src_col]];
739               if (transformF == FXDIB_Rgba) {
740                 dest_pos[0] = (uint8_t)(r_bgra_cmyk >> 24);
741                 dest_pos[1] = (uint8_t)(r_bgra_cmyk >> 16);
742                 dest_pos[2] = (uint8_t)(r_bgra_cmyk >> 8);
743               } else {
744                 *(uint32_t*)dest_pos = r_bgra_cmyk;
745               }
746             }
747             dest_pos += destBpp;
748           }
749         }
750       }
751     } else {
752       FX_BOOL bHasAlpha = m_Storer.GetBitmap()->HasAlpha();
753       int destBpp = pTransformed->GetBPP() / 8;
754       if (!(m_Flags & FXDIB_DOWNSAMPLE) &&
755           !(m_Flags & FXDIB_BICUBIC_INTERPOL)) {
756         CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
757         for (int row = 0; row < m_result.Height(); row++) {
758           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
759           for (int col = 0; col < m_result.Width(); col++) {
760             int src_col_l, src_row_l, res_x, res_y, r_pos_k_r = 0;
761             result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
762                                          res_y);
763             if (src_col_l >= 0 && src_col_l <= stretch_width &&
764                 src_row_l >= 0 && src_row_l <= stretch_height) {
765               if (src_col_l == stretch_width) {
766                 src_col_l--;
767               }
768               if (src_row_l == stretch_height) {
769                 src_row_l--;
770               }
771               int src_col_r = src_col_l + 1;
772               int src_row_r = src_row_l + 1;
773               if (src_col_r == stretch_width) {
774                 src_col_r--;
775               }
776               if (src_row_r == stretch_height) {
777                 src_row_r--;
778               }
779               int row_offset_l = src_row_l * stretch_pitch;
780               int row_offset_r = src_row_r * stretch_pitch;
781               uint8_t r_pos_red_y_r =
782                   bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
783                                     src_col_l, src_col_r, res_x, res_y, Bpp, 2);
784               uint8_t r_pos_green_m_r =
785                   bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
786                                     src_col_l, src_col_r, res_x, res_y, Bpp, 1);
787               uint8_t r_pos_blue_c_r =
788                   bilinear_interpol(stretch_buf, row_offset_l, row_offset_r,
789                                     src_col_l, src_col_r, res_x, res_y, Bpp, 0);
790               if (bHasAlpha) {
791                 if (transformF != FXDIB_Argb) {
792                   if (transformF == FXDIB_Rgba) {
793                     dest_pos[0] = r_pos_blue_c_r;
794                     dest_pos[1] = r_pos_green_m_r;
795                     dest_pos[2] = r_pos_red_y_r;
796                   } else {
797                     r_pos_k_r = bilinear_interpol(
798                         stretch_buf, row_offset_l, row_offset_r, src_col_l,
799                         src_col_r, res_x, res_y, Bpp, 3);
800                     *(uint32_t*)dest_pos =
801                         FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
802                                                 r_pos_red_y_r, r_pos_k_r));
803                   }
804                 } else {
805                   uint8_t r_pos_a_r = bilinear_interpol(
806                       stretch_buf, row_offset_l, row_offset_r, src_col_l,
807                       src_col_r, res_x, res_y, Bpp, 3);
808                   *(uint32_t*)dest_pos = FXARGB_TODIB(
809                       FXARGB_MAKE(r_pos_a_r, r_pos_red_y_r, r_pos_green_m_r,
810                                   r_pos_blue_c_r));
811                 }
812               } else {
813                 r_pos_k_r = 0xff;
814                 if (transformF == FXDIB_Cmyka) {
815                   r_pos_k_r = bilinear_interpol(
816                       stretch_buf, row_offset_l, row_offset_r, src_col_l,
817                       src_col_r, res_x, res_y, Bpp, 3);
818                   *(uint32_t*)dest_pos =
819                       FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
820                                               r_pos_red_y_r, r_pos_k_r));
821                 } else {
822                   *(uint32_t*)dest_pos = FXARGB_TODIB(
823                       FXARGB_MAKE(r_pos_k_r, r_pos_red_y_r, r_pos_green_m_r,
824                                   r_pos_blue_c_r));
825                 }
826               }
827             }
828             dest_pos += destBpp;
829           }
830         }
831       } else if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
832         CFX_BilinearMatrix result2stretch_fix(result2stretch, 8);
833         for (int row = 0; row < m_result.Height(); row++) {
834           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
835           for (int col = 0; col < m_result.Width(); col++) {
836             int src_col_l, src_row_l, res_x, res_y, r_pos_k_r = 0;
837             result2stretch_fix.Transform(col, row, src_col_l, src_row_l, res_x,
838                                          res_y);
839             if (src_col_l >= 0 && src_col_l <= stretch_width &&
840                 src_row_l >= 0 && src_row_l <= stretch_height) {
841               int pos_pixel[8];
842               int u_w[4], v_w[4];
843               if (src_col_l == stretch_width) {
844                 src_col_l--;
845               }
846               if (src_row_l == stretch_height) {
847                 src_row_l--;
848               }
849               bicubic_get_pos_weight(pos_pixel, u_w, v_w, src_col_l, src_row_l,
850                                      res_x, res_y, stretch_width,
851                                      stretch_height);
852               uint8_t r_pos_red_y_r =
853                   bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
854                                    v_w, res_x, res_y, Bpp, 2);
855               uint8_t r_pos_green_m_r =
856                   bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
857                                    v_w, res_x, res_y, Bpp, 1);
858               uint8_t r_pos_blue_c_r =
859                   bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel, u_w,
860                                    v_w, res_x, res_y, Bpp, 0);
861               if (bHasAlpha) {
862                 if (transformF != FXDIB_Argb) {
863                   if (transformF == FXDIB_Rgba) {
864                     dest_pos[0] = r_pos_blue_c_r;
865                     dest_pos[1] = r_pos_green_m_r;
866                     dest_pos[2] = r_pos_red_y_r;
867                   } else {
868                     r_pos_k_r =
869                         bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
870                                          u_w, v_w, res_x, res_y, Bpp, 3);
871                     *(uint32_t*)dest_pos =
872                         FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
873                                                 r_pos_red_y_r, r_pos_k_r));
874                   }
875                 } else {
876                   uint8_t r_pos_a_r =
877                       bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
878                                        u_w, v_w, res_x, res_y, Bpp, 3);
879                   *(uint32_t*)dest_pos = FXARGB_TODIB(
880                       FXARGB_MAKE(r_pos_a_r, r_pos_red_y_r, r_pos_green_m_r,
881                                   r_pos_blue_c_r));
882                 }
883               } else {
884                 r_pos_k_r = 0xff;
885                 if (transformF == FXDIB_Cmyka) {
886                   r_pos_k_r =
887                       bicubic_interpol(stretch_buf, stretch_pitch, pos_pixel,
888                                        u_w, v_w, res_x, res_y, Bpp, 3);
889                   *(uint32_t*)dest_pos =
890                       FXCMYK_TODIB(CmykEncode(r_pos_blue_c_r, r_pos_green_m_r,
891                                               r_pos_red_y_r, r_pos_k_r));
892                 } else {
893                   *(uint32_t*)dest_pos = FXARGB_TODIB(
894                       FXARGB_MAKE(r_pos_k_r, r_pos_red_y_r, r_pos_green_m_r,
895                                   r_pos_blue_c_r));
896                 }
897               }
898             }
899             dest_pos += destBpp;
900           }
901         }
902       } else {
903         CPDF_FixedMatrix result2stretch_fix(result2stretch, 8);
904         for (int row = 0; row < m_result.Height(); row++) {
905           uint8_t* dest_pos = (uint8_t*)pTransformed->GetScanline(row);
906           for (int col = 0; col < m_result.Width(); col++) {
907             int src_col, src_row;
908             result2stretch_fix.Transform(col, row, src_col, src_row);
909             if (src_col >= 0 && src_col <= stretch_width && src_row >= 0 &&
910                 src_row <= stretch_height) {
911               if (src_col == stretch_width) {
912                 src_col--;
913               }
914               if (src_row == stretch_height) {
915                 src_row--;
916               }
917               const uint8_t* src_pos =
918                   stretch_buf + src_row * stretch_pitch + src_col * Bpp;
919               if (bHasAlpha) {
920                 if (transformF != FXDIB_Argb) {
921                   if (transformF == FXDIB_Rgba) {
922                     dest_pos[0] = src_pos[0];
923                     dest_pos[1] = src_pos[1];
924                     dest_pos[2] = src_pos[2];
925                   } else {
926                     *(uint32_t*)dest_pos = FXCMYK_TODIB(CmykEncode(
927                         src_pos[0], src_pos[1], src_pos[2], src_pos[3]));
928                   }
929                 } else {
930                   *(uint32_t*)dest_pos = FXARGB_TODIB(FXARGB_MAKE(
931                       src_pos[3], src_pos[2], src_pos[1], src_pos[0]));
932                 }
933               } else {
934                 if (transformF == FXDIB_Cmyka) {
935                   *(uint32_t*)dest_pos = FXCMYK_TODIB(CmykEncode(
936                       src_pos[0], src_pos[1], src_pos[2], src_pos[3]));
937                 } else {
938                   *(uint32_t*)dest_pos = FXARGB_TODIB(
939                       FXARGB_MAKE(0xff, src_pos[2], src_pos[1], src_pos[0]));
940                 }
941               }
942             }
943             dest_pos += destBpp;
944           }
945         }
946       }
947     }
948   }
949   m_Storer.Replace(std::move(pTransformed));
950   return FALSE;
951 }
952 
DetachBitmap()953 std::unique_ptr<CFX_DIBitmap> CFX_ImageTransformer::DetachBitmap() {
954   return m_Storer.Detach();
955 }
956