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