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 17 bool SourceSizeWithinLimit(int width, int height) { 18 const int kMaxProgressiveStretchPixels = 1000000; 19 return !height || width < kMaxProgressiveStretchPixels / height; 20 } 21 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 35 CWeightTable::CWeightTable() 36 : m_DestMin(0), 37 m_ItemSize(0), 38 m_pWeightTables(nullptr), 39 m_dwWeightTablesSize(0) {} 40 41 CWeightTable::~CWeightTable() { 42 FX_Free(m_pWeightTables); 43 } 44 45 size_t CWeightTable::GetPixelWeightSize() const { 46 return m_ItemSize / sizeof(int) - 2; 47 } 48 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 251 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 257 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 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 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 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 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 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 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 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 876 CFX_ImageStretcher::~CFX_ImageStretcher() { 877 } 878 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 926 bool CFX_ImageStretcher::Continue(IFX_Pause* pPause) { 927 if (m_Flags & FXDIB_DOWNSAMPLE) 928 return ContinueQuickStretch(pPause); 929 return ContinueStretch(pPause); 930 } 931 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 944 bool CFX_ImageStretcher::ContinueStretch(IFX_Pause* pPause) { 945 return m_pStretchEngine && m_pStretchEngine->Continue(pPause); 946 } 947 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 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