68 static constexpr size_t kMaxTableBytesAllowed = 512 * 1024 * 1024;
75 m_WeightTablesSizeBytes = 0;
76 m_WeightTables.clear();
80 if (dest_min > dest_max)
85 const double scale =
static_cast<
double>(src_len) / dest_len;
86 const double base = dest_len < 0 ? src_len : 0;
87 const size_t weight_count =
static_cast<size_t>(ceil(fabs(scale))) + 1;
88 m_ItemSizeBytes = PixelWeight::TotalBytesForWeightCount(weight_count);
90 const size_t dest_range =
static_cast<size_t>(dest_max - dest_min);
91 const size_t kMaxTableItemsAllowed = kMaxTableBytesAllowed / m_ItemSizeBytes;
92 if (dest_range > kMaxTableItemsAllowed)
95 m_WeightTablesSizeBytes = dest_range * m_ItemSizeBytes;
96 m_WeightTables.resize(m_WeightTablesSizeBytes);
98 for (
int dest_pixel = dest_min; dest_pixel < dest_max; ++dest_pixel) {
100 double src_pos = dest_pixel * scale + scale / 2 + base;
102 int src_start =
static_cast<
int>(floor(src_pos - 0.5));
103 int src_end =
static_cast<
int>(floor(src_pos + 0.5));
104 src_start =
std::max(src_start, src_min);
105 src_end =
std::min(src_end, src_max - 1);
106 pixel_weights.SetStartEnd(src_start, src_end, weight_count);
117 int pixel_pos =
static_cast<
int>(floor(src_pos));
118 int src_start =
std::max(pixel_pos, src_min);
119 int src_end =
std::min(pixel_pos, src_max - 1);
120 pixel_weights.SetStartEnd(src_start, src_end, weight_count);
127 for (
int dest_pixel = dest_min; dest_pixel < dest_max; ++dest_pixel) {
129 double src_start = dest_pixel * scale + base;
130 double src_end = src_start + scale;
131 int start_i = floor(
std::min(src_start, src_end));
132 int end_i = floor(
std::max(src_start, src_end));
133 start_i =
std::max(start_i, src_min);
134 end_i =
std::min(end_i, src_max - 1);
135 if (start_i > end_i) {
136 start_i =
std::min(start_i, src_max - 1);
137 pixel_weights.SetStartEnd(start_i, start_i, weight_count);
140 pixel_weights.SetStartEnd(start_i, end_i, weight_count);
142 double rounding_error = 0.0;
143 for (
int j = start_i; j < end_i; ++j) {
144 double dest_start = (j - base) / scale;
145 double dest_end = (j + 1 - base) / scale;
146 if (dest_start > dest_end)
147 std::swap(dest_start, dest_end);
148 double area_start =
std::max(dest_start,
static_cast<
double>(dest_pixel));
149 double area_end =
std::min(dest_end,
static_cast<
double>(dest_pixel + 1));
150 double weight =
std::max(0.0, area_end - area_start);
153 remaining -= fixed_weight;
187 : m_DestFormat(dest_format),
196 m_DestWidth(dest_width),
197 m_DestHeight(dest_height),
198 m_DestClip
(clip_rect
) {
202 DCHECK_EQ(m_pSource->GetFormat(), FXDIB_Format::kArgb);
206 absl::optional<uint32_t> maybe_size =
207 fxge::CalculatePitch32(m_DestBpp, clip_rect.Width());
208 if (!maybe_size.has_value())
211 m_DestScanline.resize(maybe_size.value());
212 if (dest_format == FXDIB_Format::kRgb32)
213 std::fill(m_DestScanline.begin(), m_DestScanline.end(), 255);
223 m_ResampleOptions = options;
226 double scale_x =
static_cast<
float>(m_SrcWidth) / m_DestWidth;
227 double scale_y =
static_cast<
float>(m_SrcHeight) / m_DestHeight;
228 double base_x = m_DestWidth > 0 ? 0.0f : m_DestWidth;
229 double base_y = m_DestHeight > 0 ? 0.0f : m_DestHeight;
230 double src_left = scale_x * (clip_rect
.left + base_x);
231 double src_right = scale_x * (clip_rect
.right + base_x);
232 double src_top = scale_y * (clip_rect
.top + base_y);
233 double src_bottom = scale_y * (clip_rect
.bottom + base_y);
234 if (src_left > src_right)
235 std::swap(src_left, src_right);
236 if (src_top > src_bottom)
237 std::swap(src_top, src_bottom);
238 m_SrcClip
.left =
static_cast<
int>(floor(src_left));
239 m_SrcClip
.right =
static_cast<
int>(ceil(src_right));
240 m_SrcClip
.top =
static_cast<
int>(floor(src_top));
241 m_SrcClip
.bottom =
static_cast<
int>(ceil(src_bottom));
247 m_TransMethod = m_DestBpp == 8 ? TransformMethod::k1BppTo8Bpp
248 : TransformMethod::k1BppToManyBpp;
251 m_TransMethod = m_DestBpp == 8 ? TransformMethod::k8BppTo8Bpp
252 : TransformMethod::k8BppToManyBpp;
255 m_TransMethod = m_bHasAlpha ? TransformMethod::kManyBpptoManyBppWithAlpha
256 : TransformMethod::kManyBpptoManyBpp;
275 if (m_DestWidth == 0 || m_InterPitch == 0 || m_DestScanline.empty())
278 FX_SAFE_SIZE_T safe_size = m_SrcClip.Height();
279 safe_size *= m_InterPitch;
280 const size_t size = safe_size.ValueOrDefault(0);
284 m_InterBuf = FixedSizeDataVector<uint8_t>::TryZeroed(size);
285 if (m_InterBuf.empty()) {
288 if (!m_WeightTable.CalculateWeights(
289 m_DestWidth, m_DestClip.left, m_DestClip.right, m_SrcWidth,
290 m_SrcClip.left, m_SrcClip.right, m_ResampleOptions)) {
293 m_CurRow = m_SrcClip
.top;
294 m_State = State::kHorizontal;
301 if (m_pSource->SkipToScanline(m_CurRow, pPause))
304 int Bpp = m_DestBpp / 8;
305 static const int kStrechPauseRows = 10;
306 int rows_to_go = kStrechPauseRows;
307 for (; m_CurRow < m_SrcClip
.bottom; ++m_CurRow) {
308 if (rows_to_go == 0) {
312 rows_to_go = kStrechPauseRows;
315 const uint8_t* src_scan = m_pSource->GetScanline(m_CurRow).data();
316 pdfium::span<uint8_t> dest_span = m_InterBuf.subspan(
317 (m_CurRow - m_SrcClip.top) * m_InterPitch, m_InterPitch);
318 size_t dest_span_index = 0;
320 switch (m_TransMethod) {
321 case TransformMethod::k1BppTo8Bpp:
322 case TransformMethod::k1BppToManyBpp: {
323 for (
int col = m_DestClip
.left; col < m_DestClip
.right; ++col) {
324 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
328 if (src_scan[j / 8] & (1 << (7 - j % 8)))
329 dest_a += pixel_weight * 255;
335 case TransformMethod::k8BppTo8Bpp: {
336 for (
int col = m_DestClip
.left; col < m_DestClip
.right; ++col) {
337 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
341 dest_a += pixel_weight * src_scan[j];
347 case TransformMethod::k8BppToManyBpp: {
348 for (
int col = m_DestClip
.left; col < m_DestClip
.right; ++col) {
349 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
355 unsigned long argb = m_pSrcPalette[src_scan[j]];
357 dest_r += pixel_weight *
static_cast<uint8_t>(argb >> 16);
358 dest_g += pixel_weight *
static_cast<uint8_t>(argb >> 8);
359 dest_b += pixel_weight *
static_cast<uint8_t>(argb);
361 dest_b += pixel_weight *
static_cast<uint8_t>(argb >> 24);
362 dest_g += pixel_weight *
static_cast<uint8_t>(argb >> 16);
363 dest_r += pixel_weight *
static_cast<uint8_t>(argb >> 8);
372 case TransformMethod::kManyBpptoManyBpp: {
373 for (
int col = m_DestClip
.left; col < m_DestClip
.right; ++col) {
374 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
380 const uint8_t* src_pixel = src_scan + j * Bpp;
381 dest_b += pixel_weight * (*src_pixel++);
382 dest_g += pixel_weight * (*src_pixel++);
383 dest_r += pixel_weight * (*src_pixel);
388 dest_span_index += Bpp - 3;
392 case TransformMethod::kManyBpptoManyBppWithAlpha: {
394 for (
int col = m_DestClip
.left; col < m_DestClip
.right; ++col) {
395 PixelWeight* pWeights = m_WeightTable.GetPixelWeight(col);
401 const uint8_t* src_pixel = src_scan + j * Bpp;
402 uint32_t pixel_weight =
404 dest_b += pixel_weight * (*src_pixel++);
405 dest_g += pixel_weight * (*src_pixel++);
406 dest_r += pixel_weight * (*src_pixel);
407 dest_a += pixel_weight;
413 dest_span_index += Bpp - 3;
424 if (m_DestHeight == 0)
430 m_ResampleOptions
)) {
434 const int DestBpp = m_DestBpp / 8;
435 for (
int row = m_DestClip
.top; row < m_DestClip
.bottom; ++row) {
436 unsigned char* dest_scan = m_DestScanline.data();
438 switch (m_TransMethod) {
439 case TransformMethod::k1BppTo8Bpp:
440 case TransformMethod::k1BppToManyBpp:
441 case TransformMethod::k8BppTo8Bpp: {
442 for (
int col = m_DestClip
.left; col < m_DestClip
.right; ++col) {
443 pdfium::span<
const uint8_t> src_span =
444 m_InterBuf.subspan((col - m_DestClip.left) * DestBpp);
449 pixel_weight * src_span[(j - m_SrcClip
.top) * m_InterPitch];
452 dest_scan += DestBpp;
456 case TransformMethod::k8BppToManyBpp:
457 case TransformMethod::kManyBpptoManyBpp: {
458 for (
int col = m_DestClip
.left; col < m_DestClip
.right; ++col) {
459 pdfium::span<
const uint8_t> src_span =
460 m_InterBuf.subspan((col - m_DestClip.left) * DestBpp);
466 pdfium::span<
const uint8_t> src_pixel =
467 src_span.subspan((j - m_SrcClip.top) * m_InterPitch, 3);
468 dest_b += pixel_weight * src_pixel[0];
469 dest_g += pixel_weight * src_pixel[1];
470 dest_r += pixel_weight * src_pixel[2];
475 dest_scan += DestBpp;
479 case TransformMethod::kManyBpptoManyBppWithAlpha: {
481 for (
int col = m_DestClip
.left; col < m_DestClip
.right; ++col) {
482 pdfium::span<
const uint8_t> src_span =
483 m_InterBuf.subspan((col - m_DestClip.left) * DestBpp);
488 constexpr size_t kPixelBytes = 4;
491 pdfium::span<
const uint8_t> src_pixel = src_span.subspan(
492 (j - m_SrcClip.top) * m_InterPitch, kPixelBytes);
493 dest_b += pixel_weight * src_pixel[0];
494 dest_g += pixel_weight * src_pixel[1];
495 dest_r += pixel_weight * src_pixel[2];
496 dest_a += pixel_weight * src_pixel[3];
499 int r =
static_cast<uint32_t>(dest_r) * 255 / dest_a;
500 int g =
static_cast<uint32_t>(dest_g) * 255 / dest_a;
501 int b =
static_cast<uint32_t>(dest_b) * 255 / dest_a;
502 dest_scan[0] =
std::clamp(b, 0, 255);
503 dest_scan[1] =
std::clamp(g, 0, 255);
504 dest_scan[2] =
std::clamp(r, 0, 255);
507 dest_scan += DestBpp;
512 m_pDestBitmap->ComposeScanline(row - m_DestClip.top, m_DestScanline);
CStretchEngine(ScanlineComposerIface *pDestBitmap, FXDIB_Format dest_format, int dest_width, int dest_height, const FX_RECT &clip_rect, const RetainPtr< const CFX_DIBBase > &pSrcBitmap, const FXDIB_ResampleOptions &options)