1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxge/dib/cstretchengine.h"
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "core/fxcrt/ifx_pauseindicator.h"
13 #include "core/fxge/dib/cfx_dibitmap.h"
14 #include "core/fxge/dib/cfx_dibsource.h"
15 #include "core/fxge/dib/ifx_scanlinecomposer.h"
16 #include "core/fxge/fx_dib.h"
17
18 namespace {
19
20 const int kMaxDestValue = 16711680;
21
22 } // namespace
23
CWeightTable()24 CStretchEngine::CWeightTable::CWeightTable()
25 : m_DestMin(0),
26 m_ItemSize(0),
27 m_dwWeightTablesSize(0) {}
28
~CWeightTable()29 CStretchEngine::CWeightTable::~CWeightTable() {}
30
GetPixelWeightSize() const31 size_t CStretchEngine::CWeightTable::GetPixelWeightSize() const {
32 return m_ItemSize / sizeof(int) - 2;
33 }
34
Calc(int dest_len,int dest_min,int dest_max,int src_len,int src_min,int src_max,int flags)35 bool CStretchEngine::CWeightTable::Calc(int dest_len,
36 int dest_min,
37 int dest_max,
38 int src_len,
39 int src_min,
40 int src_max,
41 int flags) {
42 m_WeightTables.clear();
43 m_dwWeightTablesSize = 0;
44 const double scale = static_cast<float>(src_len) / dest_len;
45 const double base = dest_len < 0 ? src_len : 0;
46 const int ext_size = flags & FXDIB_BICUBIC_INTERPOL ? 3 : 1;
47 m_ItemSize =
48 sizeof(int) * 2 +
49 static_cast<int>(sizeof(int) *
50 (ceil(fabs(static_cast<float>(scale))) + ext_size));
51
52 m_DestMin = dest_min;
53 if (dest_max - dest_min > static_cast<int>((1U << 30) - 4) / m_ItemSize)
54 return false;
55
56 m_dwWeightTablesSize = (dest_max - dest_min) * m_ItemSize + 4;
57 m_WeightTables.resize(m_dwWeightTablesSize);
58 if ((flags & FXDIB_NOSMOOTH) != 0 || fabs(static_cast<float>(scale)) < 1.0f) {
59 for (int dest_pixel = dest_min; dest_pixel < dest_max; ++dest_pixel) {
60 PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);
61 double src_pos = dest_pixel * scale + scale / 2 + base;
62 if (flags & FXDIB_INTERPOL) {
63 pixel_weights.m_SrcStart =
64 static_cast<int>(floor(static_cast<float>(src_pos) - 1.0f / 2));
65 pixel_weights.m_SrcEnd =
66 static_cast<int>(floor(static_cast<float>(src_pos) + 1.0f / 2));
67 pixel_weights.m_SrcStart = std::max(pixel_weights.m_SrcStart, src_min);
68 pixel_weights.m_SrcEnd = std::min(pixel_weights.m_SrcEnd, src_max - 1);
69 if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
70 pixel_weights.m_Weights[0] = 65536;
71 } else {
72 pixel_weights.m_Weights[1] =
73 FXSYS_round(static_cast<float>(
74 src_pos - pixel_weights.m_SrcStart - 1.0f / 2) *
75 65536);
76 pixel_weights.m_Weights[0] = 65536 - pixel_weights.m_Weights[1];
77 }
78 } else if (flags & FXDIB_BICUBIC_INTERPOL) {
79 pixel_weights.m_SrcStart =
80 static_cast<int>(floor(static_cast<float>(src_pos) - 1.0f / 2));
81 pixel_weights.m_SrcEnd =
82 static_cast<int>(floor(static_cast<float>(src_pos) + 1.0f / 2));
83 int start = pixel_weights.m_SrcStart - 1;
84 int end = pixel_weights.m_SrcEnd + 1;
85 start = std::max(start, src_min);
86 end = std::min(end, src_max - 1);
87 if (pixel_weights.m_SrcStart < src_min) {
88 src_pos += src_min - pixel_weights.m_SrcStart;
89 pixel_weights.m_SrcStart = src_min;
90 }
91 pixel_weights.m_SrcEnd = std::min(pixel_weights.m_SrcEnd, src_max - 1);
92 int weight = FXSYS_round(
93 static_cast<float>(src_pos - pixel_weights.m_SrcStart - 1.0f / 2) *
94 256);
95 if (start == end) {
96 pixel_weights.m_Weights[0] =
97 (SDP_Table[256 + weight] + SDP_Table[weight] +
98 SDP_Table[256 - weight] + SDP_Table[512 - weight])
99 << 8;
100 } else if ((start == pixel_weights.m_SrcStart &&
101 (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd ||
102 end == pixel_weights.m_SrcEnd) &&
103 start < end) ||
104 (start < pixel_weights.m_SrcStart &&
105 pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd &&
106 end == pixel_weights.m_SrcEnd)) {
107 if (start < pixel_weights.m_SrcStart) {
108 pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
109 pixel_weights.m_Weights[1] =
110 (SDP_Table[weight] + SDP_Table[256 - weight] +
111 SDP_Table[512 - weight])
112 << 8;
113 } else {
114 if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
115 pixel_weights.m_Weights[0] =
116 (SDP_Table[256 + weight] + SDP_Table[weight] +
117 SDP_Table[256 - weight])
118 << 8;
119 pixel_weights.m_Weights[1] = SDP_Table[512 - weight] << 8;
120 } else {
121 pixel_weights.m_Weights[0] =
122 (SDP_Table[256 + weight] + SDP_Table[weight]) << 8;
123 pixel_weights.m_Weights[1] =
124 (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;
125 }
126 }
127 if (pixel_weights.m_SrcStart == pixel_weights.m_SrcEnd) {
128 pixel_weights.m_SrcEnd = end;
129 }
130 if (start < pixel_weights.m_SrcStart) {
131 pixel_weights.m_SrcStart = start;
132 }
133 } else if (start == pixel_weights.m_SrcStart &&
134 start < pixel_weights.m_SrcEnd &&
135 pixel_weights.m_SrcEnd < end) {
136 pixel_weights.m_Weights[0] =
137 (SDP_Table[256 + weight] + SDP_Table[weight]) << 8;
138 pixel_weights.m_Weights[1] = SDP_Table[256 - weight] << 8;
139 pixel_weights.m_Weights[2] = SDP_Table[512 - weight] << 8;
140 pixel_weights.m_SrcEnd = end;
141 } else if (start < pixel_weights.m_SrcStart &&
142 pixel_weights.m_SrcStart < pixel_weights.m_SrcEnd &&
143 pixel_weights.m_SrcEnd == end) {
144 pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
145 pixel_weights.m_Weights[1] = SDP_Table[weight] << 8;
146 pixel_weights.m_Weights[2] =
147 (SDP_Table[256 - weight] + SDP_Table[512 - weight]) << 8;
148 pixel_weights.m_SrcStart = start;
149 } else {
150 pixel_weights.m_Weights[0] = SDP_Table[256 + weight] << 8;
151 pixel_weights.m_Weights[1] = SDP_Table[weight] << 8;
152 pixel_weights.m_Weights[2] = SDP_Table[256 - weight] << 8;
153 pixel_weights.m_Weights[3] = SDP_Table[512 - weight] << 8;
154 pixel_weights.m_SrcStart = start;
155 pixel_weights.m_SrcEnd = end;
156 }
157 } else {
158 int pixel_pos = static_cast<int>(floor(static_cast<float>(src_pos)));
159 pixel_weights.m_SrcStart = std::max(pixel_pos, src_min);
160 pixel_weights.m_SrcEnd = std::min(pixel_pos, src_max - 1);
161 pixel_weights.m_Weights[0] = 65536;
162 }
163 }
164 return true;
165 }
166
167 for (int dest_pixel = dest_min; dest_pixel < dest_max; ++dest_pixel) {
168 PixelWeight& pixel_weights = *GetPixelWeight(dest_pixel);
169 double src_start = dest_pixel * scale + base;
170 double src_end = src_start + scale;
171 int start_i = floor(std::min(src_start, src_end));
172 int end_i = floor(std::max(src_start, src_end));
173 start_i = std::max(start_i, src_min);
174 end_i = std::min(end_i, src_max - 1);
175 if (start_i > end_i) {
176 start_i = std::min(start_i, src_max - 1);
177 pixel_weights.m_SrcStart = start_i;
178 pixel_weights.m_SrcEnd = start_i;
179 continue;
180 }
181 pixel_weights.m_SrcStart = start_i;
182 pixel_weights.m_SrcEnd = end_i;
183 for (int j = start_i; j <= end_i; ++j) {
184 double dest_start = (j - base) / scale;
185 double dest_end = (j + 1 - base) / scale;
186 if (dest_start > dest_end)
187 std::swap(dest_start, dest_end);
188 double area_start = std::max(dest_start, static_cast<double>(dest_pixel));
189 double area_end = std::min(dest_end, static_cast<double>(dest_pixel + 1));
190 double weight = std::max(0.0, area_end - area_start);
191 if (weight == 0 && j == end_i) {
192 --pixel_weights.m_SrcEnd;
193 break;
194 }
195 size_t idx = j - start_i;
196 if (idx >= GetPixelWeightSize())
197 return false;
198
199 pixel_weights.m_Weights[idx] = FXSYS_round(weight * 65536);
200 }
201 }
202 return true;
203 }
204
GetPixelWeight(int pixel) const205 PixelWeight* CStretchEngine::CWeightTable::GetPixelWeight(int pixel) const {
206 ASSERT(pixel >= m_DestMin);
207 return reinterpret_cast<PixelWeight*>(const_cast<uint8_t*>(
208 m_WeightTables.data() + (pixel - m_DestMin) * m_ItemSize));
209 }
210
GetValueFromPixelWeight(PixelWeight * pWeight,int index) const211 int* CStretchEngine::CWeightTable::GetValueFromPixelWeight(PixelWeight* pWeight,
212 int index) const {
213 if (index < pWeight->m_SrcStart)
214 return nullptr;
215
216 size_t idx = index - pWeight->m_SrcStart;
217 return idx < GetPixelWeightSize() ? &pWeight->m_Weights[idx] : nullptr;
218 }
219
CStretchEngine(IFX_ScanlineComposer * pDestBitmap,FXDIB_Format dest_format,int dest_width,int dest_height,const FX_RECT & clip_rect,const RetainPtr<CFX_DIBSource> & pSrcBitmap,int flags)220 CStretchEngine::CStretchEngine(IFX_ScanlineComposer* pDestBitmap,
221 FXDIB_Format dest_format,
222 int dest_width,
223 int dest_height,
224 const FX_RECT& clip_rect,
225 const RetainPtr<CFX_DIBSource>& pSrcBitmap,
226 int flags) {
227 m_State = 0;
228 m_DestFormat = dest_format;
229 m_DestBpp = dest_format & 0xff;
230 m_SrcBpp = pSrcBitmap->GetFormat() & 0xff;
231 m_bHasAlpha = pSrcBitmap->GetFormat() & 0x200;
232 m_pSrcPalette = pSrcBitmap->GetPalette();
233 m_pDestBitmap = pDestBitmap;
234 m_DestWidth = dest_width;
235 m_DestHeight = dest_height;
236 m_DestClip = clip_rect;
237 uint32_t size = clip_rect.Width();
238 if (size && m_DestBpp > static_cast<int>(INT_MAX / size))
239 return;
240
241 size *= m_DestBpp;
242 if (size > INT_MAX - 31)
243 return;
244
245 size += 31;
246 size = size / 32 * 4;
247 m_DestScanline.resize(size);
248 if (dest_format == FXDIB_Rgb32)
249 std::fill(m_DestScanline.begin(), m_DestScanline.end(), 255);
250 m_InterPitch = (m_DestClip.Width() * m_DestBpp + 31) / 32 * 4;
251 m_ExtraMaskPitch = (m_DestClip.Width() * 8 + 31) / 32 * 4;
252 m_pSource = pSrcBitmap;
253 m_SrcWidth = pSrcBitmap->GetWidth();
254 m_SrcHeight = pSrcBitmap->GetHeight();
255 m_SrcPitch = (m_SrcWidth * m_SrcBpp + 31) / 32 * 4;
256 if ((flags & FXDIB_NOSMOOTH) == 0) {
257 bool bInterpol = flags & FXDIB_INTERPOL || flags & FXDIB_BICUBIC_INTERPOL;
258 if (!bInterpol && abs(dest_width) != 0 &&
259 abs(dest_height) / 8 < static_cast<long long>(m_SrcWidth) *
260 m_SrcHeight / abs(dest_width)) {
261 flags = FXDIB_INTERPOL;
262 }
263 m_Flags = flags;
264 } else {
265 m_Flags = FXDIB_NOSMOOTH;
266 if (flags & FXDIB_DOWNSAMPLE)
267 m_Flags |= FXDIB_DOWNSAMPLE;
268 }
269 double scale_x = static_cast<float>(m_SrcWidth) / m_DestWidth;
270 double scale_y = static_cast<float>(m_SrcHeight) / m_DestHeight;
271 double base_x = m_DestWidth > 0 ? 0.0f : m_DestWidth;
272 double base_y = m_DestHeight > 0 ? 0.0f : m_DestHeight;
273 double src_left = scale_x * (clip_rect.left + base_x);
274 double src_right = scale_x * (clip_rect.right + base_x);
275 double src_top = scale_y * (clip_rect.top + base_y);
276 double src_bottom = scale_y * (clip_rect.bottom + base_y);
277 if (src_left > src_right)
278 std::swap(src_left, src_right);
279 if (src_top > src_bottom)
280 std::swap(src_top, src_bottom);
281 m_SrcClip.left = static_cast<int>(floor(src_left));
282 m_SrcClip.right = static_cast<int>(ceil(src_right));
283 m_SrcClip.top = static_cast<int>(floor(src_top));
284 m_SrcClip.bottom = static_cast<int>(ceil(src_bottom));
285 FX_RECT src_rect(0, 0, m_SrcWidth, m_SrcHeight);
286 m_SrcClip.Intersect(src_rect);
287 if (m_SrcBpp == 1) {
288 if (m_DestBpp == 8)
289 m_TransMethod = 1;
290 else
291 m_TransMethod = 2;
292 } else if (m_SrcBpp == 8) {
293 if (m_DestBpp == 8) {
294 if (!m_bHasAlpha)
295 m_TransMethod = 3;
296 else
297 m_TransMethod = 4;
298 } else {
299 if (!m_bHasAlpha)
300 m_TransMethod = 5;
301 else
302 m_TransMethod = 6;
303 }
304 } else {
305 if (!m_bHasAlpha)
306 m_TransMethod = 7;
307 else
308 m_TransMethod = 8;
309 }
310 }
311
~CStretchEngine()312 CStretchEngine::~CStretchEngine() {}
313
Continue(IFX_PauseIndicator * pPause)314 bool CStretchEngine::Continue(IFX_PauseIndicator* pPause) {
315 while (m_State == 1) {
316 if (ContinueStretchHorz(pPause))
317 return true;
318
319 m_State = 2;
320 StretchVert();
321 }
322 return false;
323 }
324
StartStretchHorz()325 bool CStretchEngine::StartStretchHorz() {
326 if (m_DestWidth == 0 || m_InterPitch == 0 || m_DestScanline.empty())
327 return false;
328
329 if (m_SrcClip.Height() == 0 ||
330 m_SrcClip.Height() > (1 << 29) / m_InterPitch) {
331 return false;
332 }
333
334 m_InterBuf.resize(m_SrcClip.Height() * m_InterPitch);
335 if (m_pSource && m_bHasAlpha && m_pSource->m_pAlphaMask) {
336 m_ExtraAlphaBuf.resize(m_SrcClip.Height(), m_ExtraMaskPitch);
337 uint32_t size = (m_DestClip.Width() * 8 + 31) / 32 * 4;
338 m_DestMaskScanline.resize(size);
339 }
340 bool ret =
341 m_WeightTable.Calc(m_DestWidth, m_DestClip.left, m_DestClip.right,
342 m_SrcWidth, m_SrcClip.left, m_SrcClip.right, m_Flags);
343 if (!ret)
344 return false;
345
346 m_CurRow = m_SrcClip.top;
347 m_State = 1;
348 return true;
349 }
350
ContinueStretchHorz(IFX_PauseIndicator * pPause)351 bool CStretchEngine::ContinueStretchHorz(IFX_PauseIndicator* pPause) {
352 if (!m_DestWidth)
353 return false;
354 if (m_pSource->SkipToScanline(m_CurRow, pPause))
355 return true;
356
357 int Bpp = m_DestBpp / 8;
358 static const int kStrechPauseRows = 10;
359 int rows_to_go = kStrechPauseRows;
360 for (; m_CurRow < m_SrcClip.bottom; ++m_CurRow) {
361 if (rows_to_go == 0) {
362 if (pPause && pPause->NeedToPauseNow())
363 return true;
364
365 rows_to_go = kStrechPauseRows;
366 }
367
368 const uint8_t* src_scan = m_pSource->GetScanline(m_CurRow);
369 uint8_t* dest_scan =
370 m_InterBuf.data() + (m_CurRow - m_SrcClip.top) * m_InterPitch;
371 const uint8_t* src_scan_mask = nullptr;
372 uint8_t* dest_scan_mask = nullptr;
373 if (!m_ExtraAlphaBuf.empty()) {
374 src_scan_mask = m_pSource->m_pAlphaMask->GetScanline(m_CurRow);
375 dest_scan_mask = m_ExtraAlphaBuf.data() +
376 (m_CurRow - m_SrcClip.top) * m_ExtraMaskPitch;
377 }
378 // TODO(npm): reduce duplicated code here
379 switch (m_TransMethod) {
380 case 1:
381 case 2: {
382 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
383 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
384 int dest_a = 0;
385 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
386 int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
387 if (!pWeight)
388 return false;
389
390 int pixel_weight = *pWeight;
391 if (src_scan[j / 8] & (1 << (7 - j % 8)))
392 dest_a += pixel_weight * 255;
393 }
394 if (m_Flags & FXDIB_BICUBIC_INTERPOL)
395 dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
396 *dest_scan++ = static_cast<uint8_t>(dest_a >> 16);
397 }
398 break;
399 }
400 case 3: {
401 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
402 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
403 int dest_a = 0;
404 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
405 int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
406 if (!pWeight)
407 return false;
408
409 int pixel_weight = *pWeight;
410 dest_a += pixel_weight * src_scan[j];
411 }
412 if (m_Flags & FXDIB_BICUBIC_INTERPOL)
413 dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
414 *dest_scan++ = static_cast<uint8_t>(dest_a >> 16);
415 }
416 break;
417 }
418 case 4: {
419 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
420 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
421 int dest_a = 0;
422 int dest_r = 0;
423 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
424 int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
425 if (!pWeight)
426 return false;
427
428 int pixel_weight = *pWeight;
429 pixel_weight = pixel_weight * src_scan_mask[j] / 255;
430 dest_r += pixel_weight * src_scan[j];
431 dest_a += pixel_weight;
432 }
433 if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
434 dest_r = pdfium::clamp(dest_r, 0, kMaxDestValue);
435 dest_a = pdfium::clamp(dest_a, 0, 65536);
436 }
437 *dest_scan++ = static_cast<uint8_t>(dest_r >> 16);
438 *dest_scan_mask++ = static_cast<uint8_t>((dest_a * 255) >> 16);
439 }
440 break;
441 }
442 case 5: {
443 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
444 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
445 int dest_r_y = 0;
446 int dest_g_m = 0;
447 int dest_b_c = 0;
448 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
449 int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
450 if (!pWeight)
451 return false;
452
453 int pixel_weight = *pWeight;
454 unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]];
455 if (m_DestFormat == FXDIB_Rgb) {
456 dest_r_y += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 16);
457 dest_g_m += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 8);
458 dest_b_c += pixel_weight * static_cast<uint8_t>(argb_cmyk);
459 } else {
460 dest_b_c += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 24);
461 dest_g_m += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 16);
462 dest_r_y += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 8);
463 }
464 }
465 if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
466 dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
467 dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
468 dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
469 }
470 *dest_scan++ = static_cast<uint8_t>(dest_b_c >> 16);
471 *dest_scan++ = static_cast<uint8_t>(dest_g_m >> 16);
472 *dest_scan++ = static_cast<uint8_t>(dest_r_y >> 16);
473 }
474 break;
475 }
476 case 6: {
477 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
478 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
479 int dest_a = 0;
480 int dest_r_y = 0;
481 int dest_g_m = 0;
482 int dest_b_c = 0;
483 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
484 int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
485 if (!pWeight)
486 return false;
487
488 int pixel_weight = *pWeight;
489 pixel_weight = pixel_weight * src_scan_mask[j] / 255;
490 unsigned long argb_cmyk = m_pSrcPalette[src_scan[j]];
491 if (m_DestFormat == FXDIB_Rgba) {
492 dest_r_y += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 16);
493 dest_g_m += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 8);
494 dest_b_c += pixel_weight * static_cast<uint8_t>(argb_cmyk);
495 } else {
496 dest_b_c += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 24);
497 dest_g_m += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 16);
498 dest_r_y += pixel_weight * static_cast<uint8_t>(argb_cmyk >> 8);
499 }
500 dest_a += pixel_weight;
501 }
502 if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
503 dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
504 dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
505 dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
506 dest_a = pdfium::clamp(dest_a, 0, 65536);
507 }
508 *dest_scan++ = static_cast<uint8_t>(dest_b_c >> 16);
509 *dest_scan++ = static_cast<uint8_t>(dest_g_m >> 16);
510 *dest_scan++ = static_cast<uint8_t>(dest_r_y >> 16);
511 *dest_scan_mask++ = static_cast<uint8_t>((dest_a * 255) >> 16);
512 }
513 break;
514 }
515 case 7: {
516 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
517 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
518 int dest_r_y = 0;
519 int dest_g_m = 0;
520 int dest_b_c = 0;
521 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
522 int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
523 if (!pWeight)
524 return false;
525
526 int pixel_weight = *pWeight;
527 const uint8_t* src_pixel = src_scan + j * Bpp;
528 dest_b_c += pixel_weight * (*src_pixel++);
529 dest_g_m += pixel_weight * (*src_pixel++);
530 dest_r_y += pixel_weight * (*src_pixel);
531 }
532 if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
533 dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
534 dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
535 dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
536 }
537 *dest_scan++ = static_cast<uint8_t>((dest_b_c) >> 16);
538 *dest_scan++ = static_cast<uint8_t>((dest_g_m) >> 16);
539 *dest_scan++ = static_cast<uint8_t>((dest_r_y) >> 16);
540 dest_scan += Bpp - 3;
541 }
542 break;
543 }
544 case 8: {
545 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
546 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
547 int dest_a = 0;
548 int dest_r_y = 0;
549 int dest_g_m = 0;
550 int dest_b_c = 0;
551 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
552 int* pWeight = m_WeightTable.GetValueFromPixelWeight(pWeights, j);
553 if (!pWeight)
554 return false;
555
556 int pixel_weight = *pWeight;
557 const uint8_t* src_pixel = src_scan + j * Bpp;
558 if (m_DestFormat == FXDIB_Argb) {
559 pixel_weight = pixel_weight * src_pixel[3] / 255;
560 } else {
561 pixel_weight = pixel_weight * src_scan_mask[j] / 255;
562 }
563 dest_b_c += pixel_weight * (*src_pixel++);
564 dest_g_m += pixel_weight * (*src_pixel++);
565 dest_r_y += pixel_weight * (*src_pixel);
566 dest_a += pixel_weight;
567 }
568 if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
569 dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
570 dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
571 dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
572 dest_a = pdfium::clamp(dest_a, 0, 65536);
573 }
574 *dest_scan++ = static_cast<uint8_t>((dest_b_c) >> 16);
575 *dest_scan++ = static_cast<uint8_t>((dest_g_m) >> 16);
576 *dest_scan++ = static_cast<uint8_t>((dest_r_y) >> 16);
577 if (m_DestFormat == FXDIB_Argb)
578 *dest_scan = static_cast<uint8_t>((dest_a * 255) >> 16);
579 if (dest_scan_mask)
580 *dest_scan_mask++ = static_cast<uint8_t>((dest_a * 255) >> 16);
581 dest_scan += Bpp - 3;
582 }
583 break;
584 }
585 }
586 rows_to_go--;
587 }
588 return false;
589 }
590
StretchVert()591 void CStretchEngine::StretchVert() {
592 if (m_DestHeight == 0)
593 return;
594
595 CWeightTable table;
596 bool ret = table.Calc(m_DestHeight, m_DestClip.top, m_DestClip.bottom,
597 m_SrcHeight, m_SrcClip.top, m_SrcClip.bottom, m_Flags);
598 if (!ret)
599 return;
600
601 const int DestBpp = m_DestBpp / 8;
602 for (int row = m_DestClip.top; row < m_DestClip.bottom; ++row) {
603 unsigned char* dest_scan = m_DestScanline.data();
604 unsigned char* dest_scan_mask = m_DestMaskScanline.data();
605 PixelWeight* pWeights = table.GetPixelWeight(row);
606 switch (m_TransMethod) {
607 case 1:
608 case 2:
609 case 3: {
610 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
611 unsigned char* src_scan =
612 m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
613 int dest_a = 0;
614 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
615 int* pWeight = table.GetValueFromPixelWeight(pWeights, j);
616 if (!pWeight)
617 return;
618
619 int pixel_weight = *pWeight;
620 dest_a +=
621 pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];
622 }
623 if (m_Flags & FXDIB_BICUBIC_INTERPOL)
624 dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
625 *dest_scan = static_cast<uint8_t>(dest_a >> 16);
626 dest_scan += DestBpp;
627 }
628 break;
629 }
630 case 4: {
631 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
632 unsigned char* src_scan =
633 m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
634 unsigned char* src_scan_mask =
635 m_ExtraAlphaBuf.data() + (col - m_DestClip.left);
636 int dest_a = 0;
637 int dest_k = 0;
638 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
639 int* pWeight = table.GetValueFromPixelWeight(pWeights, j);
640 if (!pWeight)
641 return;
642
643 int pixel_weight = *pWeight;
644 dest_k +=
645 pixel_weight * src_scan[(j - m_SrcClip.top) * m_InterPitch];
646 dest_a += pixel_weight *
647 src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch];
648 }
649 if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
650 dest_k = pdfium::clamp(dest_k, 0, kMaxDestValue);
651 dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
652 }
653 *dest_scan = static_cast<uint8_t>(dest_k >> 16);
654 dest_scan += DestBpp;
655 *dest_scan_mask++ = static_cast<uint8_t>(dest_a >> 16);
656 }
657 break;
658 }
659 case 5:
660 case 7: {
661 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
662 unsigned char* src_scan =
663 m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
664 int dest_r_y = 0;
665 int dest_g_m = 0;
666 int dest_b_c = 0;
667 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
668 int* pWeight = table.GetValueFromPixelWeight(pWeights, j);
669 if (!pWeight)
670 return;
671
672 int pixel_weight = *pWeight;
673 const uint8_t* src_pixel =
674 src_scan + (j - m_SrcClip.top) * m_InterPitch;
675 dest_b_c += pixel_weight * (*src_pixel++);
676 dest_g_m += pixel_weight * (*src_pixel++);
677 dest_r_y += pixel_weight * (*src_pixel);
678 }
679 if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
680 dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
681 dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
682 dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
683 }
684 dest_scan[0] = static_cast<uint8_t>((dest_b_c) >> 16);
685 dest_scan[1] = static_cast<uint8_t>((dest_g_m) >> 16);
686 dest_scan[2] = static_cast<uint8_t>((dest_r_y) >> 16);
687 dest_scan += DestBpp;
688 }
689 break;
690 }
691 case 6:
692 case 8: {
693 for (int col = m_DestClip.left; col < m_DestClip.right; ++col) {
694 unsigned char* src_scan =
695 m_InterBuf.data() + (col - m_DestClip.left) * DestBpp;
696 unsigned char* src_scan_mask = nullptr;
697 if (m_DestFormat != FXDIB_Argb)
698 src_scan_mask = m_ExtraAlphaBuf.data() + (col - m_DestClip.left);
699 int dest_a = 0;
700 int dest_r_y = 0;
701 int dest_g_m = 0;
702 int dest_b_c = 0;
703 for (int j = pWeights->m_SrcStart; j <= pWeights->m_SrcEnd; ++j) {
704 int* pWeight = table.GetValueFromPixelWeight(pWeights, j);
705 if (!pWeight)
706 return;
707
708 int pixel_weight = *pWeight;
709 const uint8_t* src_pixel =
710 src_scan + (j - m_SrcClip.top) * m_InterPitch;
711 int mask_v = 255;
712 if (src_scan_mask)
713 mask_v = src_scan_mask[(j - m_SrcClip.top) * m_ExtraMaskPitch];
714 dest_b_c += pixel_weight * (*src_pixel++);
715 dest_g_m += pixel_weight * (*src_pixel++);
716 dest_r_y += pixel_weight * (*src_pixel);
717 if (m_DestFormat == FXDIB_Argb)
718 dest_a += pixel_weight * (*(src_pixel + 1));
719 else
720 dest_a += pixel_weight * mask_v;
721 }
722 if (m_Flags & FXDIB_BICUBIC_INTERPOL) {
723 dest_r_y = pdfium::clamp(dest_r_y, 0, kMaxDestValue);
724 dest_g_m = pdfium::clamp(dest_g_m, 0, kMaxDestValue);
725 dest_b_c = pdfium::clamp(dest_b_c, 0, kMaxDestValue);
726 dest_a = pdfium::clamp(dest_a, 0, kMaxDestValue);
727 }
728 if (dest_a) {
729 int r = static_cast<uint32_t>(dest_r_y) * 255 / dest_a;
730 int g = static_cast<uint32_t>(dest_g_m) * 255 / dest_a;
731 int b = static_cast<uint32_t>(dest_b_c) * 255 / dest_a;
732 dest_scan[0] = pdfium::clamp(b, 0, 255);
733 dest_scan[1] = pdfium::clamp(g, 0, 255);
734 dest_scan[2] = pdfium::clamp(r, 0, 255);
735 }
736 if (m_DestFormat == FXDIB_Argb)
737 dest_scan[3] = static_cast<uint8_t>((dest_a) >> 16);
738 else
739 *dest_scan_mask = static_cast<uint8_t>((dest_a) >> 16);
740 dest_scan += DestBpp;
741 if (dest_scan_mask)
742 dest_scan_mask++;
743 }
744 break;
745 }
746 }
747 m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_DestScanline.data(),
748 m_DestMaskScanline.data());
749 }
750 }
751