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