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