1 // Copyright 2016 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/fpdfapi/render/cpdf_renderstatus.h" 8 9 #include <algorithm> 10 #include <cmath> 11 #include <limits> 12 #include <memory> 13 #include <utility> 14 #include <vector> 15 16 #include "core/fpdfapi/font/cpdf_font.h" 17 #include "core/fpdfapi/font/cpdf_type3char.h" 18 #include "core/fpdfapi/font/cpdf_type3font.h" 19 #include "core/fpdfapi/page/cpdf_docpagedata.h" 20 #include "core/fpdfapi/page/cpdf_form.h" 21 #include "core/fpdfapi/page/cpdf_formobject.h" 22 #include "core/fpdfapi/page/cpdf_function.h" 23 #include "core/fpdfapi/page/cpdf_graphicstates.h" 24 #include "core/fpdfapi/page/cpdf_image.h" 25 #include "core/fpdfapi/page/cpdf_imageobject.h" 26 #include "core/fpdfapi/page/cpdf_meshstream.h" 27 #include "core/fpdfapi/page/cpdf_page.h" 28 #include "core/fpdfapi/page/cpdf_pageobject.h" 29 #include "core/fpdfapi/page/cpdf_pathobject.h" 30 #include "core/fpdfapi/page/cpdf_shadingobject.h" 31 #include "core/fpdfapi/page/cpdf_shadingpattern.h" 32 #include "core/fpdfapi/page/cpdf_textobject.h" 33 #include "core/fpdfapi/page/cpdf_tilingpattern.h" 34 #include "core/fpdfapi/parser/cpdf_array.h" 35 #include "core/fpdfapi/parser/cpdf_dictionary.h" 36 #include "core/fpdfapi/parser/cpdf_document.h" 37 #include "core/fpdfapi/render/cpdf_charposlist.h" 38 #include "core/fpdfapi/render/cpdf_devicebuffer.h" 39 #include "core/fpdfapi/render/cpdf_dibsource.h" 40 #include "core/fpdfapi/render/cpdf_docrenderdata.h" 41 #include "core/fpdfapi/render/cpdf_imagerenderer.h" 42 #include "core/fpdfapi/render/cpdf_pagerendercache.h" 43 #include "core/fpdfapi/render/cpdf_rendercontext.h" 44 #include "core/fpdfapi/render/cpdf_renderoptions.h" 45 #include "core/fpdfapi/render/cpdf_scaledrenderbuffer.h" 46 #include "core/fpdfapi/render/cpdf_textrenderer.h" 47 #include "core/fpdfapi/render/cpdf_transferfunc.h" 48 #include "core/fpdfapi/render/cpdf_type3cache.h" 49 #include "core/fpdfdoc/cpdf_occontext.h" 50 #include "core/fxcrt/autorestorer.h" 51 #include "core/fxcrt/cfx_fixedbufgrow.h" 52 #include "core/fxcrt/fx_safe_types.h" 53 #include "core/fxcrt/maybe_owned.h" 54 #include "core/fxge/cfx_defaultrenderdevice.h" 55 #include "core/fxge/cfx_graphstatedata.h" 56 #include "core/fxge/cfx_pathdata.h" 57 #include "core/fxge/cfx_renderdevice.h" 58 #include "core/fxge/ifx_renderdevicedriver.h" 59 #include "third_party/base/logging.h" 60 #include "third_party/base/numerics/safe_math.h" 61 #include "third_party/base/ptr_util.h" 62 63 #ifdef _SKIA_SUPPORT_ 64 #include "core/fxge/skia/fx_skia_device.h" 65 #endif 66 67 #define SHADING_STEPS 256 68 69 namespace { 70 71 void ReleaseCachedType3(CPDF_Type3Font* pFont) { 72 CPDF_Document* pDoc = pFont->GetDocument(); 73 if (!pDoc) 74 return; 75 76 pDoc->GetRenderData()->MaybePurgeCachedType3(pFont); 77 pDoc->GetPageData()->ReleaseFont(pFont->GetFontDict()); 78 } 79 80 class CPDF_RefType3Cache { 81 public: 82 explicit CPDF_RefType3Cache(CPDF_Type3Font* pType3Font) 83 : m_dwCount(0), m_pType3Font(pType3Font) {} 84 85 ~CPDF_RefType3Cache() { 86 while (m_dwCount--) 87 ReleaseCachedType3(m_pType3Font.Get()); 88 } 89 90 uint32_t m_dwCount; 91 UnownedPtr<CPDF_Type3Font> const m_pType3Font; 92 }; 93 94 uint32_t CountOutputs( 95 const std::vector<std::unique_ptr<CPDF_Function>>& funcs) { 96 uint32_t total = 0; 97 for (const auto& func : funcs) { 98 if (func) 99 total += func->CountOutputs(); 100 } 101 return total; 102 } 103 104 void DrawAxialShading(const RetainPtr<CFX_DIBitmap>& pBitmap, 105 CFX_Matrix* pObject2Bitmap, 106 CPDF_Dictionary* pDict, 107 const std::vector<std::unique_ptr<CPDF_Function>>& funcs, 108 CPDF_ColorSpace* pCS, 109 int alpha) { 110 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 111 CPDF_Array* pCoords = pDict->GetArrayFor("Coords"); 112 if (!pCoords) 113 return; 114 115 float start_x = pCoords->GetNumberAt(0); 116 float start_y = pCoords->GetNumberAt(1); 117 float end_x = pCoords->GetNumberAt(2); 118 float end_y = pCoords->GetNumberAt(3); 119 float t_min = 0; 120 float t_max = 1.0f; 121 CPDF_Array* pArray = pDict->GetArrayFor("Domain"); 122 if (pArray) { 123 t_min = pArray->GetNumberAt(0); 124 t_max = pArray->GetNumberAt(1); 125 } 126 bool bStartExtend = false; 127 bool bEndExtend = false; 128 pArray = pDict->GetArrayFor("Extend"); 129 if (pArray) { 130 bStartExtend = !!pArray->GetIntegerAt(0); 131 bEndExtend = !!pArray->GetIntegerAt(1); 132 } 133 int width = pBitmap->GetWidth(); 134 int height = pBitmap->GetHeight(); 135 float x_span = end_x - start_x; 136 float y_span = end_y - start_y; 137 float axis_len_square = (x_span * x_span) + (y_span * y_span); 138 uint32_t total_results = 139 std::max(CountOutputs(funcs), pCS->CountComponents()); 140 CFX_FixedBufGrow<float, 16> result_array(total_results); 141 float* pResults = result_array; 142 memset(pResults, 0, total_results * sizeof(float)); 143 uint32_t rgb_array[SHADING_STEPS]; 144 for (int i = 0; i < SHADING_STEPS; i++) { 145 float input = (t_max - t_min) * i / SHADING_STEPS + t_min; 146 int offset = 0; 147 for (const auto& func : funcs) { 148 if (func) { 149 int nresults = 0; 150 if (func->Call(&input, 1, pResults + offset, &nresults)) 151 offset += nresults; 152 } 153 } 154 float R = 0.0f; 155 float G = 0.0f; 156 float B = 0.0f; 157 pCS->GetRGB(pResults, &R, &G, &B); 158 rgb_array[i] = 159 FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255), 160 FXSYS_round(G * 255), FXSYS_round(B * 255))); 161 } 162 int pitch = pBitmap->GetPitch(); 163 CFX_Matrix matrix = pObject2Bitmap->GetInverse(); 164 for (int row = 0; row < height; row++) { 165 uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch); 166 for (int column = 0; column < width; column++) { 167 CFX_PointF pos = matrix.Transform( 168 CFX_PointF(static_cast<float>(column), static_cast<float>(row))); 169 float scale = 170 (((pos.x - start_x) * x_span) + ((pos.y - start_y) * y_span)) / 171 axis_len_square; 172 int index = (int32_t)(scale * (SHADING_STEPS - 1)); 173 if (index < 0) { 174 if (!bStartExtend) 175 continue; 176 177 index = 0; 178 } else if (index >= SHADING_STEPS) { 179 if (!bEndExtend) 180 continue; 181 182 index = SHADING_STEPS - 1; 183 } 184 dib_buf[column] = rgb_array[index]; 185 } 186 } 187 } 188 189 void DrawRadialShading(const RetainPtr<CFX_DIBitmap>& pBitmap, 190 CFX_Matrix* pObject2Bitmap, 191 CPDF_Dictionary* pDict, 192 const std::vector<std::unique_ptr<CPDF_Function>>& funcs, 193 CPDF_ColorSpace* pCS, 194 int alpha) { 195 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 196 CPDF_Array* pCoords = pDict->GetArrayFor("Coords"); 197 if (!pCoords) 198 return; 199 200 float start_x = pCoords->GetNumberAt(0); 201 float start_y = pCoords->GetNumberAt(1); 202 float start_r = pCoords->GetNumberAt(2); 203 float end_x = pCoords->GetNumberAt(3); 204 float end_y = pCoords->GetNumberAt(4); 205 float end_r = pCoords->GetNumberAt(5); 206 float t_min = 0; 207 float t_max = 1.0f; 208 CPDF_Array* pArray = pDict->GetArrayFor("Domain"); 209 if (pArray) { 210 t_min = pArray->GetNumberAt(0); 211 t_max = pArray->GetNumberAt(1); 212 } 213 bool bStartExtend = false; 214 bool bEndExtend = false; 215 pArray = pDict->GetArrayFor("Extend"); 216 if (pArray) { 217 bStartExtend = !!pArray->GetIntegerAt(0); 218 bEndExtend = !!pArray->GetIntegerAt(1); 219 } 220 uint32_t total_results = 221 std::max(CountOutputs(funcs), pCS->CountComponents()); 222 CFX_FixedBufGrow<float, 16> result_array(total_results); 223 float* pResults = result_array; 224 memset(pResults, 0, total_results * sizeof(float)); 225 uint32_t rgb_array[SHADING_STEPS]; 226 for (int i = 0; i < SHADING_STEPS; i++) { 227 float input = (t_max - t_min) * i / SHADING_STEPS + t_min; 228 int offset = 0; 229 for (const auto& func : funcs) { 230 if (func) { 231 int nresults; 232 if (func->Call(&input, 1, pResults + offset, &nresults)) 233 offset += nresults; 234 } 235 } 236 float R = 0.0f; 237 float G = 0.0f; 238 float B = 0.0f; 239 pCS->GetRGB(pResults, &R, &G, &B); 240 rgb_array[i] = 241 FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255), 242 FXSYS_round(G * 255), FXSYS_round(B * 255))); 243 } 244 float a = ((start_x - end_x) * (start_x - end_x)) + 245 ((start_y - end_y) * (start_y - end_y)) - 246 ((start_r - end_r) * (start_r - end_r)); 247 int width = pBitmap->GetWidth(); 248 int height = pBitmap->GetHeight(); 249 int pitch = pBitmap->GetPitch(); 250 bool bDecreasing = false; 251 if (start_r > end_r) { 252 int length = (int)sqrt((((start_x - end_x) * (start_x - end_x)) + 253 ((start_y - end_y) * (start_y - end_y)))); 254 if (length < start_r - end_r) { 255 bDecreasing = true; 256 } 257 } 258 CFX_Matrix matrix = pObject2Bitmap->GetInverse(); 259 for (int row = 0; row < height; row++) { 260 uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch); 261 for (int column = 0; column < width; column++) { 262 CFX_PointF pos = matrix.Transform( 263 CFX_PointF(static_cast<float>(column), static_cast<float>(row))); 264 float b = -2 * (((pos.x - start_x) * (end_x - start_x)) + 265 ((pos.y - start_y) * (end_y - start_y)) + 266 (start_r * (end_r - start_r))); 267 float c = ((pos.x - start_x) * (pos.x - start_x)) + 268 ((pos.y - start_y) * (pos.y - start_y)) - (start_r * start_r); 269 float s; 270 if (a == 0) { 271 s = -c / b; 272 } else { 273 float b2_4ac = (b * b) - 4 * (a * c); 274 if (b2_4ac < 0) { 275 continue; 276 } 277 float root = sqrt(b2_4ac); 278 float s1, s2; 279 if (a > 0) { 280 s1 = (-b - root) / (2 * a); 281 s2 = (-b + root) / (2 * a); 282 } else { 283 s2 = (-b - root) / (2 * a); 284 s1 = (-b + root) / (2 * a); 285 } 286 if (bDecreasing) { 287 if (s1 >= 0 || bStartExtend) { 288 s = s1; 289 } else { 290 s = s2; 291 } 292 } else { 293 if (s2 <= 1.0f || bEndExtend) { 294 s = s2; 295 } else { 296 s = s1; 297 } 298 } 299 if ((start_r + s * (end_r - start_r)) < 0) { 300 continue; 301 } 302 } 303 int index = (int32_t)(s * (SHADING_STEPS - 1)); 304 if (index < 0) { 305 if (!bStartExtend) { 306 continue; 307 } 308 index = 0; 309 } 310 if (index >= SHADING_STEPS) { 311 if (!bEndExtend) { 312 continue; 313 } 314 index = SHADING_STEPS - 1; 315 } 316 dib_buf[column] = rgb_array[index]; 317 } 318 } 319 } 320 321 void DrawFuncShading(const RetainPtr<CFX_DIBitmap>& pBitmap, 322 CFX_Matrix* pObject2Bitmap, 323 CPDF_Dictionary* pDict, 324 const std::vector<std::unique_ptr<CPDF_Function>>& funcs, 325 CPDF_ColorSpace* pCS, 326 int alpha) { 327 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 328 CPDF_Array* pDomain = pDict->GetArrayFor("Domain"); 329 float xmin = 0, ymin = 0, xmax = 1.0f, ymax = 1.0f; 330 if (pDomain) { 331 xmin = pDomain->GetNumberAt(0); 332 xmax = pDomain->GetNumberAt(1); 333 ymin = pDomain->GetNumberAt(2); 334 ymax = pDomain->GetNumberAt(3); 335 } 336 CFX_Matrix mtDomain2Target = pDict->GetMatrixFor("Matrix"); 337 CFX_Matrix matrix = pObject2Bitmap->GetInverse(); 338 matrix.Concat(mtDomain2Target.GetInverse()); 339 int width = pBitmap->GetWidth(); 340 int height = pBitmap->GetHeight(); 341 int pitch = pBitmap->GetPitch(); 342 uint32_t total_results = 343 std::max(CountOutputs(funcs), pCS->CountComponents()); 344 CFX_FixedBufGrow<float, 16> result_array(total_results); 345 float* pResults = result_array; 346 memset(pResults, 0, total_results * sizeof(float)); 347 for (int row = 0; row < height; row++) { 348 uint32_t* dib_buf = (uint32_t*)(pBitmap->GetBuffer() + row * pitch); 349 for (int column = 0; column < width; column++) { 350 CFX_PointF pos = matrix.Transform( 351 CFX_PointF(static_cast<float>(column), static_cast<float>(row))); 352 if (pos.x < xmin || pos.x > xmax || pos.y < ymin || pos.y > ymax) 353 continue; 354 355 float input[] = {pos.x, pos.y}; 356 int offset = 0; 357 for (const auto& func : funcs) { 358 if (func) { 359 int nresults; 360 if (func->Call(input, 2, pResults + offset, &nresults)) 361 offset += nresults; 362 } 363 } 364 365 float R = 0.0f; 366 float G = 0.0f; 367 float B = 0.0f; 368 pCS->GetRGB(pResults, &R, &G, &B); 369 dib_buf[column] = FXARGB_TODIB(FXARGB_MAKE( 370 alpha, (int32_t)(R * 255), (int32_t)(G * 255), (int32_t)(B * 255))); 371 } 372 } 373 } 374 375 bool GetScanlineIntersect(int y, 376 const CFX_PointF& first, 377 const CFX_PointF& second, 378 float* x) { 379 if (first.y == second.y) 380 return false; 381 382 if (first.y < second.y) { 383 if (y < first.y || y > second.y) 384 return false; 385 } else if (y < second.y || y > first.y) { 386 return false; 387 } 388 *x = first.x + ((second.x - first.x) * (y - first.y) / (second.y - first.y)); 389 return true; 390 } 391 392 void DrawGouraud(const RetainPtr<CFX_DIBitmap>& pBitmap, 393 int alpha, 394 CPDF_MeshVertex triangle[3]) { 395 float min_y = triangle[0].position.y; 396 float max_y = triangle[0].position.y; 397 for (int i = 1; i < 3; i++) { 398 min_y = std::min(min_y, triangle[i].position.y); 399 max_y = std::max(max_y, triangle[i].position.y); 400 } 401 if (min_y == max_y) 402 return; 403 404 int min_yi = std::max(static_cast<int>(floor(min_y)), 0); 405 int max_yi = static_cast<int>(ceil(max_y)); 406 407 if (max_yi >= pBitmap->GetHeight()) 408 max_yi = pBitmap->GetHeight() - 1; 409 410 for (int y = min_yi; y <= max_yi; y++) { 411 int nIntersects = 0; 412 float inter_x[3]; 413 float r[3]; 414 float g[3]; 415 float b[3]; 416 for (int i = 0; i < 3; i++) { 417 CPDF_MeshVertex& vertex1 = triangle[i]; 418 CPDF_MeshVertex& vertex2 = triangle[(i + 1) % 3]; 419 CFX_PointF& position1 = vertex1.position; 420 CFX_PointF& position2 = vertex2.position; 421 bool bIntersect = 422 GetScanlineIntersect(y, position1, position2, &inter_x[nIntersects]); 423 if (!bIntersect) 424 continue; 425 426 float y_dist = (y - position1.y) / (position2.y - position1.y); 427 r[nIntersects] = vertex1.r + ((vertex2.r - vertex1.r) * y_dist); 428 g[nIntersects] = vertex1.g + ((vertex2.g - vertex1.g) * y_dist); 429 b[nIntersects] = vertex1.b + ((vertex2.b - vertex1.b) * y_dist); 430 nIntersects++; 431 } 432 if (nIntersects != 2) 433 continue; 434 435 int min_x, max_x, start_index, end_index; 436 if (inter_x[0] < inter_x[1]) { 437 min_x = (int)floor(inter_x[0]); 438 max_x = (int)ceil(inter_x[1]); 439 start_index = 0; 440 end_index = 1; 441 } else { 442 min_x = (int)floor(inter_x[1]); 443 max_x = (int)ceil(inter_x[0]); 444 start_index = 1; 445 end_index = 0; 446 } 447 448 int start_x = std::max(min_x, 0); 449 int end_x = max_x; 450 if (end_x > pBitmap->GetWidth()) 451 end_x = pBitmap->GetWidth(); 452 453 uint8_t* dib_buf = 454 pBitmap->GetBuffer() + y * pBitmap->GetPitch() + start_x * 4; 455 float r_unit = (r[end_index] - r[start_index]) / (max_x - min_x); 456 float g_unit = (g[end_index] - g[start_index]) / (max_x - min_x); 457 float b_unit = (b[end_index] - b[start_index]) / (max_x - min_x); 458 float R = r[start_index] + (start_x - min_x) * r_unit; 459 float G = g[start_index] + (start_x - min_x) * g_unit; 460 float B = b[start_index] + (start_x - min_x) * b_unit; 461 for (int x = start_x; x < end_x; x++) { 462 R += r_unit; 463 G += g_unit; 464 B += b_unit; 465 FXARGB_SETDIB(dib_buf, 466 FXARGB_MAKE(alpha, (int32_t)(R * 255), (int32_t)(G * 255), 467 (int32_t)(B * 255))); 468 dib_buf += 4; 469 } 470 } 471 } 472 473 void DrawFreeGouraudShading( 474 const RetainPtr<CFX_DIBitmap>& pBitmap, 475 CFX_Matrix* pObject2Bitmap, 476 CPDF_Stream* pShadingStream, 477 const std::vector<std::unique_ptr<CPDF_Function>>& funcs, 478 CPDF_ColorSpace* pCS, 479 int alpha) { 480 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 481 482 CPDF_MeshStream stream(kFreeFormGouraudTriangleMeshShading, funcs, 483 pShadingStream, pCS); 484 if (!stream.Load()) 485 return; 486 487 CPDF_MeshVertex triangle[3]; 488 memset(triangle, 0, sizeof(triangle)); 489 490 while (!stream.BitStream()->IsEOF()) { 491 CPDF_MeshVertex vertex; 492 uint32_t flag; 493 if (!stream.ReadVertex(*pObject2Bitmap, &vertex, &flag)) 494 return; 495 496 if (flag == 0) { 497 triangle[0] = vertex; 498 for (int j = 1; j < 3; j++) { 499 uint32_t tflag; 500 if (!stream.ReadVertex(*pObject2Bitmap, &triangle[j], &tflag)) 501 return; 502 } 503 } else { 504 if (flag == 1) 505 triangle[0] = triangle[1]; 506 507 triangle[1] = triangle[2]; 508 triangle[2] = vertex; 509 } 510 DrawGouraud(pBitmap, alpha, triangle); 511 } 512 } 513 514 void DrawLatticeGouraudShading( 515 const RetainPtr<CFX_DIBitmap>& pBitmap, 516 CFX_Matrix* pObject2Bitmap, 517 CPDF_Stream* pShadingStream, 518 const std::vector<std::unique_ptr<CPDF_Function>>& funcs, 519 CPDF_ColorSpace* pCS, 520 int alpha) { 521 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 522 523 int row_verts = pShadingStream->GetDict()->GetIntegerFor("VerticesPerRow"); 524 if (row_verts < 2) 525 return; 526 527 CPDF_MeshStream stream(kLatticeFormGouraudTriangleMeshShading, funcs, 528 pShadingStream, pCS); 529 if (!stream.Load()) 530 return; 531 532 std::vector<CPDF_MeshVertex> vertices[2]; 533 vertices[0] = stream.ReadVertexRow(*pObject2Bitmap, row_verts); 534 if (vertices[0].empty()) 535 return; 536 537 int last_index = 0; 538 while (1) { 539 vertices[1 - last_index] = stream.ReadVertexRow(*pObject2Bitmap, row_verts); 540 if (vertices[1 - last_index].empty()) 541 return; 542 543 CPDF_MeshVertex triangle[3]; 544 for (int i = 1; i < row_verts; ++i) { 545 triangle[0] = vertices[last_index][i]; 546 triangle[1] = vertices[1 - last_index][i - 1]; 547 triangle[2] = vertices[last_index][i - 1]; 548 DrawGouraud(pBitmap, alpha, triangle); 549 triangle[2] = vertices[1 - last_index][i]; 550 DrawGouraud(pBitmap, alpha, triangle); 551 } 552 last_index = 1 - last_index; 553 } 554 } 555 556 struct Coon_BezierCoeff { 557 float a, b, c, d; 558 void FromPoints(float p0, float p1, float p2, float p3) { 559 a = -p0 + 3 * p1 - 3 * p2 + p3; 560 b = 3 * p0 - 6 * p1 + 3 * p2; 561 c = -3 * p0 + 3 * p1; 562 d = p0; 563 } 564 Coon_BezierCoeff first_half() { 565 Coon_BezierCoeff result; 566 result.a = a / 8; 567 result.b = b / 4; 568 result.c = c / 2; 569 result.d = d; 570 return result; 571 } 572 Coon_BezierCoeff second_half() { 573 Coon_BezierCoeff result; 574 result.a = a / 8; 575 result.b = 3 * a / 8 + b / 4; 576 result.c = 3 * a / 8 + b / 2 + c / 2; 577 result.d = a / 8 + b / 4 + c / 2 + d; 578 return result; 579 } 580 void GetPoints(float p[4]) { 581 p[0] = d; 582 p[1] = c / 3 + p[0]; 583 p[2] = b / 3 - p[0] + 2 * p[1]; 584 p[3] = a + p[0] - 3 * p[1] + 3 * p[2]; 585 } 586 void GetPointsReverse(float p[4]) { 587 p[3] = d; 588 p[2] = c / 3 + p[3]; 589 p[1] = b / 3 - p[3] + 2 * p[2]; 590 p[0] = a + p[3] - 3 * p[2] + 3 * p[1]; 591 } 592 void BezierInterpol(Coon_BezierCoeff& C1, 593 Coon_BezierCoeff& C2, 594 Coon_BezierCoeff& D1, 595 Coon_BezierCoeff& D2) { 596 a = (D1.a + D2.a) / 2; 597 b = (D1.b + D2.b) / 2; 598 c = (D1.c + D2.c) / 2 - (C1.a / 8 + C1.b / 4 + C1.c / 2) + 599 (C2.a / 8 + C2.b / 4) + (-C1.d + D2.d) / 2 - (C2.a + C2.b) / 2; 600 d = C1.a / 8 + C1.b / 4 + C1.c / 2 + C1.d; 601 } 602 float Distance() { 603 float dis = a + b + c; 604 return dis < 0 ? -dis : dis; 605 } 606 }; 607 608 struct Coon_Bezier { 609 Coon_BezierCoeff x, y; 610 void FromPoints(float x0, 611 float y0, 612 float x1, 613 float y1, 614 float x2, 615 float y2, 616 float x3, 617 float y3) { 618 x.FromPoints(x0, x1, x2, x3); 619 y.FromPoints(y0, y1, y2, y3); 620 } 621 622 Coon_Bezier first_half() { 623 Coon_Bezier result; 624 result.x = x.first_half(); 625 result.y = y.first_half(); 626 return result; 627 } 628 629 Coon_Bezier second_half() { 630 Coon_Bezier result; 631 result.x = x.second_half(); 632 result.y = y.second_half(); 633 return result; 634 } 635 636 void BezierInterpol(Coon_Bezier& C1, 637 Coon_Bezier& C2, 638 Coon_Bezier& D1, 639 Coon_Bezier& D2) { 640 x.BezierInterpol(C1.x, C2.x, D1.x, D2.x); 641 y.BezierInterpol(C1.y, C2.y, D1.y, D2.y); 642 } 643 644 void GetPoints(std::vector<FX_PATHPOINT>& pPoints, size_t start_idx) { 645 float p[4]; 646 int i; 647 x.GetPoints(p); 648 for (i = 0; i < 4; i++) 649 pPoints[start_idx + i].m_Point.x = p[i]; 650 651 y.GetPoints(p); 652 for (i = 0; i < 4; i++) 653 pPoints[start_idx + i].m_Point.y = p[i]; 654 } 655 656 void GetPointsReverse(std::vector<FX_PATHPOINT>& pPoints, size_t start_idx) { 657 float p[4]; 658 int i; 659 x.GetPointsReverse(p); 660 for (i = 0; i < 4; i++) 661 pPoints[i + start_idx].m_Point.x = p[i]; 662 663 y.GetPointsReverse(p); 664 for (i = 0; i < 4; i++) 665 pPoints[i + start_idx].m_Point.y = p[i]; 666 } 667 668 float Distance() { return x.Distance() + y.Distance(); } 669 }; 670 671 int Interpolate(int p1, int p2, int delta1, int delta2, bool* overflow) { 672 pdfium::base::CheckedNumeric<int> p = p2; 673 p -= p1; 674 p *= delta1; 675 p /= delta2; 676 p += p1; 677 if (!p.IsValid()) 678 *overflow = true; 679 return p.ValueOrDefault(0); 680 } 681 682 int BiInterpolImpl(int c0, 683 int c1, 684 int c2, 685 int c3, 686 int x, 687 int y, 688 int x_scale, 689 int y_scale, 690 bool* overflow) { 691 int x1 = Interpolate(c0, c3, x, x_scale, overflow); 692 int x2 = Interpolate(c1, c2, x, x_scale, overflow); 693 return Interpolate(x1, x2, y, y_scale, overflow); 694 } 695 696 struct Coon_Color { 697 Coon_Color() { memset(comp, 0, sizeof(int) * 3); } 698 int comp[3]; 699 700 // Returns true if successful, false if overflow detected. 701 bool BiInterpol(Coon_Color colors[4], 702 int x, 703 int y, 704 int x_scale, 705 int y_scale) { 706 bool overflow = false; 707 for (int i = 0; i < 3; i++) { 708 comp[i] = BiInterpolImpl(colors[0].comp[i], colors[1].comp[i], 709 colors[2].comp[i], colors[3].comp[i], x, y, 710 x_scale, y_scale, &overflow); 711 } 712 return !overflow; 713 } 714 715 int Distance(Coon_Color& o) { 716 return std::max({abs(comp[0] - o.comp[0]), abs(comp[1] - o.comp[1]), 717 abs(comp[2] - o.comp[2])}); 718 } 719 }; 720 721 #define COONCOLOR_THRESHOLD 4 722 struct CPDF_PatchDrawer { 723 Coon_Color patch_colors[4]; 724 int max_delta; 725 CFX_PathData path; 726 CFX_RenderDevice* pDevice; 727 int fill_mode; 728 int alpha; 729 void Draw(int x_scale, 730 int y_scale, 731 int left, 732 int bottom, 733 Coon_Bezier C1, 734 Coon_Bezier C2, 735 Coon_Bezier D1, 736 Coon_Bezier D2) { 737 bool bSmall = C1.Distance() < 2 && C2.Distance() < 2 && D1.Distance() < 2 && 738 D2.Distance() < 2; 739 Coon_Color div_colors[4]; 740 int d_bottom = 0; 741 int d_left = 0; 742 int d_top = 0; 743 int d_right = 0; 744 if (!div_colors[0].BiInterpol(patch_colors, left, bottom, x_scale, 745 y_scale)) { 746 return; 747 } 748 if (!bSmall) { 749 if (!div_colors[1].BiInterpol(patch_colors, left, bottom + 1, x_scale, 750 y_scale)) { 751 return; 752 } 753 if (!div_colors[2].BiInterpol(patch_colors, left + 1, bottom + 1, x_scale, 754 y_scale)) { 755 return; 756 } 757 if (!div_colors[3].BiInterpol(patch_colors, left + 1, bottom, x_scale, 758 y_scale)) { 759 return; 760 } 761 d_bottom = div_colors[3].Distance(div_colors[0]); 762 d_left = div_colors[1].Distance(div_colors[0]); 763 d_top = div_colors[1].Distance(div_colors[2]); 764 d_right = div_colors[2].Distance(div_colors[3]); 765 } 766 767 if (bSmall || 768 (d_bottom < COONCOLOR_THRESHOLD && d_left < COONCOLOR_THRESHOLD && 769 d_top < COONCOLOR_THRESHOLD && d_right < COONCOLOR_THRESHOLD)) { 770 std::vector<FX_PATHPOINT>& pPoints = path.GetPoints(); 771 C1.GetPoints(pPoints, 0); 772 D2.GetPoints(pPoints, 3); 773 C2.GetPointsReverse(pPoints, 6); 774 D1.GetPointsReverse(pPoints, 9); 775 int fillFlags = FXFILL_WINDING | FXFILL_FULLCOVER; 776 if (fill_mode & RENDER_NOPATHSMOOTH) { 777 fillFlags |= FXFILL_NOPATHSMOOTH; 778 } 779 pDevice->DrawPath( 780 &path, nullptr, nullptr, 781 FXARGB_MAKE(alpha, div_colors[0].comp[0], div_colors[0].comp[1], 782 div_colors[0].comp[2]), 783 0, fillFlags); 784 } else { 785 if (d_bottom < COONCOLOR_THRESHOLD && d_top < COONCOLOR_THRESHOLD) { 786 Coon_Bezier m1; 787 m1.BezierInterpol(D1, D2, C1, C2); 788 y_scale *= 2; 789 bottom *= 2; 790 Draw(x_scale, y_scale, left, bottom, C1, m1, D1.first_half(), 791 D2.first_half()); 792 Draw(x_scale, y_scale, left, bottom + 1, m1, C2, D1.second_half(), 793 D2.second_half()); 794 } else if (d_left < COONCOLOR_THRESHOLD && 795 d_right < COONCOLOR_THRESHOLD) { 796 Coon_Bezier m2; 797 m2.BezierInterpol(C1, C2, D1, D2); 798 x_scale *= 2; 799 left *= 2; 800 Draw(x_scale, y_scale, left, bottom, C1.first_half(), C2.first_half(), 801 D1, m2); 802 Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(), 803 C2.second_half(), m2, D2); 804 } else { 805 Coon_Bezier m1, m2; 806 m1.BezierInterpol(D1, D2, C1, C2); 807 m2.BezierInterpol(C1, C2, D1, D2); 808 Coon_Bezier m1f = m1.first_half(); 809 Coon_Bezier m1s = m1.second_half(); 810 Coon_Bezier m2f = m2.first_half(); 811 Coon_Bezier m2s = m2.second_half(); 812 x_scale *= 2; 813 y_scale *= 2; 814 left *= 2; 815 bottom *= 2; 816 Draw(x_scale, y_scale, left, bottom, C1.first_half(), m1f, 817 D1.first_half(), m2f); 818 Draw(x_scale, y_scale, left, bottom + 1, m1f, C2.first_half(), 819 D1.second_half(), m2s); 820 Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(), m1s, m2f, 821 D2.first_half()); 822 Draw(x_scale, y_scale, left + 1, bottom + 1, m1s, C2.second_half(), m2s, 823 D2.second_half()); 824 } 825 } 826 } 827 }; 828 829 void DrawCoonPatchMeshes( 830 ShadingType type, 831 const RetainPtr<CFX_DIBitmap>& pBitmap, 832 CFX_Matrix* pObject2Bitmap, 833 CPDF_Stream* pShadingStream, 834 const std::vector<std::unique_ptr<CPDF_Function>>& funcs, 835 CPDF_ColorSpace* pCS, 836 int fill_mode, 837 int alpha) { 838 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 839 ASSERT(type == kCoonsPatchMeshShading || 840 type == kTensorProductPatchMeshShading); 841 842 CFX_DefaultRenderDevice device; 843 device.Attach(pBitmap, false, nullptr, false); 844 CPDF_MeshStream stream(type, funcs, pShadingStream, pCS); 845 if (!stream.Load()) 846 return; 847 848 CPDF_PatchDrawer patch; 849 patch.alpha = alpha; 850 patch.pDevice = &device; 851 patch.fill_mode = fill_mode; 852 853 for (int i = 0; i < 13; i++) { 854 patch.path.AppendPoint( 855 CFX_PointF(), i == 0 ? FXPT_TYPE::MoveTo : FXPT_TYPE::BezierTo, false); 856 } 857 858 CFX_PointF coords[16]; 859 int point_count = type == kTensorProductPatchMeshShading ? 16 : 12; 860 while (!stream.BitStream()->IsEOF()) { 861 if (!stream.CanReadFlag()) 862 break; 863 uint32_t flag = stream.ReadFlag(); 864 int iStartPoint = 0, iStartColor = 0, i = 0; 865 if (flag) { 866 iStartPoint = 4; 867 iStartColor = 2; 868 CFX_PointF tempCoords[4]; 869 for (i = 0; i < 4; i++) { 870 tempCoords[i] = coords[(flag * 3 + i) % 12]; 871 } 872 memcpy(coords, tempCoords, sizeof(tempCoords)); 873 Coon_Color tempColors[2]; 874 tempColors[0] = patch.patch_colors[flag]; 875 tempColors[1] = patch.patch_colors[(flag + 1) % 4]; 876 memcpy(patch.patch_colors, tempColors, sizeof(Coon_Color) * 2); 877 } 878 for (i = iStartPoint; i < point_count; i++) { 879 if (!stream.CanReadCoords()) 880 break; 881 coords[i] = pObject2Bitmap->Transform(stream.ReadCoords()); 882 } 883 884 for (i = iStartColor; i < 4; i++) { 885 if (!stream.CanReadColor()) 886 break; 887 888 float r; 889 float g; 890 float b; 891 std::tie(r, g, b) = stream.ReadColor(); 892 893 patch.patch_colors[i].comp[0] = (int32_t)(r * 255); 894 patch.patch_colors[i].comp[1] = (int32_t)(g * 255); 895 patch.patch_colors[i].comp[2] = (int32_t)(b * 255); 896 } 897 CFX_FloatRect bbox = CFX_FloatRect::GetBBox(coords, point_count); 898 if (bbox.right <= 0 || bbox.left >= (float)pBitmap->GetWidth() || 899 bbox.top <= 0 || bbox.bottom >= (float)pBitmap->GetHeight()) { 900 continue; 901 } 902 Coon_Bezier C1, C2, D1, D2; 903 C1.FromPoints(coords[0].x, coords[0].y, coords[11].x, coords[11].y, 904 coords[10].x, coords[10].y, coords[9].x, coords[9].y); 905 C2.FromPoints(coords[3].x, coords[3].y, coords[4].x, coords[4].y, 906 coords[5].x, coords[5].y, coords[6].x, coords[6].y); 907 D1.FromPoints(coords[0].x, coords[0].y, coords[1].x, coords[1].y, 908 coords[2].x, coords[2].y, coords[3].x, coords[3].y); 909 D2.FromPoints(coords[9].x, coords[9].y, coords[8].x, coords[8].y, 910 coords[7].x, coords[7].y, coords[6].x, coords[6].y); 911 patch.Draw(1, 1, 0, 0, C1, C2, D1, D2); 912 } 913 } 914 915 RetainPtr<CFX_DIBitmap> DrawPatternBitmap(CPDF_Document* pDoc, 916 CPDF_PageRenderCache* pCache, 917 CPDF_TilingPattern* pPattern, 918 const CFX_Matrix* pObject2Device, 919 int width, 920 int height, 921 int flags) { 922 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); 923 if (!pBitmap->Create(width, height, 924 pPattern->colored() ? FXDIB_Argb : FXDIB_8bppMask)) { 925 return nullptr; 926 } 927 CFX_DefaultRenderDevice bitmap_device; 928 bitmap_device.Attach(pBitmap, false, nullptr, false); 929 pBitmap->Clear(0); 930 CFX_FloatRect cell_bbox = 931 pPattern->pattern_to_form()->TransformRect(pPattern->bbox()); 932 cell_bbox = pObject2Device->TransformRect(cell_bbox); 933 CFX_FloatRect bitmap_rect(0.0f, 0.0f, (float)width, (float)height); 934 CFX_Matrix mtAdjust; 935 mtAdjust.MatchRect(bitmap_rect, cell_bbox); 936 937 CFX_Matrix mtPattern2Bitmap = *pObject2Device; 938 mtPattern2Bitmap.Concat(mtAdjust); 939 CPDF_RenderOptions options; 940 if (!pPattern->colored()) 941 options.SetColorMode(CPDF_RenderOptions::kAlpha); 942 943 flags |= RENDER_FORCE_HALFTONE; 944 options.SetFlags(flags); 945 946 CPDF_RenderContext context(pDoc, pCache); 947 context.AppendLayer(pPattern->form(), &mtPattern2Bitmap); 948 context.Render(&bitmap_device, &options, nullptr); 949 #if defined _SKIA_SUPPORT_PATHS_ 950 bitmap_device.Flush(true); 951 pBitmap->UnPreMultiply(); 952 #endif 953 return pBitmap; 954 } 955 956 bool IsAvailableMatrix(const CFX_Matrix& matrix) { 957 if (matrix.a == 0 || matrix.d == 0) 958 return matrix.b != 0 && matrix.c != 0; 959 960 if (matrix.b == 0 || matrix.c == 0) 961 return matrix.a != 0 && matrix.d != 0; 962 963 return true; 964 } 965 966 bool MissingFillColor(const CPDF_ColorState* pColorState) { 967 return !pColorState->HasRef() || pColorState->GetFillColor()->IsNull(); 968 } 969 970 bool MissingStrokeColor(const CPDF_ColorState* pColorState) { 971 return !pColorState->HasRef() || pColorState->GetStrokeColor()->IsNull(); 972 } 973 974 bool Type3CharMissingFillColor(const CPDF_Type3Char* pChar, 975 const CPDF_ColorState* pColorState) { 976 return pChar && (!pChar->colored() || 977 (pChar->colored() && MissingFillColor(pColorState))); 978 } 979 980 bool Type3CharMissingStrokeColor(const CPDF_Type3Char* pChar, 981 const CPDF_ColorState* pColorState) { 982 return pChar && (!pChar->colored() || 983 (pChar->colored() && MissingStrokeColor(pColorState))); 984 } 985 986 } // namespace 987 988 // static 989 int CPDF_RenderStatus::s_CurrentRecursionDepth = 0; 990 991 CPDF_RenderStatus::CPDF_RenderStatus() 992 : m_pFormResource(nullptr), 993 m_pPageResource(nullptr), 994 m_pContext(nullptr), 995 m_bStopped(false), 996 m_pDevice(nullptr), 997 m_pCurObj(nullptr), 998 m_pStopObj(nullptr), 999 m_bPrint(false), 1000 m_iTransparency(0), 1001 m_bDropObjects(false), 1002 m_bStdCS(false), 1003 m_GroupFamily(0), 1004 m_bLoadMask(false), 1005 m_pType3Char(nullptr), 1006 m_T3FillColor(0), 1007 m_curBlend(FXDIB_BLEND_NORMAL) {} 1008 1009 CPDF_RenderStatus::~CPDF_RenderStatus() {} 1010 1011 bool CPDF_RenderStatus::Initialize(CPDF_RenderContext* pContext, 1012 CFX_RenderDevice* pDevice, 1013 const CFX_Matrix* pDeviceMatrix, 1014 const CPDF_PageObject* pStopObj, 1015 const CPDF_RenderStatus* pParentState, 1016 const CPDF_GraphicStates* pInitialStates, 1017 const CPDF_RenderOptions* pOptions, 1018 int transparency, 1019 bool bDropObjects, 1020 CPDF_Dictionary* pFormResource, 1021 bool bStdCS, 1022 CPDF_Type3Char* pType3Char, 1023 FX_ARGB fill_color, 1024 uint32_t GroupFamily, 1025 bool bLoadMask) { 1026 m_pContext = pContext; 1027 m_pDevice = pDevice; 1028 m_bPrint = m_pDevice->GetDeviceClass() != FXDC_DISPLAY; 1029 if (pDeviceMatrix) { 1030 m_DeviceMatrix = *pDeviceMatrix; 1031 } 1032 m_pStopObj = pStopObj; 1033 if (pOptions) { 1034 m_Options = *pOptions; 1035 } 1036 m_bDropObjects = bDropObjects; 1037 m_bStdCS = bStdCS; 1038 m_T3FillColor = fill_color; 1039 m_pType3Char = pType3Char; 1040 m_GroupFamily = GroupFamily; 1041 m_bLoadMask = bLoadMask; 1042 m_pFormResource = pFormResource; 1043 m_pPageResource = m_pContext->GetPageResources(); 1044 if (pInitialStates && !m_pType3Char) { 1045 m_InitialStates.CopyStates(*pInitialStates); 1046 if (pParentState) { 1047 if (!m_InitialStates.m_ColorState.HasFillColor()) { 1048 m_InitialStates.m_ColorState.SetFillRGB( 1049 pParentState->m_InitialStates.m_ColorState.GetFillRGB()); 1050 m_InitialStates.m_ColorState.GetMutableFillColor()->Copy( 1051 pParentState->m_InitialStates.m_ColorState.GetFillColor()); 1052 } 1053 if (!m_InitialStates.m_ColorState.HasStrokeColor()) { 1054 m_InitialStates.m_ColorState.SetStrokeRGB( 1055 pParentState->m_InitialStates.m_ColorState.GetFillRGB()); 1056 m_InitialStates.m_ColorState.GetMutableStrokeColor()->Copy( 1057 pParentState->m_InitialStates.m_ColorState.GetStrokeColor()); 1058 } 1059 } 1060 } else { 1061 m_InitialStates.DefaultStates(); 1062 } 1063 m_pImageRenderer.reset(); 1064 m_iTransparency = transparency; 1065 return true; 1066 } 1067 1068 void CPDF_RenderStatus::RenderObjectList( 1069 const CPDF_PageObjectHolder* pObjectHolder, 1070 const CFX_Matrix* pObj2Device) { 1071 #if defined _SKIA_SUPPORT_ 1072 DebugVerifyDeviceIsPreMultiplied(); 1073 #endif 1074 CFX_FloatRect clip_rect = pObj2Device->GetInverse().TransformRect( 1075 CFX_FloatRect(m_pDevice->GetClipBox())); 1076 for (const auto& pCurObj : *pObjectHolder->GetPageObjectList()) { 1077 if (pCurObj.get() == m_pStopObj) { 1078 m_bStopped = true; 1079 return; 1080 } 1081 if (!pCurObj) 1082 continue; 1083 1084 if (pCurObj->m_Left > clip_rect.right || 1085 pCurObj->m_Right < clip_rect.left || 1086 pCurObj->m_Bottom > clip_rect.top || 1087 pCurObj->m_Top < clip_rect.bottom) { 1088 continue; 1089 } 1090 RenderSingleObject(pCurObj.get(), pObj2Device); 1091 if (m_bStopped) 1092 return; 1093 } 1094 #if defined _SKIA_SUPPORT_ 1095 DebugVerifyDeviceIsPreMultiplied(); 1096 #endif 1097 } 1098 1099 void CPDF_RenderStatus::RenderSingleObject(CPDF_PageObject* pObj, 1100 const CFX_Matrix* pObj2Device) { 1101 #if defined _SKIA_SUPPORT_ 1102 DebugVerifyDeviceIsPreMultiplied(); 1103 #endif 1104 AutoRestorer<int> restorer(&s_CurrentRecursionDepth); 1105 if (++s_CurrentRecursionDepth > kRenderMaxRecursionDepth) { 1106 return; 1107 } 1108 m_pCurObj = pObj; 1109 if (m_Options.GetOCContext() && pObj->m_ContentMark.HasRef()) { 1110 if (!m_Options.GetOCContext()->CheckObjectVisible(pObj)) { 1111 return; 1112 } 1113 } 1114 ProcessClipPath(pObj->m_ClipPath, pObj2Device); 1115 if (ProcessTransparency(pObj, pObj2Device)) { 1116 return; 1117 } 1118 ProcessObjectNoClip(pObj, pObj2Device); 1119 #if defined _SKIA_SUPPORT_ 1120 DebugVerifyDeviceIsPreMultiplied(); 1121 #endif 1122 } 1123 1124 bool CPDF_RenderStatus::ContinueSingleObject(CPDF_PageObject* pObj, 1125 const CFX_Matrix* pObj2Device, 1126 IFX_PauseIndicator* pPause) { 1127 if (m_pImageRenderer) { 1128 if (m_pImageRenderer->Continue(pPause)) 1129 return true; 1130 1131 if (!m_pImageRenderer->GetResult()) 1132 DrawObjWithBackground(pObj, pObj2Device); 1133 m_pImageRenderer.reset(); 1134 return false; 1135 } 1136 1137 m_pCurObj = pObj; 1138 if (m_Options.GetOCContext() && pObj->m_ContentMark.HasRef() && 1139 !m_Options.GetOCContext()->CheckObjectVisible(pObj)) { 1140 return false; 1141 } 1142 1143 ProcessClipPath(pObj->m_ClipPath, pObj2Device); 1144 if (ProcessTransparency(pObj, pObj2Device)) 1145 return false; 1146 1147 if (!pObj->IsImage()) { 1148 ProcessObjectNoClip(pObj, pObj2Device); 1149 return false; 1150 } 1151 1152 m_pImageRenderer = pdfium::MakeUnique<CPDF_ImageRenderer>(); 1153 if (!m_pImageRenderer->Start(this, pObj->AsImage(), pObj2Device, false, 1154 FXDIB_BLEND_NORMAL)) { 1155 if (!m_pImageRenderer->GetResult()) 1156 DrawObjWithBackground(pObj, pObj2Device); 1157 m_pImageRenderer.reset(); 1158 return false; 1159 } 1160 return ContinueSingleObject(pObj, pObj2Device, pPause); 1161 } 1162 1163 bool CPDF_RenderStatus::GetObjectClippedRect(const CPDF_PageObject* pObj, 1164 const CFX_Matrix* pObj2Device, 1165 bool bLogical, 1166 FX_RECT& rect) const { 1167 rect = pObj->GetBBox(pObj2Device); 1168 FX_RECT rtClip = m_pDevice->GetClipBox(); 1169 if (!bLogical) { 1170 CFX_Matrix dCTM = m_pDevice->GetCTM(); 1171 float a = fabs(dCTM.a); 1172 float d = fabs(dCTM.d); 1173 if (a != 1.0f || d != 1.0f) { 1174 rect.right = rect.left + (int32_t)ceil((float)rect.Width() * a); 1175 rect.bottom = rect.top + (int32_t)ceil((float)rect.Height() * d); 1176 rtClip.right = rtClip.left + (int32_t)ceil((float)rtClip.Width() * a); 1177 rtClip.bottom = rtClip.top + (int32_t)ceil((float)rtClip.Height() * d); 1178 } 1179 } 1180 rect.Intersect(rtClip); 1181 return rect.IsEmpty(); 1182 } 1183 1184 void CPDF_RenderStatus::ProcessObjectNoClip(CPDF_PageObject* pObj, 1185 const CFX_Matrix* pObj2Device) { 1186 #if defined _SKIA_SUPPORT_ 1187 DebugVerifyDeviceIsPreMultiplied(); 1188 #endif 1189 bool bRet = false; 1190 switch (pObj->GetType()) { 1191 case CPDF_PageObject::TEXT: 1192 bRet = ProcessText(pObj->AsText(), pObj2Device, nullptr); 1193 break; 1194 case CPDF_PageObject::PATH: 1195 bRet = ProcessPath(pObj->AsPath(), pObj2Device); 1196 break; 1197 case CPDF_PageObject::IMAGE: 1198 bRet = ProcessImage(pObj->AsImage(), pObj2Device); 1199 break; 1200 case CPDF_PageObject::SHADING: 1201 ProcessShading(pObj->AsShading(), pObj2Device); 1202 return; 1203 case CPDF_PageObject::FORM: 1204 bRet = ProcessForm(pObj->AsForm(), pObj2Device); 1205 break; 1206 } 1207 if (!bRet) 1208 DrawObjWithBackground(pObj, pObj2Device); 1209 #if defined _SKIA_SUPPORT_ 1210 DebugVerifyDeviceIsPreMultiplied(); 1211 #endif 1212 } 1213 1214 bool CPDF_RenderStatus::DrawObjWithBlend(CPDF_PageObject* pObj, 1215 const CFX_Matrix* pObj2Device) { 1216 bool bRet = false; 1217 switch (pObj->GetType()) { 1218 case CPDF_PageObject::PATH: 1219 bRet = ProcessPath(pObj->AsPath(), pObj2Device); 1220 break; 1221 case CPDF_PageObject::IMAGE: 1222 bRet = ProcessImage(pObj->AsImage(), pObj2Device); 1223 break; 1224 case CPDF_PageObject::FORM: 1225 bRet = ProcessForm(pObj->AsForm(), pObj2Device); 1226 break; 1227 default: 1228 break; 1229 } 1230 return bRet; 1231 } 1232 1233 void CPDF_RenderStatus::GetScaledMatrix(CFX_Matrix& matrix) const { 1234 CFX_Matrix dCTM = m_pDevice->GetCTM(); 1235 matrix.a *= fabs(dCTM.a); 1236 matrix.d *= fabs(dCTM.d); 1237 } 1238 1239 void CPDF_RenderStatus::DrawObjWithBackground(CPDF_PageObject* pObj, 1240 const CFX_Matrix* pObj2Device) { 1241 FX_RECT rect; 1242 if (GetObjectClippedRect(pObj, pObj2Device, false, rect)) { 1243 return; 1244 } 1245 int res = 300; 1246 if (pObj->IsImage() && 1247 m_pDevice->GetDeviceCaps(FXDC_DEVICE_CLASS) == FXDC_PRINTER) { 1248 res = 0; 1249 } 1250 CPDF_ScaledRenderBuffer buffer; 1251 if (!buffer.Initialize(m_pContext.Get(), m_pDevice, rect, pObj, &m_Options, 1252 res)) { 1253 return; 1254 } 1255 CFX_Matrix matrix = *pObj2Device; 1256 matrix.Concat(*buffer.GetMatrix()); 1257 GetScaledMatrix(matrix); 1258 CPDF_Dictionary* pFormResource = nullptr; 1259 const CPDF_FormObject* pFormObj = pObj->AsForm(); 1260 if (pFormObj) { 1261 const auto& pFormDict = pFormObj->form()->m_pFormDict; 1262 if (pFormDict) 1263 pFormResource = pFormDict->GetDictFor("Resources"); 1264 } 1265 CPDF_RenderStatus status; 1266 status.Initialize(m_pContext.Get(), buffer.GetDevice(), buffer.GetMatrix(), 1267 nullptr, nullptr, nullptr, &m_Options, m_iTransparency, 1268 m_bDropObjects, pFormResource); 1269 status.RenderSingleObject(pObj, &matrix); 1270 buffer.OutputToDevice(); 1271 } 1272 1273 bool CPDF_RenderStatus::ProcessForm(const CPDF_FormObject* pFormObj, 1274 const CFX_Matrix* pObj2Device) { 1275 #if defined _SKIA_SUPPORT_ 1276 DebugVerifyDeviceIsPreMultiplied(); 1277 #endif 1278 CPDF_Dictionary* pOC = pFormObj->form()->m_pFormDict->GetDictFor("OC"); 1279 if (pOC && m_Options.GetOCContext() && 1280 !m_Options.GetOCContext()->CheckOCGVisible(pOC)) { 1281 return true; 1282 } 1283 CFX_Matrix matrix = pFormObj->form_matrix(); 1284 matrix.Concat(*pObj2Device); 1285 const auto& pFormDict = pFormObj->form()->m_pFormDict; 1286 CPDF_Dictionary* pResources = 1287 pFormDict ? pFormDict->GetDictFor("Resources") : nullptr; 1288 CPDF_RenderStatus status; 1289 status.Initialize(m_pContext.Get(), m_pDevice, nullptr, m_pStopObj, this, 1290 pFormObj, &m_Options, m_iTransparency, m_bDropObjects, 1291 pResources, false); 1292 status.m_curBlend = m_curBlend; 1293 { 1294 CFX_RenderDevice::StateRestorer restorer(m_pDevice); 1295 status.RenderObjectList(pFormObj->form(), &matrix); 1296 m_bStopped = status.m_bStopped; 1297 } 1298 #if defined _SKIA_SUPPORT_ 1299 DebugVerifyDeviceIsPreMultiplied(); 1300 #endif 1301 return true; 1302 } 1303 1304 bool CPDF_RenderStatus::ProcessPath(CPDF_PathObject* pPathObj, 1305 const CFX_Matrix* pObj2Device) { 1306 int FillType = pPathObj->m_FillType; 1307 bool bStroke = pPathObj->m_bStroke; 1308 ProcessPathPattern(pPathObj, pObj2Device, FillType, bStroke); 1309 if (FillType == 0 && !bStroke) 1310 return true; 1311 1312 uint32_t fill_argb = FillType ? GetFillArgb(pPathObj) : 0; 1313 uint32_t stroke_argb = bStroke ? GetStrokeArgb(pPathObj) : 0; 1314 CFX_Matrix path_matrix = pPathObj->m_Matrix; 1315 path_matrix.Concat(*pObj2Device); 1316 if (!IsAvailableMatrix(path_matrix)) 1317 return true; 1318 1319 if (FillType && (m_Options.HasFlag(RENDER_RECT_AA))) 1320 FillType |= FXFILL_RECT_AA; 1321 if (m_Options.HasFlag(RENDER_FILL_FULLCOVER)) 1322 FillType |= FXFILL_FULLCOVER; 1323 if (m_Options.HasFlag(RENDER_NOPATHSMOOTH)) 1324 FillType |= FXFILL_NOPATHSMOOTH; 1325 if (bStroke) 1326 FillType |= FX_FILL_STROKE; 1327 1328 const CPDF_PageObject* pPageObj = 1329 static_cast<const CPDF_PageObject*>(pPathObj); 1330 if (pPageObj->m_GeneralState.GetStrokeAdjust()) 1331 FillType |= FX_STROKE_ADJUST; 1332 if (m_pType3Char) 1333 FillType |= FX_FILL_TEXT_MODE; 1334 1335 CFX_GraphState graphState = pPathObj->m_GraphState; 1336 if (m_Options.HasFlag(RENDER_THINLINE)) 1337 graphState.SetLineWidth(0); 1338 return m_pDevice->DrawPathWithBlend( 1339 pPathObj->m_Path.GetObject(), &path_matrix, graphState.GetObject(), 1340 fill_argb, stroke_argb, FillType, m_curBlend); 1341 } 1342 1343 RetainPtr<CPDF_TransferFunc> CPDF_RenderStatus::GetTransferFunc( 1344 CPDF_Object* pObj) const { 1345 ASSERT(pObj); 1346 CPDF_DocRenderData* pDocCache = m_pContext->GetDocument()->GetRenderData(); 1347 return pDocCache ? pDocCache->GetTransferFunc(pObj) : nullptr; 1348 } 1349 1350 FX_ARGB CPDF_RenderStatus::GetFillArgb(CPDF_PageObject* pObj, 1351 bool bType3) const { 1352 const CPDF_ColorState* pColorState = &pObj->m_ColorState; 1353 if (!bType3 && Type3CharMissingFillColor(m_pType3Char.Get(), pColorState)) 1354 return m_T3FillColor; 1355 1356 if (MissingFillColor(pColorState)) 1357 pColorState = &m_InitialStates.m_ColorState; 1358 1359 FX_COLORREF rgb = pColorState->GetFillRGB(); 1360 if (rgb == (uint32_t)-1) 1361 return 0; 1362 1363 int32_t alpha = 1364 static_cast<int32_t>((pObj->m_GeneralState.GetFillAlpha() * 255)); 1365 if (pObj->m_GeneralState.GetTR()) { 1366 if (!pObj->m_GeneralState.GetTransferFunc()) { 1367 pObj->m_GeneralState.SetTransferFunc( 1368 GetTransferFunc(pObj->m_GeneralState.GetTR())); 1369 } 1370 if (pObj->m_GeneralState.GetTransferFunc()) 1371 rgb = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(rgb); 1372 } 1373 return m_Options.TranslateColor(ArgbEncode(alpha, rgb)); 1374 } 1375 1376 FX_ARGB CPDF_RenderStatus::GetStrokeArgb(CPDF_PageObject* pObj) const { 1377 const CPDF_ColorState* pColorState = &pObj->m_ColorState; 1378 if (Type3CharMissingStrokeColor(m_pType3Char.Get(), pColorState)) 1379 return m_T3FillColor; 1380 1381 if (MissingStrokeColor(pColorState)) 1382 pColorState = &m_InitialStates.m_ColorState; 1383 1384 FX_COLORREF rgb = pColorState->GetStrokeRGB(); 1385 if (rgb == (uint32_t)-1) 1386 return 0; 1387 1388 int32_t alpha = static_cast<int32_t>(pObj->m_GeneralState.GetStrokeAlpha() * 1389 255); // not rounded. 1390 if (pObj->m_GeneralState.GetTR()) { 1391 if (!pObj->m_GeneralState.GetTransferFunc()) { 1392 pObj->m_GeneralState.SetTransferFunc( 1393 GetTransferFunc(pObj->m_GeneralState.GetTR())); 1394 } 1395 if (pObj->m_GeneralState.GetTransferFunc()) 1396 rgb = pObj->m_GeneralState.GetTransferFunc()->TranslateColor(rgb); 1397 } 1398 return m_Options.TranslateColor(ArgbEncode(alpha, rgb)); 1399 } 1400 1401 void CPDF_RenderStatus::ProcessClipPath(const CPDF_ClipPath& ClipPath, 1402 const CFX_Matrix* pObj2Device) { 1403 if (!ClipPath.HasRef()) { 1404 if (m_LastClipPath.HasRef()) { 1405 m_pDevice->RestoreState(true); 1406 m_LastClipPath.SetNull(); 1407 } 1408 return; 1409 } 1410 if (m_LastClipPath == ClipPath) 1411 return; 1412 1413 m_LastClipPath = ClipPath; 1414 m_pDevice->RestoreState(true); 1415 for (size_t i = 0; i < ClipPath.GetPathCount(); ++i) { 1416 const CFX_PathData* pPathData = ClipPath.GetPath(i).GetObject(); 1417 if (!pPathData) 1418 continue; 1419 1420 if (pPathData->GetPoints().empty()) { 1421 CFX_PathData EmptyPath; 1422 EmptyPath.AppendRect(-1, -1, 0, 0); 1423 m_pDevice->SetClip_PathFill(&EmptyPath, nullptr, FXFILL_WINDING); 1424 } else { 1425 m_pDevice->SetClip_PathFill(pPathData, pObj2Device, 1426 ClipPath.GetClipType(i)); 1427 } 1428 } 1429 1430 if (ClipPath.GetTextCount() == 0) 1431 return; 1432 1433 if (m_pDevice->GetDeviceClass() == FXDC_DISPLAY && 1434 !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)) { 1435 return; 1436 } 1437 1438 std::unique_ptr<CFX_PathData> pTextClippingPath; 1439 for (size_t i = 0; i < ClipPath.GetTextCount(); ++i) { 1440 CPDF_TextObject* pText = ClipPath.GetText(i); 1441 if (pText) { 1442 if (!pTextClippingPath) 1443 pTextClippingPath = pdfium::MakeUnique<CFX_PathData>(); 1444 ProcessText(pText, pObj2Device, pTextClippingPath.get()); 1445 continue; 1446 } 1447 1448 if (!pTextClippingPath) 1449 continue; 1450 1451 int fill_mode = FXFILL_WINDING; 1452 if (m_Options.HasFlag(RENDER_NOTEXTSMOOTH)) 1453 fill_mode |= FXFILL_NOPATHSMOOTH; 1454 m_pDevice->SetClip_PathFill(pTextClippingPath.get(), nullptr, fill_mode); 1455 pTextClippingPath.reset(); 1456 } 1457 } 1458 1459 bool CPDF_RenderStatus::SelectClipPath(const CPDF_PathObject* pPathObj, 1460 const CFX_Matrix* pObj2Device, 1461 bool bStroke) { 1462 CFX_Matrix path_matrix = pPathObj->m_Matrix; 1463 path_matrix.Concat(*pObj2Device); 1464 if (bStroke) { 1465 CFX_GraphState graphState = pPathObj->m_GraphState; 1466 if (m_Options.HasFlag(RENDER_THINLINE)) 1467 graphState.SetLineWidth(0); 1468 return m_pDevice->SetClip_PathStroke(pPathObj->m_Path.GetObject(), 1469 &path_matrix, graphState.GetObject()); 1470 } 1471 int fill_mode = pPathObj->m_FillType; 1472 if (m_Options.HasFlag(RENDER_NOPATHSMOOTH)) { 1473 fill_mode |= FXFILL_NOPATHSMOOTH; 1474 } 1475 return m_pDevice->SetClip_PathFill(pPathObj->m_Path.GetObject(), &path_matrix, 1476 fill_mode); 1477 } 1478 1479 bool CPDF_RenderStatus::ProcessTransparency(CPDF_PageObject* pPageObj, 1480 const CFX_Matrix* pObj2Device) { 1481 #if defined _SKIA_SUPPORT_ 1482 DebugVerifyDeviceIsPreMultiplied(); 1483 #endif 1484 int blend_type = pPageObj->m_GeneralState.GetBlendType(); 1485 if (blend_type == FXDIB_BLEND_UNSUPPORTED) 1486 return true; 1487 1488 CPDF_Dictionary* pSMaskDict = 1489 ToDictionary(pPageObj->m_GeneralState.GetSoftMask()); 1490 if (pSMaskDict) { 1491 if (pPageObj->IsImage() && 1492 pPageObj->AsImage()->GetImage()->GetDict()->KeyExist("SMask")) { 1493 pSMaskDict = nullptr; 1494 } 1495 } 1496 CPDF_Dictionary* pFormResource = nullptr; 1497 float group_alpha = 1.0f; 1498 int iTransparency = m_iTransparency; 1499 bool bGroupTransparent = false; 1500 const CPDF_FormObject* pFormObj = pPageObj->AsForm(); 1501 if (pFormObj) { 1502 group_alpha = pFormObj->m_GeneralState.GetFillAlpha(); 1503 iTransparency = pFormObj->form()->m_iTransparency; 1504 bGroupTransparent = !!(iTransparency & PDFTRANS_ISOLATED); 1505 const auto& pFormDict = pFormObj->form()->m_pFormDict; 1506 if (pFormDict) 1507 pFormResource = pFormDict->GetDictFor("Resources"); 1508 } 1509 bool bTextClip = 1510 (pPageObj->m_ClipPath.HasRef() && 1511 pPageObj->m_ClipPath.GetTextCount() > 0 && 1512 m_pDevice->GetDeviceClass() == FXDC_DISPLAY && 1513 !(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP)); 1514 if ((m_Options.HasFlag(RENDER_OVERPRINT)) && pPageObj->IsImage() && 1515 pPageObj->m_GeneralState.GetFillOP() && 1516 pPageObj->m_GeneralState.GetStrokeOP()) { 1517 CPDF_Document* pDocument = nullptr; 1518 CPDF_Page* pPage = nullptr; 1519 if (m_pContext->GetPageCache()) { 1520 pPage = m_pContext->GetPageCache()->GetPage(); 1521 pDocument = pPage->m_pDocument.Get(); 1522 } else { 1523 pDocument = pPageObj->AsImage()->GetImage()->GetDocument(); 1524 } 1525 CPDF_Dictionary* pPageResources = 1526 pPage ? pPage->m_pPageResources.Get() : nullptr; 1527 CPDF_Object* pCSObj = pPageObj->AsImage() 1528 ->GetImage() 1529 ->GetStream() 1530 ->GetDict() 1531 ->GetDirectObjectFor("ColorSpace"); 1532 CPDF_ColorSpace* pColorSpace = 1533 pDocument->LoadColorSpace(pCSObj, pPageResources); 1534 if (pColorSpace) { 1535 int format = pColorSpace->GetFamily(); 1536 if (format == PDFCS_DEVICECMYK || format == PDFCS_SEPARATION || 1537 format == PDFCS_DEVICEN) { 1538 blend_type = FXDIB_BLEND_DARKEN; 1539 } 1540 pDocument->GetPageData()->ReleaseColorSpace(pCSObj); 1541 } 1542 } 1543 if (!pSMaskDict && group_alpha == 1.0f && blend_type == FXDIB_BLEND_NORMAL && 1544 !bTextClip && !bGroupTransparent) { 1545 return false; 1546 } 1547 bool isolated = !!(iTransparency & PDFTRANS_ISOLATED); 1548 if (m_bPrint) { 1549 bool bRet = false; 1550 int rendCaps = m_pDevice->GetRenderCaps(); 1551 if (!((iTransparency & PDFTRANS_ISOLATED) || pSMaskDict || bTextClip) && 1552 (rendCaps & FXRC_BLEND_MODE)) { 1553 int oldBlend = m_curBlend; 1554 m_curBlend = blend_type; 1555 bRet = DrawObjWithBlend(pPageObj, pObj2Device); 1556 m_curBlend = oldBlend; 1557 } 1558 if (!bRet) { 1559 DrawObjWithBackground(pPageObj, pObj2Device); 1560 } 1561 return true; 1562 } 1563 FX_RECT rect = pPageObj->GetBBox(pObj2Device); 1564 rect.Intersect(m_pDevice->GetClipBox()); 1565 if (rect.IsEmpty()) 1566 return true; 1567 1568 CFX_Matrix deviceCTM = m_pDevice->GetCTM(); 1569 float scaleX = fabs(deviceCTM.a); 1570 float scaleY = fabs(deviceCTM.d); 1571 int width = FXSYS_round((float)rect.Width() * scaleX); 1572 int height = FXSYS_round((float)rect.Height() * scaleY); 1573 CFX_DefaultRenderDevice bitmap_device; 1574 RetainPtr<CFX_DIBitmap> oriDevice; 1575 if (!isolated && (m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) { 1576 oriDevice = pdfium::MakeRetain<CFX_DIBitmap>(); 1577 if (!m_pDevice->CreateCompatibleBitmap(oriDevice, width, height)) 1578 return true; 1579 m_pDevice->GetDIBits(oriDevice, rect.left, rect.top); 1580 } 1581 if (!bitmap_device.Create(width, height, FXDIB_Argb, oriDevice)) 1582 return true; 1583 1584 RetainPtr<CFX_DIBitmap> bitmap = bitmap_device.GetBitmap(); 1585 bitmap->Clear(0); 1586 1587 CFX_Matrix new_matrix = *pObj2Device; 1588 new_matrix.Translate(-rect.left, -rect.top); 1589 new_matrix.Scale(scaleX, scaleY); 1590 1591 RetainPtr<CFX_DIBitmap> pTextMask; 1592 if (bTextClip) { 1593 pTextMask = pdfium::MakeRetain<CFX_DIBitmap>(); 1594 if (!pTextMask->Create(width, height, FXDIB_8bppMask)) 1595 return true; 1596 1597 pTextMask->Clear(0); 1598 CFX_DefaultRenderDevice text_device; 1599 text_device.Attach(pTextMask, false, nullptr, false); 1600 for (size_t i = 0; i < pPageObj->m_ClipPath.GetTextCount(); ++i) { 1601 CPDF_TextObject* textobj = pPageObj->m_ClipPath.GetText(i); 1602 if (!textobj) 1603 break; 1604 1605 CFX_Matrix text_matrix = textobj->GetTextMatrix(); 1606 CPDF_TextRenderer::DrawTextPath( 1607 &text_device, textobj->GetCharCodes(), textobj->GetCharPositions(), 1608 textobj->m_TextState.GetFont(), textobj->m_TextState.GetFontSize(), 1609 &text_matrix, &new_matrix, textobj->m_GraphState.GetObject(), 1610 (FX_ARGB)-1, 0, nullptr, 0); 1611 } 1612 } 1613 CPDF_RenderStatus bitmap_render; 1614 bitmap_render.Initialize(m_pContext.Get(), &bitmap_device, nullptr, 1615 m_pStopObj, nullptr, nullptr, &m_Options, 0, 1616 m_bDropObjects, pFormResource, true); 1617 bitmap_render.ProcessObjectNoClip(pPageObj, &new_matrix); 1618 #if defined _SKIA_SUPPORT_PATHS_ 1619 bitmap_device.Flush(true); 1620 bitmap->UnPreMultiply(); 1621 #endif 1622 m_bStopped = bitmap_render.m_bStopped; 1623 if (pSMaskDict) { 1624 CFX_Matrix smask_matrix = *pPageObj->m_GeneralState.GetSMaskMatrix(); 1625 smask_matrix.Concat(*pObj2Device); 1626 RetainPtr<CFX_DIBSource> pSMaskSource = 1627 LoadSMask(pSMaskDict, &rect, &smask_matrix); 1628 if (pSMaskSource) 1629 bitmap->MultiplyAlpha(pSMaskSource); 1630 } 1631 if (pTextMask) { 1632 bitmap->MultiplyAlpha(pTextMask); 1633 pTextMask.Reset(); 1634 } 1635 int32_t blitAlpha = 255; 1636 if (iTransparency & PDFTRANS_GROUP && group_alpha != 1.0f) { 1637 blitAlpha = (int32_t)(group_alpha * 255); 1638 #ifndef _SKIA_SUPPORT_ 1639 bitmap->MultiplyAlpha(blitAlpha); 1640 blitAlpha = 255; 1641 #endif 1642 } 1643 iTransparency = m_iTransparency; 1644 if (pPageObj->IsForm()) { 1645 iTransparency |= PDFTRANS_GROUP; 1646 } 1647 CompositeDIBitmap(bitmap, rect.left, rect.top, 0, blitAlpha, blend_type, 1648 iTransparency); 1649 #if defined _SKIA_SUPPORT_ 1650 DebugVerifyDeviceIsPreMultiplied(); 1651 #endif 1652 return true; 1653 } 1654 1655 RetainPtr<CFX_DIBitmap> CPDF_RenderStatus::GetBackdrop( 1656 const CPDF_PageObject* pObj, 1657 const FX_RECT& rect, 1658 bool bBackAlphaRequired, 1659 int* left, 1660 int* top) { 1661 FX_RECT bbox = rect; 1662 bbox.Intersect(m_pDevice->GetClipBox()); 1663 *left = bbox.left; 1664 *top = bbox.top; 1665 CFX_Matrix deviceCTM = m_pDevice->GetCTM(); 1666 float scaleX = fabs(deviceCTM.a); 1667 float scaleY = fabs(deviceCTM.d); 1668 int width = FXSYS_round(bbox.Width() * scaleX); 1669 int height = FXSYS_round(bbox.Height() * scaleY); 1670 auto pBackdrop = pdfium::MakeRetain<CFX_DIBitmap>(); 1671 if (bBackAlphaRequired && !m_bDropObjects) 1672 pBackdrop->Create(width, height, FXDIB_Argb); 1673 else 1674 m_pDevice->CreateCompatibleBitmap(pBackdrop, width, height); 1675 1676 if (!pBackdrop->GetBuffer()) 1677 return nullptr; 1678 1679 bool bNeedDraw; 1680 if (pBackdrop->HasAlpha()) 1681 bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT); 1682 else 1683 bNeedDraw = !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS); 1684 1685 if (!bNeedDraw) { 1686 m_pDevice->GetDIBits(pBackdrop, *left, *top); 1687 return pBackdrop; 1688 } 1689 CFX_Matrix FinalMatrix = m_DeviceMatrix; 1690 FinalMatrix.Translate(-*left, -*top); 1691 FinalMatrix.Scale(scaleX, scaleY); 1692 pBackdrop->Clear(pBackdrop->HasAlpha() ? 0 : 0xffffffff); 1693 1694 CFX_DefaultRenderDevice device; 1695 device.Attach(pBackdrop, false, nullptr, false); 1696 m_pContext->Render(&device, pObj, &m_Options, &FinalMatrix); 1697 return pBackdrop; 1698 } 1699 1700 std::unique_ptr<CPDF_GraphicStates> CPDF_RenderStatus::CloneObjStates( 1701 const CPDF_GraphicStates* pSrcStates, 1702 bool bStroke) { 1703 if (!pSrcStates) 1704 return nullptr; 1705 1706 auto pStates = pdfium::MakeUnique<CPDF_GraphicStates>(); 1707 pStates->CopyStates(*pSrcStates); 1708 const CPDF_Color* pObjColor = bStroke 1709 ? pSrcStates->m_ColorState.GetStrokeColor() 1710 : pSrcStates->m_ColorState.GetFillColor(); 1711 if (!pObjColor->IsNull()) { 1712 pStates->m_ColorState.SetFillRGB( 1713 bStroke ? pSrcStates->m_ColorState.GetStrokeRGB() 1714 : pSrcStates->m_ColorState.GetFillRGB()); 1715 pStates->m_ColorState.SetStrokeRGB(pStates->m_ColorState.GetFillRGB()); 1716 } 1717 return pStates; 1718 } 1719 1720 #if defined _SKIA_SUPPORT_ 1721 void CPDF_RenderStatus::DebugVerifyDeviceIsPreMultiplied() const { 1722 m_pDevice->DebugVerifyBitmapIsPreMultiplied(); 1723 } 1724 #endif 1725 1726 bool CPDF_RenderStatus::ProcessText(CPDF_TextObject* textobj, 1727 const CFX_Matrix* pObj2Device, 1728 CFX_PathData* pClippingPath) { 1729 if (textobj->GetCharCodes().empty()) 1730 return true; 1731 1732 const TextRenderingMode text_render_mode = textobj->m_TextState.GetTextMode(); 1733 if (text_render_mode == TextRenderingMode::MODE_INVISIBLE) 1734 return true; 1735 1736 CPDF_Font* pFont = textobj->m_TextState.GetFont(); 1737 if (pFont->IsType3Font()) 1738 return ProcessType3Text(textobj, pObj2Device); 1739 1740 bool bFill = false; 1741 bool bStroke = false; 1742 bool bClip = false; 1743 if (pClippingPath) { 1744 bClip = true; 1745 } else { 1746 switch (text_render_mode) { 1747 case TextRenderingMode::MODE_FILL: 1748 case TextRenderingMode::MODE_FILL_CLIP: 1749 bFill = true; 1750 break; 1751 case TextRenderingMode::MODE_STROKE: 1752 case TextRenderingMode::MODE_STROKE_CLIP: 1753 if (pFont->GetFace()) 1754 bStroke = true; 1755 else 1756 bFill = true; 1757 break; 1758 case TextRenderingMode::MODE_FILL_STROKE: 1759 case TextRenderingMode::MODE_FILL_STROKE_CLIP: 1760 bFill = true; 1761 if (pFont->GetFace()) 1762 bStroke = true; 1763 break; 1764 case TextRenderingMode::MODE_INVISIBLE: 1765 // Already handled above, but the compiler is not smart enough to 1766 // realize it. Fall through. 1767 NOTREACHED(); 1768 case TextRenderingMode::MODE_CLIP: 1769 return true; 1770 } 1771 } 1772 FX_ARGB stroke_argb = 0; 1773 FX_ARGB fill_argb = 0; 1774 bool bPattern = false; 1775 if (bStroke) { 1776 if (textobj->m_ColorState.GetStrokeColor()->IsPattern()) { 1777 bPattern = true; 1778 } else { 1779 stroke_argb = GetStrokeArgb(textobj); 1780 } 1781 } 1782 if (bFill) { 1783 if (textobj->m_ColorState.GetFillColor()->IsPattern()) { 1784 bPattern = true; 1785 } else { 1786 fill_argb = GetFillArgb(textobj); 1787 } 1788 } 1789 CFX_Matrix text_matrix = textobj->GetTextMatrix(); 1790 if (!IsAvailableMatrix(text_matrix)) 1791 return true; 1792 1793 float font_size = textobj->m_TextState.GetFontSize(); 1794 if (bPattern) { 1795 DrawTextPathWithPattern(textobj, pObj2Device, pFont, font_size, 1796 &text_matrix, bFill, bStroke); 1797 return true; 1798 } 1799 if (bClip || bStroke) { 1800 const CFX_Matrix* pDeviceMatrix = pObj2Device; 1801 CFX_Matrix device_matrix; 1802 if (bStroke) { 1803 const float* pCTM = textobj->m_TextState.GetCTM(); 1804 if (pCTM[0] != 1.0f || pCTM[3] != 1.0f) { 1805 CFX_Matrix ctm(pCTM[0], pCTM[1], pCTM[2], pCTM[3], 0, 0); 1806 text_matrix.ConcatInverse(ctm); 1807 device_matrix = ctm; 1808 device_matrix.Concat(*pObj2Device); 1809 pDeviceMatrix = &device_matrix; 1810 } 1811 } 1812 int flag = 0; 1813 if (bStroke && bFill) { 1814 flag |= FX_FILL_STROKE; 1815 flag |= FX_STROKE_TEXT_MODE; 1816 } 1817 if (textobj->m_GeneralState.GetStrokeAdjust()) 1818 flag |= FX_STROKE_ADJUST; 1819 if (m_Options.HasFlag(RENDER_NOTEXTSMOOTH)) 1820 flag |= FXFILL_NOPATHSMOOTH; 1821 return CPDF_TextRenderer::DrawTextPath( 1822 m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(), pFont, 1823 font_size, &text_matrix, pDeviceMatrix, 1824 textobj->m_GraphState.GetObject(), fill_argb, stroke_argb, 1825 pClippingPath, flag); 1826 } 1827 text_matrix.Concat(*pObj2Device); 1828 return CPDF_TextRenderer::DrawNormalText( 1829 m_pDevice, textobj->GetCharCodes(), textobj->GetCharPositions(), pFont, 1830 font_size, &text_matrix, fill_argb, &m_Options); 1831 } 1832 1833 RetainPtr<CPDF_Type3Cache> CPDF_RenderStatus::GetCachedType3( 1834 CPDF_Type3Font* pFont) { 1835 CPDF_Document* pDoc = pFont->GetDocument(); 1836 if (!pDoc) 1837 return nullptr; 1838 1839 pDoc->GetPageData()->GetFont(pFont->GetFontDict()); 1840 return pDoc->GetRenderData()->GetCachedType3(pFont); 1841 } 1842 1843 // TODO(npm): Font fallback for type 3 fonts? (Completely separate code!!) 1844 bool CPDF_RenderStatus::ProcessType3Text(CPDF_TextObject* textobj, 1845 const CFX_Matrix* pObj2Device) { 1846 CPDF_Type3Font* pType3Font = textobj->m_TextState.GetFont()->AsType3Font(); 1847 if (pdfium::ContainsValue(m_Type3FontCache, pType3Font)) 1848 return true; 1849 1850 CFX_Matrix dCTM = m_pDevice->GetCTM(); 1851 float sa = fabs(dCTM.a); 1852 float sd = fabs(dCTM.d); 1853 CFX_Matrix text_matrix = textobj->GetTextMatrix(); 1854 CFX_Matrix char_matrix = pType3Font->GetFontMatrix(); 1855 float font_size = textobj->m_TextState.GetFontSize(); 1856 char_matrix.Scale(font_size, font_size); 1857 FX_ARGB fill_argb = GetFillArgb(textobj, true); 1858 int fill_alpha = FXARGB_A(fill_argb); 1859 int device_class = m_pDevice->GetDeviceClass(); 1860 std::vector<FXTEXT_GLYPHPOS> glyphs; 1861 if (device_class == FXDC_DISPLAY) 1862 glyphs.resize(textobj->GetCharCodes().size()); 1863 else if (fill_alpha < 255) 1864 return false; 1865 1866 CPDF_RefType3Cache refTypeCache(pType3Font); 1867 for (size_t iChar = 0; iChar < textobj->GetCharCodes().size(); ++iChar) { 1868 uint32_t charcode = textobj->GetCharCodes()[iChar]; 1869 if (charcode == static_cast<uint32_t>(-1)) 1870 continue; 1871 1872 CPDF_Type3Char* pType3Char = pType3Font->LoadChar(charcode); 1873 if (!pType3Char) 1874 continue; 1875 1876 CFX_Matrix matrix = char_matrix; 1877 matrix.e += iChar > 0 ? textobj->GetCharPositions()[iChar - 1] : 0; 1878 matrix.Concat(text_matrix); 1879 matrix.Concat(*pObj2Device); 1880 if (!pType3Char->LoadBitmap(m_pContext.Get())) { 1881 if (!glyphs.empty()) { 1882 for (size_t i = 0; i < iChar; ++i) { 1883 const FXTEXT_GLYPHPOS& glyph = glyphs[i]; 1884 if (!glyph.m_pGlyph) 1885 continue; 1886 1887 m_pDevice->SetBitMask(glyph.m_pGlyph->m_pBitmap, 1888 glyph.m_Origin.x + glyph.m_pGlyph->m_Left, 1889 glyph.m_Origin.y - glyph.m_pGlyph->m_Top, 1890 fill_argb); 1891 } 1892 glyphs.clear(); 1893 } 1894 1895 std::unique_ptr<CPDF_GraphicStates> pStates = 1896 CloneObjStates(textobj, false); 1897 CPDF_RenderOptions options = m_Options; 1898 uint32_t option_flags = options.GetFlags(); 1899 option_flags |= RENDER_FORCE_HALFTONE | RENDER_RECT_AA; 1900 option_flags &= ~RENDER_FORCE_DOWNSAMPLE; 1901 options.SetFlags(option_flags); 1902 1903 CPDF_Dictionary* pFormResource = nullptr; 1904 if (pType3Char->form() && pType3Char->form()->m_pFormDict) { 1905 pFormResource = 1906 pType3Char->form()->m_pFormDict->GetDictFor("Resources"); 1907 } 1908 if (fill_alpha == 255) { 1909 CPDF_RenderStatus status; 1910 status.Initialize(m_pContext.Get(), m_pDevice, nullptr, nullptr, this, 1911 pStates.get(), &options, 1912 pType3Char->form()->m_iTransparency, m_bDropObjects, 1913 pFormResource, false, pType3Char, fill_argb); 1914 status.m_Type3FontCache = m_Type3FontCache; 1915 status.m_Type3FontCache.push_back(pType3Font); 1916 1917 CFX_RenderDevice::StateRestorer restorer(m_pDevice); 1918 status.RenderObjectList(pType3Char->form(), &matrix); 1919 } else { 1920 FX_RECT rect = 1921 matrix.TransformRect(pType3Char->form()->CalcBoundingBox()) 1922 .GetOuterRect(); 1923 CFX_DefaultRenderDevice bitmap_device; 1924 if (!bitmap_device.Create((int)(rect.Width() * sa), 1925 (int)(rect.Height() * sd), FXDIB_Argb, 1926 nullptr)) { 1927 return true; 1928 } 1929 bitmap_device.GetBitmap()->Clear(0); 1930 CPDF_RenderStatus status; 1931 status.Initialize(m_pContext.Get(), &bitmap_device, nullptr, nullptr, 1932 this, pStates.get(), &options, 1933 pType3Char->form()->m_iTransparency, m_bDropObjects, 1934 pFormResource, false, pType3Char, fill_argb); 1935 status.m_Type3FontCache = m_Type3FontCache; 1936 status.m_Type3FontCache.push_back(pType3Font); 1937 matrix.Translate(-rect.left, -rect.top); 1938 matrix.Scale(sa, sd); 1939 status.RenderObjectList(pType3Char->form(), &matrix); 1940 m_pDevice->SetDIBits(bitmap_device.GetBitmap(), rect.left, rect.top); 1941 } 1942 } else if (pType3Char->GetBitmap()) { 1943 if (device_class == FXDC_DISPLAY) { 1944 RetainPtr<CPDF_Type3Cache> pCache = GetCachedType3(pType3Font); 1945 refTypeCache.m_dwCount++; 1946 CFX_GlyphBitmap* pBitmap = pCache->LoadGlyph(charcode, &matrix, sa, sd); 1947 if (!pBitmap) 1948 continue; 1949 1950 CFX_Point origin(FXSYS_round(matrix.e), FXSYS_round(matrix.f)); 1951 if (glyphs.empty()) { 1952 m_pDevice->SetBitMask(pBitmap->m_pBitmap, origin.x + pBitmap->m_Left, 1953 origin.y - pBitmap->m_Top, fill_argb); 1954 } else { 1955 glyphs[iChar].m_pGlyph = pBitmap; 1956 glyphs[iChar].m_Origin = origin; 1957 } 1958 } else { 1959 CFX_Matrix image_matrix = pType3Char->matrix(); 1960 image_matrix.Concat(matrix); 1961 CPDF_ImageRenderer renderer; 1962 if (renderer.Start(this, pType3Char->GetBitmap(), fill_argb, 255, 1963 &image_matrix, 0, false, FXDIB_BLEND_NORMAL)) { 1964 renderer.Continue(nullptr); 1965 } 1966 if (!renderer.GetResult()) 1967 return false; 1968 } 1969 } 1970 } 1971 1972 if (glyphs.empty()) 1973 return true; 1974 1975 FX_RECT rect = FXGE_GetGlyphsBBox(glyphs, 0, sa, sd); 1976 auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); 1977 if (!pBitmap->Create(static_cast<int>(rect.Width() * sa), 1978 static_cast<int>(rect.Height() * sd), FXDIB_8bppMask)) { 1979 return true; 1980 } 1981 pBitmap->Clear(0); 1982 for (const FXTEXT_GLYPHPOS& glyph : glyphs) { 1983 if (!glyph.m_pGlyph) 1984 continue; 1985 1986 pdfium::base::CheckedNumeric<int> left = glyph.m_Origin.x; 1987 left += glyph.m_pGlyph->m_Left; 1988 left -= rect.left; 1989 left *= sa; 1990 if (!left.IsValid()) 1991 continue; 1992 1993 pdfium::base::CheckedNumeric<int> top = glyph.m_Origin.y; 1994 top -= glyph.m_pGlyph->m_Top; 1995 top -= rect.top; 1996 top *= sd; 1997 if (!top.IsValid()) 1998 continue; 1999 2000 pBitmap->CompositeMask(left.ValueOrDie(), top.ValueOrDie(), 2001 glyph.m_pGlyph->m_pBitmap->GetWidth(), 2002 glyph.m_pGlyph->m_pBitmap->GetHeight(), 2003 glyph.m_pGlyph->m_pBitmap, fill_argb, 0, 0, 2004 FXDIB_BLEND_NORMAL, nullptr, false, 0); 2005 } 2006 m_pDevice->SetBitMask(pBitmap, rect.left, rect.top, fill_argb); 2007 return true; 2008 } 2009 2010 void CPDF_RenderStatus::DrawTextPathWithPattern(const CPDF_TextObject* textobj, 2011 const CFX_Matrix* pObj2Device, 2012 CPDF_Font* pFont, 2013 float font_size, 2014 const CFX_Matrix* pTextMatrix, 2015 bool bFill, 2016 bool bStroke) { 2017 if (!bStroke) { 2018 CPDF_PathObject path; 2019 std::vector<std::unique_ptr<CPDF_TextObject>> pCopy; 2020 pCopy.push_back(std::unique_ptr<CPDF_TextObject>(textobj->Clone())); 2021 path.m_bStroke = false; 2022 path.m_FillType = FXFILL_WINDING; 2023 path.m_ClipPath.AppendTexts(&pCopy); 2024 path.m_ColorState = textobj->m_ColorState; 2025 path.m_Path.AppendRect(textobj->m_Left, textobj->m_Bottom, textobj->m_Right, 2026 textobj->m_Top); 2027 path.m_Left = textobj->m_Left; 2028 path.m_Bottom = textobj->m_Bottom; 2029 path.m_Right = textobj->m_Right; 2030 path.m_Top = textobj->m_Top; 2031 RenderSingleObject(&path, pObj2Device); 2032 return; 2033 } 2034 CPDF_CharPosList CharPosList; 2035 CharPosList.Load(textobj->GetCharCodes(), textobj->GetCharPositions(), pFont, 2036 font_size); 2037 for (uint32_t i = 0; i < CharPosList.m_nChars; i++) { 2038 FXTEXT_CHARPOS& charpos = CharPosList.m_pCharPos[i]; 2039 auto* font = charpos.m_FallbackFontPosition == -1 2040 ? pFont->GetFont() 2041 : pFont->GetFontFallback(charpos.m_FallbackFontPosition); 2042 const CFX_PathData* pPath = 2043 font->LoadGlyphPath(charpos.m_GlyphIndex, charpos.m_FontCharWidth); 2044 if (!pPath) 2045 continue; 2046 2047 CPDF_PathObject path; 2048 path.m_GraphState = textobj->m_GraphState; 2049 path.m_ColorState = textobj->m_ColorState; 2050 2051 CFX_Matrix matrix; 2052 if (charpos.m_bGlyphAdjust) { 2053 matrix = CFX_Matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1], 2054 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 2055 0, 0); 2056 } 2057 matrix.Concat(CFX_Matrix(font_size, 0, 0, font_size, charpos.m_Origin.x, 2058 charpos.m_Origin.y)); 2059 path.m_Path.Append(pPath, &matrix); 2060 path.m_Matrix = *pTextMatrix; 2061 path.m_bStroke = bStroke; 2062 path.m_FillType = bFill ? FXFILL_WINDING : 0; 2063 path.CalcBoundingBox(); 2064 ProcessPath(&path, pObj2Device); 2065 } 2066 } 2067 2068 void CPDF_RenderStatus::DrawShading(const CPDF_ShadingPattern* pPattern, 2069 CFX_Matrix* pMatrix, 2070 FX_RECT& clip_rect, 2071 int alpha, 2072 bool bAlphaMode) { 2073 const auto& funcs = pPattern->GetFuncs(); 2074 CPDF_Dictionary* pDict = pPattern->GetShadingObject()->GetDict(); 2075 CPDF_ColorSpace* pColorSpace = pPattern->GetCS(); 2076 if (!pColorSpace) 2077 return; 2078 2079 FX_ARGB background = 0; 2080 if (!pPattern->IsShadingObject() && pDict->KeyExist("Background")) { 2081 CPDF_Array* pBackColor = pDict->GetArrayFor("Background"); 2082 if (pBackColor && 2083 pBackColor->GetCount() >= pColorSpace->CountComponents()) { 2084 CFX_FixedBufGrow<float, 16> comps(pColorSpace->CountComponents()); 2085 for (uint32_t i = 0; i < pColorSpace->CountComponents(); i++) 2086 comps[i] = pBackColor->GetNumberAt(i); 2087 float R = 0.0f; 2088 float G = 0.0f; 2089 float B = 0.0f; 2090 pColorSpace->GetRGB(comps, &R, &G, &B); 2091 background = ArgbEncode(255, (int32_t)(R * 255), (int32_t)(G * 255), 2092 (int32_t)(B * 255)); 2093 } 2094 } 2095 if (pDict->KeyExist("BBox")) { 2096 clip_rect.Intersect( 2097 pMatrix->TransformRect(pDict->GetRectFor("BBox")).GetOuterRect()); 2098 } 2099 if (m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SHADING && 2100 m_pDevice->GetDeviceDriver()->DrawShading(pPattern, pMatrix, clip_rect, 2101 alpha, bAlphaMode)) { 2102 return; 2103 } 2104 CPDF_DeviceBuffer buffer; 2105 buffer.Initialize(m_pContext.Get(), m_pDevice, &clip_rect, m_pCurObj, 150); 2106 CFX_Matrix FinalMatrix = *pMatrix; 2107 FinalMatrix.Concat(*buffer.GetMatrix()); 2108 RetainPtr<CFX_DIBitmap> pBitmap = buffer.GetBitmap(); 2109 if (!pBitmap->GetBuffer()) 2110 return; 2111 2112 pBitmap->Clear(background); 2113 switch (pPattern->GetShadingType()) { 2114 case kInvalidShading: 2115 case kMaxShading: 2116 return; 2117 case kFunctionBasedShading: 2118 DrawFuncShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace, alpha); 2119 break; 2120 case kAxialShading: 2121 DrawAxialShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace, alpha); 2122 break; 2123 case kRadialShading: 2124 DrawRadialShading(pBitmap, &FinalMatrix, pDict, funcs, pColorSpace, 2125 alpha); 2126 break; 2127 case kFreeFormGouraudTriangleMeshShading: { 2128 // The shading object can be a stream or a dictionary. We do not handle 2129 // the case of dictionary at the moment. 2130 if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) { 2131 DrawFreeGouraudShading(pBitmap, &FinalMatrix, pStream, funcs, 2132 pColorSpace, alpha); 2133 } 2134 } break; 2135 case kLatticeFormGouraudTriangleMeshShading: { 2136 // The shading object can be a stream or a dictionary. We do not handle 2137 // the case of dictionary at the moment. 2138 if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) { 2139 DrawLatticeGouraudShading(pBitmap, &FinalMatrix, pStream, funcs, 2140 pColorSpace, alpha); 2141 } 2142 } break; 2143 case kCoonsPatchMeshShading: 2144 case kTensorProductPatchMeshShading: { 2145 // The shading object can be a stream or a dictionary. We do not handle 2146 // the case of dictionary at the moment. 2147 if (CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject())) { 2148 DrawCoonPatchMeshes(pPattern->GetShadingType(), pBitmap, &FinalMatrix, 2149 pStream, funcs, pColorSpace, m_Options.GetFlags(), 2150 alpha); 2151 } 2152 } break; 2153 } 2154 if (bAlphaMode) 2155 pBitmap->LoadChannel(FXDIB_Red, pBitmap, FXDIB_Alpha); 2156 2157 if (m_Options.ColorModeIs(CPDF_RenderOptions::kGray)) 2158 pBitmap->ConvertColorScale(0, 0xffffff); 2159 buffer.OutputToDevice(); 2160 } 2161 2162 void CPDF_RenderStatus::DrawShadingPattern(CPDF_ShadingPattern* pattern, 2163 const CPDF_PageObject* pPageObj, 2164 const CFX_Matrix* pObj2Device, 2165 bool bStroke) { 2166 if (!pattern->Load()) 2167 return; 2168 2169 CFX_RenderDevice::StateRestorer restorer(m_pDevice); 2170 if (pPageObj->IsPath()) { 2171 if (!SelectClipPath(pPageObj->AsPath(), pObj2Device, bStroke)) 2172 return; 2173 } else if (pPageObj->IsImage()) { 2174 m_pDevice->SetClip_Rect(pPageObj->GetBBox(pObj2Device)); 2175 } else { 2176 return; 2177 } 2178 FX_RECT rect; 2179 if (GetObjectClippedRect(pPageObj, pObj2Device, false, rect)) 2180 return; 2181 2182 CFX_Matrix matrix = *pattern->pattern_to_form(); 2183 matrix.Concat(*pObj2Device); 2184 GetScaledMatrix(matrix); 2185 int alpha = 2186 FXSYS_round(255 * (bStroke ? pPageObj->m_GeneralState.GetStrokeAlpha() 2187 : pPageObj->m_GeneralState.GetFillAlpha())); 2188 DrawShading(pattern, &matrix, rect, alpha, 2189 m_Options.ColorModeIs(CPDF_RenderOptions::kAlpha)); 2190 } 2191 2192 void CPDF_RenderStatus::ProcessShading(const CPDF_ShadingObject* pShadingObj, 2193 const CFX_Matrix* pObj2Device) { 2194 FX_RECT rect = pShadingObj->GetBBox(pObj2Device); 2195 FX_RECT clip_box = m_pDevice->GetClipBox(); 2196 rect.Intersect(clip_box); 2197 if (rect.IsEmpty()) 2198 return; 2199 2200 CFX_Matrix matrix = pShadingObj->matrix(); 2201 matrix.Concat(*pObj2Device); 2202 DrawShading(pShadingObj->pattern(), &matrix, rect, 2203 FXSYS_round(255 * pShadingObj->m_GeneralState.GetFillAlpha()), 2204 m_Options.ColorModeIs(CPDF_RenderOptions::kAlpha)); 2205 } 2206 2207 void CPDF_RenderStatus::DrawTilingPattern(CPDF_TilingPattern* pPattern, 2208 CPDF_PageObject* pPageObj, 2209 const CFX_Matrix* pObj2Device, 2210 bool bStroke) { 2211 if (!pPattern->Load()) 2212 return; 2213 2214 CFX_RenderDevice::StateRestorer restorer(m_pDevice); 2215 if (pPageObj->IsPath()) { 2216 if (!SelectClipPath(pPageObj->AsPath(), pObj2Device, bStroke)) 2217 return; 2218 } else if (pPageObj->IsImage()) { 2219 m_pDevice->SetClip_Rect(pPageObj->GetBBox(pObj2Device)); 2220 } else { 2221 return; 2222 } 2223 2224 FX_RECT clip_box = m_pDevice->GetClipBox(); 2225 if (clip_box.IsEmpty()) 2226 return; 2227 2228 CFX_Matrix dCTM = m_pDevice->GetCTM(); 2229 float sa = fabs(dCTM.a); 2230 float sd = fabs(dCTM.d); 2231 clip_box.right = clip_box.left + (int32_t)ceil(clip_box.Width() * sa); 2232 clip_box.bottom = clip_box.top + (int32_t)ceil(clip_box.Height() * sd); 2233 2234 CFX_Matrix mtPattern2Device = *pPattern->pattern_to_form(); 2235 mtPattern2Device.Concat(*pObj2Device); 2236 GetScaledMatrix(mtPattern2Device); 2237 2238 bool bAligned = 2239 pPattern->bbox().left == 0 && pPattern->bbox().bottom == 0 && 2240 pPattern->bbox().right == pPattern->x_step() && 2241 pPattern->bbox().top == pPattern->y_step() && 2242 (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated()); 2243 2244 CFX_FloatRect cell_bbox = mtPattern2Device.TransformRect(pPattern->bbox()); 2245 2246 float ceil_height = std::ceil(cell_bbox.Height()); 2247 float ceil_width = std::ceil(cell_bbox.Width()); 2248 2249 // Validate the float will fit into the int when the conversion is done. 2250 if (!pdfium::base::IsValueInRangeForNumericType<int>(ceil_height) || 2251 !pdfium::base::IsValueInRangeForNumericType<int>(ceil_width)) { 2252 return; 2253 } 2254 2255 int width = static_cast<int>(ceil_width); 2256 int height = static_cast<int>(ceil_height); 2257 if (width <= 0) 2258 width = 1; 2259 if (height <= 0) 2260 height = 1; 2261 2262 CFX_FloatRect clip_box_p = 2263 mtPattern2Device.GetInverse().TransformRect(CFX_FloatRect(clip_box)); 2264 int min_col = (int)ceil((clip_box_p.left - pPattern->bbox().right) / 2265 pPattern->x_step()); 2266 int max_col = (int)floor((clip_box_p.right - pPattern->bbox().left) / 2267 pPattern->x_step()); 2268 int min_row = (int)ceil((clip_box_p.bottom - pPattern->bbox().top) / 2269 pPattern->y_step()); 2270 int max_row = (int)floor((clip_box_p.top - pPattern->bbox().bottom) / 2271 pPattern->y_step()); 2272 2273 // Make sure we can fit the needed width * height into an int. 2274 if (height > std::numeric_limits<int>::max() / width) 2275 return; 2276 2277 if (width > clip_box.Width() || height > clip_box.Height() || 2278 width * height > clip_box.Width() * clip_box.Height()) { 2279 std::unique_ptr<CPDF_GraphicStates> pStates; 2280 if (!pPattern->colored()) 2281 pStates = CloneObjStates(pPageObj, bStroke); 2282 2283 auto& pFormDict = pPattern->form()->m_pFormDict; 2284 CPDF_Dictionary* pFormResource = 2285 pFormDict ? pFormDict->GetDictFor("Resources") : nullptr; 2286 for (int col = min_col; col <= max_col; col++) { 2287 for (int row = min_row; row <= max_row; row++) { 2288 CFX_PointF original = mtPattern2Device.Transform( 2289 CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step())); 2290 CFX_Matrix matrix = *pObj2Device; 2291 matrix.Translate(original.x - mtPattern2Device.e, 2292 original.y - mtPattern2Device.f); 2293 CFX_RenderDevice::StateRestorer restorer2(m_pDevice); 2294 CPDF_RenderStatus status; 2295 status.Initialize(m_pContext.Get(), m_pDevice, nullptr, nullptr, this, 2296 pStates.get(), &m_Options, 2297 pPattern->form()->m_iTransparency, m_bDropObjects, 2298 pFormResource); 2299 status.RenderObjectList(pPattern->form(), &matrix); 2300 } 2301 } 2302 return; 2303 } 2304 if (bAligned) { 2305 int orig_x = FXSYS_round(mtPattern2Device.e); 2306 int orig_y = FXSYS_round(mtPattern2Device.f); 2307 min_col = (clip_box.left - orig_x) / width; 2308 if (clip_box.left < orig_x) 2309 min_col--; 2310 2311 max_col = (clip_box.right - orig_x) / width; 2312 if (clip_box.right <= orig_x) 2313 max_col--; 2314 2315 min_row = (clip_box.top - orig_y) / height; 2316 if (clip_box.top < orig_y) 2317 min_row--; 2318 2319 max_row = (clip_box.bottom - orig_y) / height; 2320 if (clip_box.bottom <= orig_y) 2321 max_row--; 2322 } 2323 float left_offset = cell_bbox.left - mtPattern2Device.e; 2324 float top_offset = cell_bbox.bottom - mtPattern2Device.f; 2325 RetainPtr<CFX_DIBitmap> pPatternBitmap; 2326 if (width * height < 16) { 2327 RetainPtr<CFX_DIBitmap> pEnlargedBitmap = 2328 DrawPatternBitmap(m_pContext->GetDocument(), m_pContext->GetPageCache(), 2329 pPattern, pObj2Device, 8, 8, m_Options.GetFlags()); 2330 pPatternBitmap = pEnlargedBitmap->StretchTo(width, height, 0, nullptr); 2331 } else { 2332 pPatternBitmap = DrawPatternBitmap( 2333 m_pContext->GetDocument(), m_pContext->GetPageCache(), pPattern, 2334 pObj2Device, width, height, m_Options.GetFlags()); 2335 } 2336 if (!pPatternBitmap) 2337 return; 2338 2339 if (m_Options.ColorModeIs(CPDF_RenderOptions::kGray)) 2340 pPatternBitmap->ConvertColorScale(0, 0xffffff); 2341 2342 FX_ARGB fill_argb = GetFillArgb(pPageObj); 2343 int clip_width = clip_box.right - clip_box.left; 2344 int clip_height = clip_box.bottom - clip_box.top; 2345 auto pScreen = pdfium::MakeRetain<CFX_DIBitmap>(); 2346 if (!pScreen->Create(clip_width, clip_height, FXDIB_Argb)) 2347 return; 2348 2349 pScreen->Clear(0); 2350 uint32_t* src_buf = (uint32_t*)pPatternBitmap->GetBuffer(); 2351 for (int col = min_col; col <= max_col; col++) { 2352 for (int row = min_row; row <= max_row; row++) { 2353 int start_x, start_y; 2354 if (bAligned) { 2355 start_x = FXSYS_round(mtPattern2Device.e) + col * width - clip_box.left; 2356 start_y = FXSYS_round(mtPattern2Device.f) + row * height - clip_box.top; 2357 } else { 2358 CFX_PointF original = mtPattern2Device.Transform( 2359 CFX_PointF(col * pPattern->x_step(), row * pPattern->y_step())); 2360 2361 pdfium::base::CheckedNumeric<int> safeStartX = 2362 FXSYS_round(original.x + left_offset); 2363 pdfium::base::CheckedNumeric<int> safeStartY = 2364 FXSYS_round(original.y + top_offset); 2365 2366 safeStartX -= clip_box.left; 2367 safeStartY -= clip_box.top; 2368 if (!safeStartX.IsValid() || !safeStartY.IsValid()) 2369 return; 2370 2371 start_x = safeStartX.ValueOrDie(); 2372 start_y = safeStartY.ValueOrDie(); 2373 } 2374 if (width == 1 && height == 1) { 2375 if (start_x < 0 || start_x >= clip_box.Width() || start_y < 0 || 2376 start_y >= clip_box.Height()) { 2377 continue; 2378 } 2379 uint32_t* dest_buf = 2380 (uint32_t*)(pScreen->GetBuffer() + pScreen->GetPitch() * start_y + 2381 start_x * 4); 2382 if (pPattern->colored()) 2383 *dest_buf = *src_buf; 2384 else 2385 *dest_buf = (*(uint8_t*)src_buf << 24) | (fill_argb & 0xffffff); 2386 } else { 2387 if (pPattern->colored()) { 2388 pScreen->CompositeBitmap(start_x, start_y, width, height, 2389 pPatternBitmap, 0, 0); 2390 } else { 2391 pScreen->CompositeMask(start_x, start_y, width, height, 2392 pPatternBitmap, fill_argb, 0, 0); 2393 } 2394 } 2395 } 2396 } 2397 CompositeDIBitmap(pScreen, clip_box.left, clip_box.top, 0, 255, 2398 FXDIB_BLEND_NORMAL, false); 2399 } 2400 2401 void CPDF_RenderStatus::DrawPathWithPattern(CPDF_PathObject* pPathObj, 2402 const CFX_Matrix* pObj2Device, 2403 const CPDF_Color* pColor, 2404 bool bStroke) { 2405 CPDF_Pattern* pattern = pColor->GetPattern(); 2406 if (!pattern) 2407 return; 2408 2409 if (CPDF_TilingPattern* pTilingPattern = pattern->AsTilingPattern()) 2410 DrawTilingPattern(pTilingPattern, pPathObj, pObj2Device, bStroke); 2411 else if (CPDF_ShadingPattern* pShadingPattern = pattern->AsShadingPattern()) 2412 DrawShadingPattern(pShadingPattern, pPathObj, pObj2Device, bStroke); 2413 } 2414 2415 void CPDF_RenderStatus::ProcessPathPattern(CPDF_PathObject* pPathObj, 2416 const CFX_Matrix* pObj2Device, 2417 int& filltype, 2418 bool& bStroke) { 2419 if (filltype) { 2420 const CPDF_Color& FillColor = *pPathObj->m_ColorState.GetFillColor(); 2421 if (FillColor.IsPattern()) { 2422 DrawPathWithPattern(pPathObj, pObj2Device, &FillColor, false); 2423 filltype = 0; 2424 } 2425 } 2426 if (bStroke) { 2427 const CPDF_Color& StrokeColor = *pPathObj->m_ColorState.GetStrokeColor(); 2428 if (StrokeColor.IsPattern()) { 2429 DrawPathWithPattern(pPathObj, pObj2Device, &StrokeColor, true); 2430 bStroke = false; 2431 } 2432 } 2433 } 2434 2435 bool CPDF_RenderStatus::ProcessImage(CPDF_ImageObject* pImageObj, 2436 const CFX_Matrix* pObj2Device) { 2437 CPDF_ImageRenderer render; 2438 if (render.Start(this, pImageObj, pObj2Device, m_bStdCS, m_curBlend)) 2439 render.Continue(nullptr); 2440 return render.GetResult(); 2441 } 2442 2443 void CPDF_RenderStatus::CompositeDIBitmap( 2444 const RetainPtr<CFX_DIBitmap>& pDIBitmap, 2445 int left, 2446 int top, 2447 FX_ARGB mask_argb, 2448 int bitmap_alpha, 2449 int blend_mode, 2450 int iTransparency) { 2451 if (!pDIBitmap) 2452 return; 2453 2454 if (blend_mode == FXDIB_BLEND_NORMAL) { 2455 if (!pDIBitmap->IsAlphaMask()) { 2456 if (bitmap_alpha < 255) { 2457 #ifdef _SKIA_SUPPORT_ 2458 std::unique_ptr<CFX_ImageRenderer> dummy; 2459 CFX_Matrix m(pDIBitmap->GetWidth(), 0, 0, -pDIBitmap->GetHeight(), left, 2460 top + pDIBitmap->GetHeight()); 2461 m_pDevice->StartDIBits(pDIBitmap, bitmap_alpha, 0, &m, 0, &dummy); 2462 return; 2463 #else 2464 pDIBitmap->MultiplyAlpha(bitmap_alpha); 2465 #endif 2466 } 2467 #ifdef _SKIA_SUPPORT_ 2468 CFX_SkiaDeviceDriver::PreMultiply(pDIBitmap); 2469 #endif 2470 if (m_pDevice->SetDIBits(pDIBitmap, left, top)) { 2471 return; 2472 } 2473 } else { 2474 uint32_t fill_argb = m_Options.TranslateColor(mask_argb); 2475 if (bitmap_alpha < 255) { 2476 uint8_t* fill_argb8 = reinterpret_cast<uint8_t*>(&fill_argb); 2477 fill_argb8[3] *= bitmap_alpha / 255; 2478 } 2479 if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) { 2480 return; 2481 } 2482 } 2483 } 2484 bool bIsolated = !!(iTransparency & PDFTRANS_ISOLATED); 2485 bool bGroup = !!(iTransparency & PDFTRANS_GROUP); 2486 bool bBackAlphaRequired = blend_mode && bIsolated && !m_bDropObjects; 2487 bool bGetBackGround = 2488 ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) || 2489 (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) && 2490 (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired); 2491 if (bGetBackGround) { 2492 if (bIsolated || !bGroup) { 2493 if (!pDIBitmap->IsAlphaMask()) 2494 m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode); 2495 return; 2496 } 2497 2498 FX_RECT rect(left, top, left + pDIBitmap->GetWidth(), 2499 top + pDIBitmap->GetHeight()); 2500 rect.Intersect(m_pDevice->GetClipBox()); 2501 RetainPtr<CFX_DIBitmap> pClone; 2502 if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) { 2503 pClone = m_pDevice->GetBackDrop()->Clone(&rect); 2504 if (!pClone) 2505 return; 2506 2507 RetainPtr<CFX_DIBitmap> pForeBitmap = m_pDevice->GetBitmap(); 2508 pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(), 2509 pForeBitmap, rect.left, rect.top); 2510 left = std::min(left, 0); 2511 top = std::min(top, 0); 2512 if (pDIBitmap->IsAlphaMask()) { 2513 pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(), 2514 pDIBitmap, mask_argb, left, top, blend_mode); 2515 } else { 2516 pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(), 2517 pDIBitmap, left, top, blend_mode); 2518 } 2519 } else { 2520 pClone = pDIBitmap; 2521 } 2522 if (m_pDevice->GetBackDrop()) { 2523 m_pDevice->SetDIBits(pClone, rect.left, rect.top); 2524 } else { 2525 if (!pDIBitmap->IsAlphaMask()) { 2526 m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top, 2527 blend_mode); 2528 } 2529 } 2530 return; 2531 } 2532 int back_left; 2533 int back_top; 2534 FX_RECT rect(left, top, left + pDIBitmap->GetWidth(), 2535 top + pDIBitmap->GetHeight()); 2536 RetainPtr<CFX_DIBitmap> pBackdrop = 2537 GetBackdrop(m_pCurObj, rect, blend_mode > FXDIB_BLEND_NORMAL && bIsolated, 2538 &back_left, &back_top); 2539 if (!pBackdrop) 2540 return; 2541 2542 if (pDIBitmap->IsAlphaMask()) { 2543 pBackdrop->CompositeMask(left - back_left, top - back_top, 2544 pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), 2545 pDIBitmap, mask_argb, 0, 0, blend_mode); 2546 } else { 2547 pBackdrop->CompositeBitmap(left - back_left, top - back_top, 2548 pDIBitmap->GetWidth(), pDIBitmap->GetHeight(), 2549 pDIBitmap, 0, 0, blend_mode); 2550 } 2551 2552 auto pBackdrop1 = pdfium::MakeRetain<CFX_DIBitmap>(); 2553 pBackdrop1->Create(pBackdrop->GetWidth(), pBackdrop->GetHeight(), 2554 FXDIB_Rgb32); 2555 pBackdrop1->Clear((uint32_t)-1); 2556 pBackdrop1->CompositeBitmap(0, 0, pBackdrop->GetWidth(), 2557 pBackdrop->GetHeight(), pBackdrop, 0, 0); 2558 pBackdrop = std::move(pBackdrop1); 2559 m_pDevice->SetDIBits(pBackdrop, back_left, back_top); 2560 } 2561 2562 RetainPtr<CFX_DIBitmap> CPDF_RenderStatus::LoadSMask( 2563 CPDF_Dictionary* pSMaskDict, 2564 FX_RECT* pClipRect, 2565 const CFX_Matrix* pMatrix) { 2566 if (!pSMaskDict) 2567 return nullptr; 2568 2569 CPDF_Stream* pGroup = pSMaskDict->GetStreamFor("G"); 2570 if (!pGroup) 2571 return nullptr; 2572 2573 std::unique_ptr<CPDF_Function> pFunc; 2574 CPDF_Object* pFuncObj = pSMaskDict->GetDirectObjectFor("TR"); 2575 if (pFuncObj && (pFuncObj->IsDictionary() || pFuncObj->IsStream())) 2576 pFunc = CPDF_Function::Load(pFuncObj); 2577 2578 CFX_Matrix matrix = *pMatrix; 2579 matrix.Translate(-pClipRect->left, -pClipRect->top); 2580 2581 CPDF_Form form(m_pContext->GetDocument(), m_pContext->GetPageResources(), 2582 pGroup); 2583 form.ParseContent(); 2584 2585 CFX_DefaultRenderDevice bitmap_device; 2586 bool bLuminosity = pSMaskDict->GetStringFor("S") != "Alpha"; 2587 int width = pClipRect->right - pClipRect->left; 2588 int height = pClipRect->bottom - pClipRect->top; 2589 FXDIB_Format format; 2590 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_ || \ 2591 defined _SKIA_SUPPORT_PATHS_ 2592 format = bLuminosity ? FXDIB_Rgb32 : FXDIB_8bppMask; 2593 #else 2594 format = bLuminosity ? FXDIB_Rgb : FXDIB_8bppMask; 2595 #endif 2596 if (!bitmap_device.Create(width, height, format, nullptr)) 2597 return nullptr; 2598 2599 CFX_DIBitmap& bitmap = *bitmap_device.GetBitmap(); 2600 int color_space_family = 0; 2601 if (bLuminosity) { 2602 CPDF_Array* pBC = pSMaskDict->GetArrayFor("BC"); 2603 FX_ARGB back_color = 0xff000000; 2604 if (pBC) { 2605 CPDF_Object* pCSObj = nullptr; 2606 CPDF_Dictionary* pDict = pGroup->GetDict(); 2607 if (pDict && pDict->GetDictFor("Group")) { 2608 pCSObj = pDict->GetDictFor("Group")->GetDirectObjectFor("CS"); 2609 } 2610 const CPDF_ColorSpace* pCS = 2611 m_pContext->GetDocument()->LoadColorSpace(pCSObj); 2612 if (pCS) { 2613 // Store Color Space Family to use in CPDF_RenderStatus::Initialize. 2614 color_space_family = pCS->GetFamily(); 2615 2616 float R, G, B; 2617 uint32_t comps = 8; 2618 if (pCS->CountComponents() > comps) { 2619 comps = pCS->CountComponents(); 2620 } 2621 CFX_FixedBufGrow<float, 8> float_array(comps); 2622 float* pFloats = float_array; 2623 FX_SAFE_UINT32 num_floats = comps; 2624 num_floats *= sizeof(float); 2625 if (!num_floats.IsValid()) { 2626 return nullptr; 2627 } 2628 memset(pFloats, 0, num_floats.ValueOrDie()); 2629 size_t count = pBC->GetCount() > 8 ? 8 : pBC->GetCount(); 2630 for (size_t i = 0; i < count; i++) { 2631 pFloats[i] = pBC->GetNumberAt(i); 2632 } 2633 pCS->GetRGB(pFloats, &R, &G, &B); 2634 back_color = 0xff000000 | ((int32_t)(R * 255) << 16) | 2635 ((int32_t)(G * 255) << 8) | (int32_t)(B * 255); 2636 m_pContext->GetDocument()->GetPageData()->ReleaseColorSpace(pCSObj); 2637 } 2638 } 2639 bitmap.Clear(back_color); 2640 } else { 2641 bitmap.Clear(0); 2642 } 2643 CPDF_Dictionary* pFormResource = nullptr; 2644 if (form.m_pFormDict) { 2645 pFormResource = form.m_pFormDict->GetDictFor("Resources"); 2646 } 2647 CPDF_RenderOptions options; 2648 options.SetColorMode(bLuminosity ? CPDF_RenderOptions::kNormal 2649 : CPDF_RenderOptions::kAlpha); 2650 CPDF_RenderStatus status; 2651 status.Initialize(m_pContext.Get(), &bitmap_device, nullptr, nullptr, nullptr, 2652 nullptr, &options, 0, m_bDropObjects, pFormResource, true, 2653 nullptr, 0, color_space_family, bLuminosity); 2654 status.RenderObjectList(&form, &matrix); 2655 2656 auto pMask = pdfium::MakeRetain<CFX_DIBitmap>(); 2657 if (!pMask->Create(width, height, FXDIB_8bppMask)) 2658 return nullptr; 2659 2660 uint8_t* dest_buf = pMask->GetBuffer(); 2661 int dest_pitch = pMask->GetPitch(); 2662 uint8_t* src_buf = bitmap.GetBuffer(); 2663 int src_pitch = bitmap.GetPitch(); 2664 std::vector<uint8_t> transfers(256); 2665 if (pFunc) { 2666 CFX_FixedBufGrow<float, 16> results(pFunc->CountOutputs()); 2667 for (int i = 0; i < 256; i++) { 2668 float input = (float)i / 255.0f; 2669 int nresult; 2670 pFunc->Call(&input, 1, results, &nresult); 2671 transfers[i] = FXSYS_round(results[0] * 255); 2672 } 2673 } else { 2674 for (int i = 0; i < 256; i++) { 2675 transfers[i] = i; 2676 } 2677 } 2678 if (bLuminosity) { 2679 int Bpp = bitmap.GetBPP() / 8; 2680 for (int row = 0; row < height; row++) { 2681 uint8_t* dest_pos = dest_buf + row * dest_pitch; 2682 uint8_t* src_pos = src_buf + row * src_pitch; 2683 for (int col = 0; col < width; col++) { 2684 *dest_pos++ = transfers[FXRGB2GRAY(src_pos[2], src_pos[1], *src_pos)]; 2685 src_pos += Bpp; 2686 } 2687 } 2688 } else if (pFunc) { 2689 int size = dest_pitch * height; 2690 for (int i = 0; i < size; i++) { 2691 dest_buf[i] = transfers[src_buf[i]]; 2692 } 2693 } else { 2694 memcpy(dest_buf, src_buf, dest_pitch * height); 2695 } 2696 return pMask; 2697 } 2698