Fix clang warnings so we can treat warnings as errors.
[pdfium.git] / core / src / fxge / dib / fx_dib_engine.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4  \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../include/fxge/fx_dib.h"\r
8 #include "../../../include/fxge/fx_ge.h"\r
9 #include "dib_int.h"\r
10 #include <limits.h>\r
11 extern int SDP_Table[513];\r
12 void CWeightTable::Calc(int dest_len, int dest_min, int dest_max, int src_len, int src_min, int src_max, int flags)\r
13 {\r
14     if (m_pWeightTables) {\r
15         FX_Free(m_pWeightTables);\r
16         m_pWeightTables = NULL;\r
17     }\r
18     double scale, base;\r
19     scale = FXSYS_Div((FX_FLOAT)(src_len), (FX_FLOAT)(dest_len));\r
20     if (dest_len < 0) {\r
21         base = (FX_FLOAT)(src_len);\r
22     } else {\r
23         base = 0;\r
24     }\r
25     int ext_size = flags & FXDIB_BICUBIC_INTERPOL ? 3 : 1;\r
26     m_ItemSize = sizeof(int) * 2 + (int)(sizeof(int) * (FXSYS_ceil(FXSYS_fabs((FX_FLOAT)scale)) + ext_size));\r
27     m_DestMin = dest_min;\r
28     if ((dest_max - dest_min) > (int)((1U << 30) - 4) / m_ItemSize) {\r
29         return;\r
30     }\r
31     m_pWeightTables = FX_AllocNL(FX_BYTE, (dest_max - dest_min) * m_ItemSize + 4);\r
32     if (m_pWeightTables == NULL) {\r
33         return;\r
34     }\r
35     FXSYS_memset32(m_pWeightTables, 0, sizeof(FX_BYTE) * ((dest_max - dest_min)*m_ItemSize + 4));\r
36     if ((flags & FXDIB_NOSMOOTH) != 0 || FXSYS_fabs((FX_FLOAT)scale) < 1.0f) {\r
37         for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel ++) {\r
38             PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);\r
39             double src_pos = dest_pixel * scale + scale / 2 + base;\r
40             if (flags & FXDIB_INTERPOL) {\r
41                 pixel_weights.m_SrcStart = (int)FXSYS_floor((FX_FLOAT)src_pos - 1.0f / 2);\r
42                 pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos + 1.0f / 2);\r
43                 if (pixel_weights.m_SrcStart < src_min) {\r
44                     pixel_weights.m_SrcStart = src_min;\r
45                 }\r
46                 if (pixel_weights.m_SrcEnd >= src_max) {\r
47                     pixel_weights.m_SrcEnd = src_max - 1;\r
48                 }\r
49                 if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {\r
50                     pixel_weights.m_Weights[0] = 65536;\r
51                 } else {\r
52                     pixel_weights.m_Weights[1] = FXSYS_round((FX_FLOAT)(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * 65536);\r
53                     pixel_weights.m_Weights[0] = 65536 - pixel_weights.m_Weights[1];\r
54                 }\r
55             } else if (flags & FXDIB_BICUBIC_INTERPOL) {\r
56                 pixel_weights.m_SrcStart = (int)FXSYS_floor((FX_FLOAT)src_pos - 1.0f / 2);\r
57                 pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos + 1.0f / 2);\r
58                 int start = pixel_weights.m_SrcStart - 1;\r
59                 int end = pixel_weights.m_SrcEnd + 1;\r
60                 if (start < src_min) {\r
61                     start = src_min;\r
62                 }\r
63                 if (end >= src_max) {\r
64                     end = src_max - 1;\r
65                 }\r
66                 if (pixel_weights.m_SrcStart < src_min) {\r
67                     src_pos += src_min - pixel_weights.m_SrcStart;\r
68                     pixel_weights.m_SrcStart = src_min;\r
69                 }\r
70                 if (pixel_weights.m_SrcEnd >= src_max) {\r
71                     pixel_weights.m_SrcEnd = src_max - 1;\r
72                 }\r
73                 int weight;\r
74                 weight = FXSYS_round((FX_FLOAT)(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) * 256);\r
75                 if (start == end) {\r
76                     pixel_weights.m_Weights[0] = (SDP_Table[256 + weight] + SDP_Table[weight] + SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;\r
77                 } else if ((start == pixel_weights.m_SrcStart && (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd ||\r
78                             end == pixel_weights.m_SrcEnd) && start < end) || (start < pixel_weights.m_SrcStart && pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd && end == pixel_weights.m_SrcEnd)) {\r
79                     if (start < pixel_weights.m_SrcStart) {\r
80                         pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;\r
81                         pixel_weights.m_Weights[1] = (SDP_Table[weight] + SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;\r
82                     } else {\r
83                         if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {\r
84                             pixel_weights.m_Weights[0] = (SDP_Table[256 + weight] + SDP_Table[weight] + SDP_Table[256 - weight]) << 8;\r
85                             pixel_weights.m_Weights[1] = SDP_Table[512 - weight] << 8;\r
86                         } else {\r
87                             pixel_weights.m_Weights[0] = (SDP_Table[256 + weight] + SDP_Table[weight]) << 8;\r
88                             pixel_weights.m_Weights[1] = (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;\r
89                         }\r
90                     }\r
91                     if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {\r
92                         pixel_weights.m_SrcEnd = end;\r
93                     }\r
94                     if (start < pixel_weights.m_SrcStart) {\r
95                         pixel_weights.m_SrcStart = start;\r
96                     }\r
97                 } else if (start == pixel_weights.m_SrcStart &&\r
98                            start < pixel_weights.m_SrcEnd &&\r
99                            pixel_weights.m_SrcEnd < end) {\r
100                     pixel_weights.m_Weights[0] = (SDP_Table[256 + weight] + SDP_Table[weight]) << 8;\r
101                     pixel_weights.m_Weights[1] = SDP_Table[256 - weight] << 8;\r
102                     pixel_weights.m_Weights[2] = SDP_Table[512 - weight] << 8;\r
103                     pixel_weights.m_SrcEnd = end;\r
104                 } else if (start < pixel_weights.m_SrcStart &&\r
105                            pixel_weights.m_SrcStart < pixel_weights.m_SrcEnd &&\r
106                            pixel_weights.m_SrcEnd == end) {\r
107                     pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;\r
108                     pixel_weights.m_Weights[1] = SDP_Table[weight] << 8;\r
109                     pixel_weights.m_Weights[2] = (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;\r
110                     pixel_weights.m_SrcStart = start;\r
111                 } else {\r
112                     pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;\r
113                     pixel_weights.m_Weights[1] = SDP_Table[weight] << 8;\r
114                     pixel_weights.m_Weights[2] = SDP_Table[256 - weight] << 8;\r
115                     pixel_weights.m_Weights[3] = SDP_Table[512 - weight] << 8;\r
116                     pixel_weights.m_SrcStart = start;\r
117                     pixel_weights.m_SrcEnd = end;\r
118                 }\r
119             } else {\r
120                 pixel_weights.m_SrcStart = pixel_weights.m_SrcEnd = (int)FXSYS_floor((FX_FLOAT)src_pos);\r
121                 if (pixel_weights.m_SrcStart < src_min) {\r
122                     pixel_weights.m_SrcStart = src_min;\r
123                 }\r
124                 if (pixel_weights.m_SrcEnd >= src_max) {\r
125                     pixel_weights.m_SrcEnd = src_max - 1;\r
126                 }\r
127                 pixel_weights.m_Weights[0] = 65536;\r
128             }\r
129         }\r
130         return;\r
131     }\r
132     for (int dest_pixel = dest_min; dest_pixel < dest_max; dest_pixel ++) {\r
133         PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);\r
134         double src_start = dest_pixel * scale + base;\r
135         double src_end = src_start + scale;\r
136         int start_i, end_i;\r
137         if (src_start < src_end) {\r
138             start_i = (int)FXSYS_floor((FX_FLOAT)src_start);\r
139             end_i = (int)FXSYS_ceil((FX_FLOAT)src_end);\r
140         } else {\r
141             start_i = (int)FXSYS_floor((FX_FLOAT)src_end);\r
142             end_i = (int)FXSYS_ceil((FX_FLOAT)src_start);\r
143         }\r
144         if (start_i < src_min) {\r
145             start_i = src_min;\r
146         }\r
147         if (end_i >= src_max) {\r
148             end_i = src_max - 1;\r
149         }\r
150         if (start_i > end_i) {\r
151             if (start_i >= src_max) {\r
152                 start_i = src_max - 1;\r
153             }\r
154             pixel_weights.m_SrcStart = start_i;\r
155             pixel_weights.m_SrcEnd = start_i;\r
156             continue;\r
157         }\r
158         pixel_weights.m_SrcStart = start_i;\r
159         pixel_weights.m_SrcEnd = end_i;\r
160         for (int j = start_i; j <= end_i; j ++) {\r
161             double dest_start = FXSYS_Div((FX_FLOAT)(j) - base, scale);\r
162             double dest_end = FXSYS_Div((FX_FLOAT)(j + 1) - base, scale);\r
163             if (dest_start > dest_end) {\r
164                 double temp = dest_start;\r
165                 dest_start = dest_end;\r
166                 dest_end = temp;\r
167             }\r
168             double area_start = dest_start > (FX_FLOAT)(dest_pixel) ? dest_start : (FX_FLOAT)(dest_pixel);\r
169             double area_end = dest_end > (FX_FLOAT)(dest_pixel + 1) ? (FX_FLOAT)(dest_pixel + 1) : dest_end;\r
170             double weight = area_start >= area_end ? 0.0f : area_end - area_start;\r
171             if (weight == 0 && j == end_i) {\r
172                 pixel_weights.m_SrcEnd --;\r
173                 break;\r
174             }\r
175             pixel_weights.m_Weights[j - start_i] = FXSYS_round((FX_FLOAT)(weight * 65536));\r
176         }\r
177     }\r
178 }\r
179 CStretchEngine::CStretchEngine(IFX_ScanlineComposer* pDestBitmap, FXDIB_Format dest_format,\r
180                                int dest_width, int dest_height, const FX_RECT& clip_rect,\r
181                                const CFX_DIBSource* pSrcBitmap, int flags)\r
182 {\r
183     m_State = 0;\r
184     m_DestFormat = dest_format;\r
185     m_DestBpp = dest_format & 0xff;\r
186     m_SrcBpp = pSrcBitmap->GetFormat() & 0xff;\r
187     m_bHasAlpha = pSrcBitmap->GetFormat() & 0x200;\r
188     m_pSrcPalette = pSrcBitmap->GetPalette();\r
189     m_pDestBitmap = pDestBitmap;\r
190     m_DestWidth = dest_width;\r
191     m_DestHeight = dest_height;\r
192     m_pInterBuf = NULL;\r
193     m_pExtraAlphaBuf = NULL;\r
194     m_pDestMaskScanline = NULL;\r
195     m_DestClip = clip_rect;\r
196     FX_DWORD size = clip_rect.Width();\r
197     if (size && m_DestBpp > (int)(INT_MAX / size)) {\r
198         return;\r
199     }\r
200     size *= m_DestBpp;\r
201     if (size > INT_MAX - 31) {\r
202         return;\r
203     }\r
204     size += 31;\r
205     size = size / 32 * 4;\r
206     m_pDestScanline = FX_AllocNL(FX_BYTE, size);\r
207     if (m_pDestScanline == NULL) {\r
208         return;\r
209     }\r
210     FXSYS_memset32(m_pDestScanline, 0, sizeof(FX_BYTE) * size);\r
211     if (dest_format == FXDIB_Rgb32) {\r
212         FXSYS_memset8(m_pDestScanline, 255, size);\r
213     }\r
214     m_InterPitch = (m_DestClip.Width() * m_DestBpp + 31) / 32 * 4;\r
215     m_ExtraMaskPitch = (m_DestClip.Width() * 8 + 31) / 32 * 4;\r
216     m_pInterBuf = NULL;\r
217     m_pSource = pSrcBitmap;\r
218     m_SrcWidth = pSrcBitmap->GetWidth();\r
219     m_SrcHeight = pSrcBitmap->GetHeight();\r
220     m_SrcPitch = (m_SrcWidth * m_SrcBpp + 31) / 32 * 4;\r
221     if ((flags & FXDIB_NOSMOOTH) == 0) {\r
222         FX_BOOL bInterpol = flags & FXDIB_INTERPOL || flags & FXDIB_BICUBIC_INTERPOL;\r
223         if (!bInterpol && FXSYS_abs(dest_width) != 0 && FXSYS_abs(dest_height) < m_SrcWidth * m_SrcHeight * 8 / FXSYS_abs(dest_width)) {\r
224             flags = FXDIB_INTERPOL;\r
225         }\r
226         m_Flags = flags;\r
227     } else {\r
228         m_Flags = FXDIB_NOSMOOTH;\r
229         if (flags & FXDIB_DOWNSAMPLE) {\r
230             m_Flags |= FXDIB_DOWNSAMPLE;\r
231         }\r
232     }\r
233     double scale_x = FXSYS_Div((FX_FLOAT)(m_SrcWidth), (FX_FLOAT)(m_DestWidth));\r
234     double scale_y = FXSYS_Div((FX_FLOAT)(m_SrcHeight), (FX_FLOAT)(m_DestHeight));\r
235     double base_x = m_DestWidth > 0 ? 0.0f : (FX_FLOAT)(m_DestWidth);\r
236     double base_y = m_DestHeight > 0 ? 0.0f : (FX_FLOAT)(m_DestHeight);\r
237     double src_left = FXSYS_Mul(scale_x, (FX_FLOAT)(clip_rect.left) + base_x);\r
238     double src_right = FXSYS_Mul(scale_x, (FX_FLOAT)(clip_rect.right) + base_x);\r
239     double src_top = FXSYS_Mul(scale_y, (FX_FLOAT)(clip_rect.top) + base_y);\r
240     double src_bottom = FXSYS_Mul(scale_y, (FX_FLOAT)(clip_rect.bottom) + base_y);\r
241     if (src_left > src_right) {\r
242         double temp = src_left;\r
243         src_left = src_right;\r
244         src_right = temp;\r
245     }\r
246     if (src_top > src_bottom) {\r
247         double temp = src_top;\r
248         src_top = src_bottom;\r
249         src_bottom = temp;\r
250     }\r
251     m_SrcClip.left = (int)FXSYS_floor((FX_FLOAT)src_left);\r
252     m_SrcClip.right = (int)FXSYS_ceil((FX_FLOAT)src_right);\r
253     m_SrcClip.top = (int)FXSYS_floor((FX_FLOAT)src_top);\r
254     m_SrcClip.bottom = (int)FXSYS_ceil((FX_FLOAT)src_bottom);\r
255     FX_RECT src_rect(0, 0, m_SrcWidth, m_SrcHeight);\r
256     m_SrcClip.Intersect(src_rect);\r
257     if (m_SrcBpp == 1) {\r
258         if (m_DestBpp == 8) {\r
259             m_TransMethod = 1;\r
260         } else {\r
261             m_TransMethod = 2;\r
262         }\r
263     } else if (m_SrcBpp == 8) {\r
264         if (m_DestBpp == 8) {\r
265             if (!m_bHasAlpha) {\r
266                 m_TransMethod = 3;\r
267             } else {\r
268                 m_TransMethod = 4;\r
269             }\r
270         } else {\r
271             if (!m_bHasAlpha) {\r
272                 m_TransMethod = 5;\r
273             } else {\r
274                 m_TransMethod = 6;\r
275             }\r
276         }\r
277     } else {\r
278         if (!m_bHasAlpha) {\r
279             m_TransMethod = 7;\r
280         } else {\r
281             m_TransMethod = 8;\r
282         }\r
283     }\r
284 }\r
285 FX_BOOL CStretchEngine::Continue(IFX_Pause* pPause)\r
286 {\r
287     while (m_State == 1) {\r
288         if (ContinueStretchHorz(pPause)) {\r
289             return TRUE;\r
290         }\r
291         m_State = 2;\r
292         StretchVert();\r
293     }\r
294     return FALSE;\r
295 }\r
296 CStretchEngine::~CStretchEngine()\r
297 {\r
298     if (m_pDestScanline) {\r
299         FX_Free(m_pDestScanline);\r
300     }\r
301     if (m_pInterBuf) {\r
302         FX_Free(m_pInterBuf);\r
303     }\r
304     if (m_pExtraAlphaBuf) {\r
305         FX_Free(m_pExtraAlphaBuf);\r
306     }\r
307     if (m_pDestMaskScanline) {\r
308         FX_Free(m_pDestMaskScanline);\r
309     }\r
310 }\r
311 FX_BOOL CStretchEngine::StartStretchHorz()\r
312 {\r
313     if (m_DestWidth == 0 || m_pDestScanline == NULL || m_SrcClip.Height() > (int)((1U << 29) / m_InterPitch) || m_SrcClip.Height() == 0) {\r
314         return FALSE;\r
315     }\r
316 #ifndef _FPDFAPI_MINI_\r
317     m_pInterBuf = FX_AllocNL(unsigned char, m_SrcClip.Height() * m_InterPitch);\r
318 #else\r
319     m_pInterBuf = FX_Alloc(unsigned char, m_SrcClip.Height() * m_InterPitch);\r
320 #endif\r
321     if (m_pInterBuf == NULL) {\r
322         return FALSE;\r
323     }\r
324     if (m_pSource && m_bHasAlpha && m_pSource->m_pAlphaMask) {\r
325         m_pExtraAlphaBuf = FX_Alloc(unsigned char, m_SrcClip.Height() * m_ExtraMaskPitch);\r
326         if (!m_pExtraAlphaBuf) {\r
327             return FALSE;\r
328         }\r
329         FX_DWORD size = (m_DestClip.Width() * 8 + 31) / 32 * 4;\r
330         m_pDestMaskScanline = FX_AllocNL(unsigned char, size);\r
331         if (!m_pDestMaskScanline) {\r
332             return FALSE;\r
333         }\r
334     }\r
335     m_WeightTable.Calc(m_DestWidth, m_DestClip.left, m_DestClip.right, m_SrcWidth, m_SrcClip.left, m_SrcClip.right, m_Flags);\r
336     if (m_WeightTable.m_pWeightTables == NULL) {\r
337         return FALSE;\r
338     }\r
339     m_CurRow = m_SrcClip.top;\r
340     m_State = 1;\r
341     return TRUE;\r
342 }\r
343 #define FX_STRECH_PAUSE_ROWS    10\r
344 FX_BOOL CStretchEngine::ContinueStretchHorz(IFX_Pause* pPause)\r
345 {\r
346     if (!m_DestWidth) {\r
347         return 0;\r
348     }\r
349     if (m_pSource->SkipToScanline(m_CurRow, pPause)) {\r
350         return TRUE;\r
351     }\r
352     int Bpp = m_DestBpp / 8;\r
353     int rows_to_go = FX_STRECH_PAUSE_ROWS;\r
354     for (; m_CurRow < m_SrcClip.bottom; m_CurRow ++) {\r
355         if (rows_to_go == 0) {\r
356             if (pPause && pPause->NeedToPauseNow()) {\r
357                 return TRUE;\r
358             } else {\r
359                 rows_to_go = FX_STRECH_PAUSE_ROWS;\r
360             }\r
361         }\r
362         FX_LPCBYTE src_scan = m_pSource->GetScanline(m_CurRow);\r
363         FX_LPBYTE dest_scan = m_pInterBuf + (m_CurRow - m_SrcClip.top) * m_InterPitch;\r
364         FX_LPCBYTE src_scan_mask = NULL;\r
365         FX_LPBYTE dest_scan_mask = NULL;\r
366         if (m_pExtraAlphaBuf) {\r
367             src_scan_mask = m_pSource->m_pAlphaMask->GetScanline(m_CurRow);\r
368             dest_scan_mask = m_pExtraAlphaBuf + (m_CurRow - m_SrcClip.top) * m_ExtraMaskPitch;\r
369         }\r
370         switch (m_TransMethod) {\r
371             case 1:\r
372             case 2: {\r
373                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
374                         PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);\r
375                         int dest_a = 0;\r
376                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
377                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
378                             if (src_scan[j / 8] & (1 << (7 - j % 8))) {\r
379                                 dest_a += pixel_weight * 255;\r
380                             }\r
381                         }\r
382                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
383                             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;\r
384                         }\r
385                         *dest_scan++ = (FX_BYTE)(dest_a >> 16);\r
386                     }\r
387                     break;\r
388                 }\r
389             case 3: {\r
390                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
391                         PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);\r
392                         int dest_a = 0;\r
393                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
394                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
395                             dest_a += pixel_weight * src_scan[j];\r
396                         }\r
397                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
398                             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;\r
399                         }\r
400                         *dest_scan++ = (FX_BYTE)(dest_a >> 16);\r
401                     }\r
402                     break;\r
403                 }\r
404             case 4: {\r
405                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
406                         PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);\r
407                         int dest_a = 0, dest_r = 0;\r
408                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
409                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
410                             pixel_weight = pixel_weight * src_scan_mask[j] / 255;\r
411                             dest_r += pixel_weight * src_scan[j];\r
412                             dest_a += pixel_weight;\r
413                         }\r
414                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
415                             dest_r = dest_r < 0 ? 0 : dest_r > 16711680 ? 16711680 : dest_r;\r
416                             dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a;\r
417                         }\r
418                         *dest_scan++ = (FX_BYTE)(dest_r >> 16);\r
419                         *dest_scan_mask++ = (FX_BYTE)((dest_a * 255) >> 16);\r
420                     }\r
421                     break;\r
422                 }\r
423             case 5: {\r
424                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
425                         PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);\r
426                         int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0, dest_k = 0;\r
427                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
428                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
429                             unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]];\r
430                             if (m_DestFormat == FXDIB_Rgb) {\r
431                                 dest_r_y += pixel_weight * (FX_BYTE)(argb_cmyk >> 16);\r
432                                 dest_g_m += pixel_weight * (FX_BYTE)(argb_cmyk >> 8);\r
433                                 dest_b_c += pixel_weight * (FX_BYTE)argb_cmyk;\r
434                             } else {\r
435                                 dest_b_c += pixel_weight * (FX_BYTE)(argb_cmyk >> 24);\r
436                                 dest_g_m += pixel_weight * (FX_BYTE)(argb_cmyk >> 16);\r
437                                 dest_r_y += pixel_weight * (FX_BYTE)(argb_cmyk >> 8);\r
438                             }\r
439                         }\r
440                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
441                             dest_r_y = dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;\r
442                             dest_g_m = dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;\r
443                             dest_b_c = dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;\r
444                         }\r
445                         *dest_scan++ = (FX_BYTE)(dest_b_c >> 16);\r
446                         *dest_scan++ = (FX_BYTE)(dest_g_m >> 16);\r
447                         *dest_scan++ = (FX_BYTE)(dest_r_y >> 16);\r
448                     }\r
449                     break;\r
450                 }\r
451             case 6: {\r
452                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
453                         PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);\r
454                         int dest_a = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0, dest_k = 0;\r
455                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
456                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
457                             pixel_weight = pixel_weight * src_scan_mask[j] / 255;\r
458                             unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]];\r
459                             if (m_DestFormat == FXDIB_Rgba) {\r
460                                 dest_r_y += pixel_weight * (FX_BYTE)(argb_cmyk >> 16);\r
461                                 dest_g_m += pixel_weight * (FX_BYTE)(argb_cmyk >> 8);\r
462                                 dest_b_c += pixel_weight * (FX_BYTE)argb_cmyk;\r
463                             } else {\r
464                                 dest_b_c += pixel_weight * (FX_BYTE)(argb_cmyk >> 24);\r
465                                 dest_g_m += pixel_weight * (FX_BYTE)(argb_cmyk >> 16);\r
466                                 dest_r_y += pixel_weight * (FX_BYTE)(argb_cmyk >> 8);\r
467                             }\r
468                             dest_a += pixel_weight;\r
469                         }\r
470                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
471                             dest_k = dest_k < 0 ? 0 : dest_k > 16711680 ? 16711680 : dest_k;\r
472                             dest_b_c = dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;\r
473                             dest_g_m = dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;\r
474                             dest_r_y = dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;\r
475                             dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a;\r
476                         }\r
477                         *dest_scan++ = (FX_BYTE)(dest_b_c >> 16);\r
478                         *dest_scan++ = (FX_BYTE)(dest_g_m >> 16);\r
479                         *dest_scan++ = (FX_BYTE)(dest_r_y >> 16);\r
480                         *dest_scan_mask++ = (FX_BYTE)((dest_a * 255) >> 16);\r
481                     }\r
482                     break;\r
483                 }\r
484             case 7: {\r
485                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
486                         PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);\r
487                         int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0, dest_k = 0;\r
488                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
489                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
490                             FX_LPCBYTE src_pixel = src_scan + j * Bpp;\r
491                             dest_b_c += pixel_weight * (*src_pixel++);\r
492                             dest_g_m += pixel_weight * (*src_pixel++);\r
493                             dest_r_y += pixel_weight * (*src_pixel);\r
494                         }\r
495                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
496                             dest_b_c = dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;\r
497                             dest_g_m = dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;\r
498                             dest_r_y = dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;\r
499                         }\r
500                         *dest_scan++ = (FX_BYTE)((dest_b_c) >> 16);\r
501                         *dest_scan++ = (FX_BYTE)((dest_g_m) >> 16);\r
502                         *dest_scan++ = (FX_BYTE)((dest_r_y) >> 16);\r
503                         dest_scan += Bpp - 3;\r
504                     }\r
505                     break;\r
506                 }\r
507             case 8: {\r
508                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
509                         PixelWeight* pPixelWeights = m_WeightTable.GetPixelWeight(col);\r
510                         int dest_a = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0, dest_k = 0;\r
511                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
512                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
513                             FX_LPCBYTE src_pixel = src_scan + j * Bpp;\r
514                             if (m_DestFormat == FXDIB_Argb) {\r
515                                 pixel_weight = pixel_weight * src_pixel[3] / 255;\r
516                             } else {\r
517                                 pixel_weight = pixel_weight * src_scan_mask[j] / 255;\r
518                             }\r
519                             dest_b_c += pixel_weight * (*src_pixel++);\r
520                             dest_g_m += pixel_weight * (*src_pixel++);\r
521                             dest_r_y += pixel_weight * (*src_pixel);\r
522                             dest_a += pixel_weight;\r
523                         }\r
524                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
525                             dest_r_y = dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;\r
526                             dest_g_m = dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;\r
527                             dest_b_c = dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;\r
528                             dest_a = dest_a < 0 ? 0 : dest_a > 65536 ? 65536 : dest_a;\r
529                         }\r
530                         *dest_scan++ = (FX_BYTE)((dest_b_c) >> 16);\r
531                         *dest_scan++ = (FX_BYTE)((dest_g_m) >> 16);\r
532                         *dest_scan++ = (FX_BYTE)((dest_r_y) >> 16);\r
533                         if (m_DestFormat == FXDIB_Argb) {\r
534                             *dest_scan = (FX_BYTE)((dest_a * 255) >> 16);\r
535                         }\r
536                         if (dest_scan_mask) {\r
537                             *dest_scan_mask++ = (FX_BYTE)((dest_a * 255) >> 16);\r
538                         }\r
539                         dest_scan += Bpp - 3;\r
540                     }\r
541                     break;\r
542                 }\r
543         }\r
544         rows_to_go --;\r
545     }\r
546     return FALSE;\r
547 }\r
548 void CStretchEngine::StretchVert()\r
549 {\r
550     if (m_DestHeight == 0) {\r
551         return;\r
552     }\r
553     CWeightTable table;\r
554     table.Calc(m_DestHeight, m_DestClip.top, m_DestClip.bottom, m_SrcHeight, m_SrcClip.top, m_SrcClip.bottom, m_Flags);\r
555     if (table.m_pWeightTables == NULL) {\r
556         return;\r
557     }\r
558     int DestBpp = m_DestBpp / 8;\r
559     for (int row = m_DestClip.top; row < m_DestClip.bottom; row ++) {\r
560         unsigned char* dest_scan = m_pDestScanline;\r
561         unsigned char* dest_sacn_mask = m_pDestMaskScanline;\r
562         PixelWeight* pPixelWeights = table.GetPixelWeight(row);\r
563         switch(m_TransMethod) {\r
564             case 1:\r
565             case 2:\r
566             case 3: {\r
567                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
568                         unsigned char* src_scan = m_pInterBuf + (col - m_DestClip.left) * DestBpp;\r
569                         int dest_a = 0;\r
570                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
571                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
572                             dest_a += pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];\r
573                         }\r
574                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
575                             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;\r
576                         }\r
577                         *dest_scan = (FX_BYTE)(dest_a >> 16);\r
578                         dest_scan += DestBpp;\r
579                     }\r
580                     break;\r
581                 }\r
582             case 4: {\r
583                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
584                         unsigned char* src_scan = m_pInterBuf + (col - m_DestClip.left) * DestBpp;\r
585                         unsigned char* src_scan_mask = m_pExtraAlphaBuf + (col - m_DestClip.left);\r
586                         int dest_a = 0, dest_k = 0;\r
587                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
588                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
589                             dest_k += pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];\r
590                             dest_a += pixel_weight * src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch];\r
591                         }\r
592                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
593                             dest_k = dest_k < 0 ? 0 : dest_k > 16711680 ? 16711680 : dest_k;\r
594                             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;\r
595                         }\r
596                         *dest_scan = (FX_BYTE)(dest_k >> 16);\r
597                         dest_scan += DestBpp;\r
598                         *dest_sacn_mask++ = (FX_BYTE)(dest_a >> 16);\r
599                     }\r
600                     break;\r
601                 }\r
602             case 5:\r
603             case 7: {\r
604                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
605                         unsigned char* src_scan = m_pInterBuf + (col - m_DestClip.left) * DestBpp;\r
606                         int dest_r_y = 0, dest_g_m = 0, dest_b_c = 0, dest_k = 0;\r
607                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
608                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
609                             FX_LPCBYTE src_pixel = src_scan + (j - m_SrcClip.top) * m_InterPitch;\r
610                             dest_b_c += pixel_weight * (*src_pixel++);\r
611                             dest_g_m += pixel_weight * (*src_pixel++);\r
612                             dest_r_y += pixel_weight * (*src_pixel);\r
613                         }\r
614                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
615                             dest_r_y = dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;\r
616                             dest_g_m = dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;\r
617                             dest_b_c = dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;\r
618                         }\r
619                         dest_scan[0] = (FX_BYTE)((dest_b_c) >> 16);\r
620                         dest_scan[1] = (FX_BYTE)((dest_g_m) >> 16);\r
621                         dest_scan[2] = (FX_BYTE)((dest_r_y) >> 16);\r
622                         dest_scan += DestBpp;\r
623                     }\r
624                     break;\r
625                 }\r
626             case 6:\r
627             case 8: {\r
628                     for (int col = m_DestClip.left; col < m_DestClip.right; col ++) {\r
629                         unsigned char* src_scan = m_pInterBuf + (col - m_DestClip.left) * DestBpp;\r
630                         unsigned char* src_scan_mask = NULL;\r
631                         if (m_DestFormat != FXDIB_Argb) {\r
632                             src_scan_mask = m_pExtraAlphaBuf + (col - m_DestClip.left);\r
633                         }\r
634                         int dest_a = 0, dest_k = 0, dest_r_y = 0, dest_g_m = 0, dest_b_c = 0;\r
635                         for (int j = pPixelWeights->m_SrcStart; j <= pPixelWeights->m_SrcEnd; j ++) {\r
636                             int pixel_weight = pPixelWeights->m_Weights[j - pPixelWeights->m_SrcStart];\r
637                             FX_LPCBYTE src_pixel = src_scan + (j - m_SrcClip.top) * m_InterPitch;\r
638                             int mask_v = 255;\r
639                             if (src_scan_mask) {\r
640                                 mask_v = src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch];\r
641                             }\r
642                             dest_b_c += pixel_weight * (*src_pixel++);\r
643                             dest_g_m += pixel_weight * (*src_pixel++);\r
644                             dest_r_y += pixel_weight * (*src_pixel);\r
645                             if (m_DestFormat == FXDIB_Argb) {\r
646                                 dest_a += pixel_weight * (*(src_pixel + 1));\r
647                             } else {\r
648                                 dest_a += pixel_weight * mask_v;\r
649                             }\r
650                         }\r
651                         if (m_Flags & FXDIB_BICUBIC_INTERPOL) {\r
652                             dest_r_y = dest_r_y < 0 ? 0 : dest_r_y > 16711680 ? 16711680 : dest_r_y;\r
653                             dest_g_m = dest_g_m < 0 ? 0 : dest_g_m > 16711680 ? 16711680 : dest_g_m;\r
654                             dest_b_c = dest_b_c < 0 ? 0 : dest_b_c > 16711680 ? 16711680 : dest_b_c;\r
655                             dest_a = dest_a < 0 ? 0 : dest_a > 16711680 ? 16711680 : dest_a;\r
656                         }\r
657                         if (dest_a) {\r
658                             int r = ((FX_DWORD)dest_r_y) * 255 / dest_a;\r
659                             int g = ((FX_DWORD)dest_g_m) * 255 / dest_a;\r
660                             int b = ((FX_DWORD)dest_b_c) * 255 / dest_a;\r
661                             dest_scan[0] = b > 255 ? 255 : b < 0 ? 0 : b;\r
662                             dest_scan[1] = g > 255 ? 255 : g < 0 ? 0 : g;\r
663                             dest_scan[2] = r > 255 ? 255 : r < 0 ? 0 : r;\r
664                         }\r
665                         if (m_DestFormat == FXDIB_Argb) {\r
666                             dest_scan[3] = (FX_BYTE)((dest_a) >> 16);\r
667                         } else {\r
668                             *dest_sacn_mask = (FX_BYTE)((dest_a) >> 16);\r
669                         }\r
670                         dest_scan += DestBpp;\r
671                         if (dest_sacn_mask) {\r
672                             dest_sacn_mask++;\r
673                         }\r
674                     }\r
675                     break;\r
676                 }\r
677         }\r
678         m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_pDestScanline, m_pDestMaskScanline);\r
679     }\r
680 }\r
681 CFX_ImageStretcher::CFX_ImageStretcher()\r
682 {\r
683     m_pScanline = NULL;\r
684     m_pStretchEngine = NULL;\r
685     m_pMaskScanline = NULL;\r
686 }\r
687 CFX_ImageStretcher::~CFX_ImageStretcher()\r
688 {\r
689     if (m_pScanline) {\r
690         FX_Free(m_pScanline);\r
691     }\r
692     if (m_pStretchEngine) {\r
693         delete m_pStretchEngine;\r
694     }\r
695     if (m_pMaskScanline) {\r
696         FX_Free(m_pMaskScanline);\r
697     }\r
698 }\r
699 FXDIB_Format _GetStretchedFormat(const CFX_DIBSource* pSrc)\r
700 {\r
701     FXDIB_Format format = pSrc->GetFormat();\r
702     if (format == FXDIB_1bppMask) {\r
703         format = FXDIB_8bppMask;\r
704     } else if (format == FXDIB_1bppRgb) {\r
705         format = FXDIB_8bppRgb;\r
706     } else if (format == FXDIB_8bppRgb) {\r
707         if (pSrc->GetPalette()) {\r
708             format = FXDIB_Rgb;\r
709         }\r
710     }\r
711     return format;\r
712 }\r
713 FX_BOOL CFX_ImageStretcher::Start(IFX_ScanlineComposer* pDest,\r
714                                   const CFX_DIBSource* pSource, int dest_width, int dest_height,\r
715                                   const FX_RECT& rect, FX_DWORD flags)\r
716 {\r
717     m_DestFormat = _GetStretchedFormat(pSource);\r
718     m_DestBPP = m_DestFormat & 0xff;\r
719     m_pDest = pDest;\r
720     m_pSource = pSource;\r
721     m_DestWidth = dest_width;\r
722     m_DestHeight = dest_height;\r
723     m_ClipRect = rect;\r
724     m_Flags = flags;\r
725     if (pSource->GetFormat() == FXDIB_1bppRgb && pSource->GetPalette()) {\r
726         FX_ARGB pal[256];\r
727         int a0, r0, g0, b0, a1, r1, g1, b1;\r
728         ArgbDecode(pSource->GetPaletteEntry(0), a0, r0, g0, b0);\r
729         ArgbDecode(pSource->GetPaletteEntry(1), a1, r1, g1, b1);\r
730         for (int i = 0; i < 256; i ++) {\r
731             int a = a0 + (a1 - a0) * i / 255;\r
732             int r = r0 + (r1 - r0) * i / 255;\r
733             int g = g0 + (g1 - g0) * i / 255;\r
734             int b = b0 + (b1 - b0) * i / 255;\r
735             pal[i] = ArgbEncode(a, r, g, b);\r
736         }\r
737         if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, pal)) {\r
738             return FALSE;\r
739         }\r
740     } else if (pSource->GetFormat() == FXDIB_1bppCmyk && pSource->GetPalette()) {\r
741         FX_CMYK pal[256];\r
742         int c0, m0, y0, k0, c1, m1, y1, k1;\r
743         CmykDecode(pSource->GetPaletteEntry(0), c0, m0, y0, k0);\r
744         CmykDecode(pSource->GetPaletteEntry(1), c1, m1, y1, k1);\r
745         for (int i = 0; i < 256; i ++) {\r
746             int c = c0 + (c1 - c0) * i / 255;\r
747             int m = m0 + (m1 - m0) * i / 255;\r
748             int y = y0 + (y1 - y0) * i / 255;\r
749             int k = k0 + (k1 - k0) * i / 255;\r
750             pal[i] = CmykEncode(c, m, y, k);\r
751         }\r
752         if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, pal)) {\r
753             return FALSE;\r
754         }\r
755     } else if (!pDest->SetInfo(rect.Width(), rect.Height(), m_DestFormat, NULL)) {\r
756         return FALSE;\r
757     }\r
758     if (flags & FXDIB_DOWNSAMPLE) {\r
759         return StartQuickStretch();\r
760     } else {\r
761         return StartStretch();\r
762     }\r
763 }\r
764 FX_BOOL CFX_ImageStretcher::Continue(IFX_Pause* pPause)\r
765 {\r
766     if (m_Flags & FXDIB_DOWNSAMPLE) {\r
767         return ContinueQuickStretch(pPause);\r
768     } else {\r
769         return ContinueStretch(pPause);\r
770     }\r
771 }\r
772 #ifndef _FPDFAPI_MINI_\r
773 #define MAX_PROGRESSIVE_STRETCH_PIXELS  1000000\r
774 #else\r
775 #define MAX_PROGRESSIVE_STRETCH_PIXELS  100000\r
776 #endif\r
777 FX_BOOL CFX_ImageStretcher::StartStretch()\r
778 {\r
779     m_pStretchEngine = FX_NEW CStretchEngine(m_pDest, m_DestFormat, m_DestWidth, m_DestHeight, m_ClipRect, m_pSource, m_Flags);\r
780     if (!m_pStretchEngine) {\r
781         return FALSE;\r
782     }\r
783     m_pStretchEngine->StartStretchHorz();\r
784     if (m_pSource->GetWidth() * m_pSource->GetHeight() < MAX_PROGRESSIVE_STRETCH_PIXELS) {\r
785         m_pStretchEngine->Continue(NULL);\r
786         return FALSE;\r
787     }\r
788     return TRUE;\r
789 }\r
790 FX_BOOL CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause)\r
791 {\r
792     if (m_pStretchEngine == NULL) {\r
793         return FALSE;\r
794     }\r
795     return m_pStretchEngine->Continue(pPause);\r
796 }\r
797 FX_BOOL CFX_ImageStretcher::StartQuickStretch()\r
798 {\r
799 #ifdef _FPDFAPI_MINI_\r
800     m_pSource->SetDownSampleSize(m_DestWidth, m_DestHeight);\r
801 #endif\r
802     m_bFlipX = FALSE;\r
803     m_bFlipY = FALSE;\r
804     if (m_DestWidth < 0) {\r
805         m_bFlipX = TRUE;\r
806         m_DestWidth = -m_DestWidth;\r
807     }\r
808     if (m_DestHeight < 0) {\r
809         m_bFlipY = TRUE;\r
810         m_DestHeight = -m_DestHeight;\r
811     }\r
812     m_LineIndex = 0;\r
813     FX_DWORD size = m_ClipRect.Width();\r
814     if (size && m_DestBPP > (int)(INT_MAX / size)) {\r
815         return FALSE;\r
816     }\r
817     size *= m_DestBPP;\r
818     m_pScanline = FX_Alloc(FX_BYTE, (size / 8 + 3) / 4 * 4);\r
819     if (!m_pScanline) {\r
820         return FALSE;\r
821     }\r
822     if (m_pSource->m_pAlphaMask) {\r
823         m_pMaskScanline = FX_Alloc(FX_BYTE, (m_ClipRect.Width() + 3) / 4 * 4);\r
824         if (!m_pMaskScanline) {\r
825             return FALSE;\r
826         }\r
827     }\r
828     if (m_pSource->GetWidth() * m_pSource->GetHeight() < MAX_PROGRESSIVE_STRETCH_PIXELS) {\r
829         ContinueQuickStretch(NULL);\r
830         return FALSE;\r
831     }\r
832     return TRUE;\r
833 }\r
834 FX_BOOL CFX_ImageStretcher::ContinueQuickStretch(IFX_Pause* pPause)\r
835 {\r
836     if (m_pScanline == NULL) {\r
837         return FALSE;\r
838     }\r
839     int result_width = m_ClipRect.Width(), result_height = m_ClipRect.Height();\r
840     int src_width = m_pSource->GetWidth(), src_height = m_pSource->GetHeight();\r
841     for (; m_LineIndex < result_height; m_LineIndex ++) {\r
842         int dest_y, src_y;\r
843         if (m_bFlipY) {\r
844             dest_y = result_height - m_LineIndex - 1;\r
845             src_y = (m_DestHeight - (dest_y + m_ClipRect.top) - 1) * src_height / m_DestHeight;\r
846         } else {\r
847             dest_y = m_LineIndex;\r
848             src_y = (dest_y + m_ClipRect.top) * src_height / m_DestHeight;\r
849         }\r
850         if (src_y >= src_height) {\r
851             src_y = src_height - 1;\r
852         }\r
853         if (src_y < 0) {\r
854             src_y = 0;\r
855         }\r
856         if (m_pSource->SkipToScanline(src_y, pPause)) {\r
857             return TRUE;\r
858         }\r
859         m_pSource->DownSampleScanline(src_y, m_pScanline, m_DestBPP, m_DestWidth, m_bFlipX, m_ClipRect.left, result_width);\r
860         FX_LPBYTE scan_extra_alpha = NULL;\r
861         if (m_pMaskScanline) {\r
862             m_pSource->m_pAlphaMask->DownSampleScanline(src_y, m_pMaskScanline, 1, m_DestWidth, m_bFlipX, m_ClipRect.left, result_width);\r
863         }\r
864         m_pDest->ComposeScanline(dest_y, m_pScanline, m_pMaskScanline);\r
865     }\r
866     return FALSE;\r
867 }\r