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 "render_int.h" 8 9 #include "core/include/fpdfapi/fpdf_pageobj.h" 10 #include "core/include/fpdfapi/fpdf_render.h" 11 #include "core/include/fxge/fx_ge.h" 12 #include "core/src/fpdfapi/fpdf_page/pageint.h" 13 14 #define SHADING_STEPS 256 15 static void DrawAxialShading(CFX_DIBitmap* pBitmap, 16 CFX_Matrix* pObject2Bitmap, 17 CPDF_Dictionary* pDict, 18 CPDF_Function** pFuncs, 19 int nFuncs, 20 CPDF_ColorSpace* pCS, 21 int alpha) { 22 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 23 CPDF_Array* pCoords = pDict->GetArray("Coords"); 24 if (!pCoords) { 25 return; 26 } 27 FX_FLOAT start_x = pCoords->GetNumber(0); 28 FX_FLOAT start_y = pCoords->GetNumber(1); 29 FX_FLOAT end_x = pCoords->GetNumber(2); 30 FX_FLOAT end_y = pCoords->GetNumber(3); 31 FX_FLOAT t_min = 0, t_max = 1.0f; 32 CPDF_Array* pArray = pDict->GetArray("Domain"); 33 if (pArray) { 34 t_min = pArray->GetNumber(0); 35 t_max = pArray->GetNumber(1); 36 } 37 FX_BOOL bStartExtend = FALSE, bEndExtend = FALSE; 38 pArray = pDict->GetArray("Extend"); 39 if (pArray) { 40 bStartExtend = pArray->GetInteger(0); 41 bEndExtend = pArray->GetInteger(1); 42 } 43 int width = pBitmap->GetWidth(); 44 int height = pBitmap->GetHeight(); 45 FX_FLOAT x_span = end_x - start_x; 46 FX_FLOAT y_span = end_y - start_y; 47 FX_FLOAT axis_len_square = 48 FXSYS_Mul(x_span, x_span) + FXSYS_Mul(y_span, y_span); 49 CFX_Matrix matrix; 50 matrix.SetReverse(*pObject2Bitmap); 51 int total_results = 0; 52 for (int j = 0; j < nFuncs; j++) { 53 if (pFuncs[j]) { 54 total_results += pFuncs[j]->CountOutputs(); 55 } 56 } 57 if (pCS->CountComponents() > total_results) { 58 total_results = pCS->CountComponents(); 59 } 60 CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results); 61 FX_FLOAT* pResults = result_array; 62 FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT)); 63 FX_DWORD rgb_array[SHADING_STEPS]; 64 for (int i = 0; i < SHADING_STEPS; i++) { 65 FX_FLOAT input = (t_max - t_min) * i / SHADING_STEPS + t_min; 66 int offset = 0; 67 for (int j = 0; j < nFuncs; j++) { 68 if (pFuncs[j]) { 69 int nresults = 0; 70 if (pFuncs[j]->Call(&input, 1, pResults + offset, nresults)) { 71 offset += nresults; 72 } 73 } 74 } 75 FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f; 76 pCS->GetRGB(pResults, R, G, B); 77 rgb_array[i] = 78 FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255), 79 FXSYS_round(G * 255), FXSYS_round(B * 255))); 80 } 81 int pitch = pBitmap->GetPitch(); 82 for (int row = 0; row < height; row++) { 83 FX_DWORD* dib_buf = (FX_DWORD*)(pBitmap->GetBuffer() + row * pitch); 84 for (int column = 0; column < width; column++) { 85 FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row; 86 matrix.Transform(x, y); 87 FX_FLOAT scale = FXSYS_Div( 88 FXSYS_Mul(x - start_x, x_span) + FXSYS_Mul(y - start_y, y_span), 89 axis_len_square); 90 int index = (int32_t)(scale * (SHADING_STEPS - 1)); 91 if (index < 0) { 92 if (!bStartExtend) { 93 continue; 94 } 95 index = 0; 96 } else if (index >= SHADING_STEPS) { 97 if (!bEndExtend) { 98 continue; 99 } 100 index = SHADING_STEPS - 1; 101 } 102 dib_buf[column] = rgb_array[index]; 103 } 104 } 105 } 106 static void DrawRadialShading(CFX_DIBitmap* pBitmap, 107 CFX_Matrix* pObject2Bitmap, 108 CPDF_Dictionary* pDict, 109 CPDF_Function** pFuncs, 110 int nFuncs, 111 CPDF_ColorSpace* pCS, 112 int alpha) { 113 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 114 CPDF_Array* pCoords = pDict->GetArray("Coords"); 115 if (!pCoords) { 116 return; 117 } 118 FX_FLOAT start_x = pCoords->GetNumber(0); 119 FX_FLOAT start_y = pCoords->GetNumber(1); 120 FX_FLOAT start_r = pCoords->GetNumber(2); 121 FX_FLOAT end_x = pCoords->GetNumber(3); 122 FX_FLOAT end_y = pCoords->GetNumber(4); 123 FX_FLOAT end_r = pCoords->GetNumber(5); 124 CFX_Matrix matrix; 125 matrix.SetReverse(*pObject2Bitmap); 126 FX_FLOAT t_min = 0, t_max = 1.0f; 127 CPDF_Array* pArray = pDict->GetArray("Domain"); 128 if (pArray) { 129 t_min = pArray->GetNumber(0); 130 t_max = pArray->GetNumber(1); 131 } 132 FX_BOOL bStartExtend = FALSE, bEndExtend = FALSE; 133 pArray = pDict->GetArray("Extend"); 134 if (pArray) { 135 bStartExtend = pArray->GetInteger(0); 136 bEndExtend = pArray->GetInteger(1); 137 } 138 int total_results = 0; 139 for (int j = 0; j < nFuncs; j++) { 140 if (pFuncs[j]) { 141 total_results += pFuncs[j]->CountOutputs(); 142 } 143 } 144 if (pCS->CountComponents() > total_results) { 145 total_results = pCS->CountComponents(); 146 } 147 CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results); 148 FX_FLOAT* pResults = result_array; 149 FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT)); 150 FX_DWORD rgb_array[SHADING_STEPS]; 151 for (int i = 0; i < SHADING_STEPS; i++) { 152 FX_FLOAT input = (t_max - t_min) * i / SHADING_STEPS + t_min; 153 int offset = 0; 154 for (int j = 0; j < nFuncs; j++) { 155 if (pFuncs[j]) { 156 int nresults; 157 if (pFuncs[j]->Call(&input, 1, pResults + offset, nresults)) { 158 offset += nresults; 159 } 160 } 161 } 162 FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f; 163 pCS->GetRGB(pResults, R, G, B); 164 rgb_array[i] = 165 FXARGB_TODIB(FXARGB_MAKE(alpha, FXSYS_round(R * 255), 166 FXSYS_round(G * 255), FXSYS_round(B * 255))); 167 } 168 FX_FLOAT a = FXSYS_Mul(start_x - end_x, start_x - end_x) + 169 FXSYS_Mul(start_y - end_y, start_y - end_y) - 170 FXSYS_Mul(start_r - end_r, start_r - end_r); 171 int width = pBitmap->GetWidth(); 172 int height = pBitmap->GetHeight(); 173 int pitch = pBitmap->GetPitch(); 174 FX_BOOL bDecreasing = FALSE; 175 if (start_r > end_r) { 176 int length = (int)FXSYS_sqrt((FXSYS_Mul(start_x - end_x, start_x - end_x) + 177 FXSYS_Mul(start_y - end_y, start_y - end_y))); 178 if (length < start_r - end_r) { 179 bDecreasing = TRUE; 180 } 181 } 182 for (int row = 0; row < height; row++) { 183 FX_DWORD* dib_buf = (FX_DWORD*)(pBitmap->GetBuffer() + row * pitch); 184 for (int column = 0; column < width; column++) { 185 FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row; 186 matrix.Transform(x, y); 187 FX_FLOAT b = -2 * (FXSYS_Mul(x - start_x, end_x - start_x) + 188 FXSYS_Mul(y - start_y, end_y - start_y) + 189 FXSYS_Mul(start_r, end_r - start_r)); 190 FX_FLOAT c = FXSYS_Mul(x - start_x, x - start_x) + 191 FXSYS_Mul(y - start_y, y - start_y) - 192 FXSYS_Mul(start_r, start_r); 193 FX_FLOAT s; 194 if (a == 0) { 195 s = FXSYS_Div(-c, b); 196 } else { 197 FX_FLOAT b2_4ac = FXSYS_Mul(b, b) - 4 * FXSYS_Mul(a, c); 198 if (b2_4ac < 0) { 199 continue; 200 } 201 FX_FLOAT root = FXSYS_sqrt(b2_4ac); 202 FX_FLOAT s1, s2; 203 if (a > 0) { 204 s1 = FXSYS_Div(-b - root, 2 * a); 205 s2 = FXSYS_Div(-b + root, 2 * a); 206 } else { 207 s2 = FXSYS_Div(-b - root, 2 * a); 208 s1 = FXSYS_Div(-b + root, 2 * a); 209 } 210 if (bDecreasing) { 211 if (s1 >= 0 || bStartExtend) { 212 s = s1; 213 } else { 214 s = s2; 215 } 216 } else { 217 if (s2 <= 1.0f || bEndExtend) { 218 s = s2; 219 } else { 220 s = s1; 221 } 222 } 223 if ((start_r + s * (end_r - start_r)) < 0) { 224 continue; 225 } 226 } 227 int index = (int32_t)(s * (SHADING_STEPS - 1)); 228 if (index < 0) { 229 if (!bStartExtend) { 230 continue; 231 } 232 index = 0; 233 } 234 if (index >= SHADING_STEPS) { 235 if (!bEndExtend) { 236 continue; 237 } 238 index = SHADING_STEPS - 1; 239 } 240 dib_buf[column] = rgb_array[index]; 241 } 242 } 243 } 244 static void DrawFuncShading(CFX_DIBitmap* pBitmap, 245 CFX_Matrix* pObject2Bitmap, 246 CPDF_Dictionary* pDict, 247 CPDF_Function** pFuncs, 248 int nFuncs, 249 CPDF_ColorSpace* pCS, 250 int alpha) { 251 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 252 CPDF_Array* pDomain = pDict->GetArray("Domain"); 253 FX_FLOAT xmin = 0, ymin = 0, xmax = 1.0f, ymax = 1.0f; 254 if (pDomain) { 255 xmin = pDomain->GetNumber(0); 256 xmax = pDomain->GetNumber(1); 257 ymin = pDomain->GetNumber(2); 258 ymax = pDomain->GetNumber(3); 259 } 260 CFX_Matrix mtDomain2Target = pDict->GetMatrix("Matrix"); 261 CFX_Matrix matrix, reverse_matrix; 262 matrix.SetReverse(*pObject2Bitmap); 263 reverse_matrix.SetReverse(mtDomain2Target); 264 matrix.Concat(reverse_matrix); 265 int width = pBitmap->GetWidth(); 266 int height = pBitmap->GetHeight(); 267 int pitch = pBitmap->GetPitch(); 268 int total_results = 0; 269 for (int j = 0; j < nFuncs; j++) { 270 if (pFuncs[j]) { 271 total_results += pFuncs[j]->CountOutputs(); 272 } 273 } 274 if (pCS->CountComponents() > total_results) { 275 total_results = pCS->CountComponents(); 276 } 277 CFX_FixedBufGrow<FX_FLOAT, 16> result_array(total_results); 278 FX_FLOAT* pResults = result_array; 279 FXSYS_memset(pResults, 0, total_results * sizeof(FX_FLOAT)); 280 for (int row = 0; row < height; row++) { 281 FX_DWORD* dib_buf = (FX_DWORD*)(pBitmap->GetBuffer() + row * pitch); 282 for (int column = 0; column < width; column++) { 283 FX_FLOAT x = (FX_FLOAT)column, y = (FX_FLOAT)row; 284 matrix.Transform(x, y); 285 if (x < xmin || x > xmax || y < ymin || y > ymax) { 286 continue; 287 } 288 FX_FLOAT input[2]; 289 int offset = 0; 290 input[0] = x; 291 input[1] = y; 292 for (int j = 0; j < nFuncs; j++) { 293 if (pFuncs[j]) { 294 int nresults; 295 if (pFuncs[j]->Call(input, 2, pResults + offset, nresults)) { 296 offset += nresults; 297 } 298 } 299 } 300 FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f; 301 pCS->GetRGB(pResults, R, G, B); 302 dib_buf[column] = FXARGB_TODIB(FXARGB_MAKE( 303 alpha, (int32_t)(R * 255), (int32_t)(G * 255), (int32_t)(B * 255))); 304 } 305 } 306 } 307 FX_BOOL _GetScanlineIntersect(int y, 308 FX_FLOAT x1, 309 FX_FLOAT y1, 310 FX_FLOAT x2, 311 FX_FLOAT y2, 312 FX_FLOAT& x) { 313 if (y1 == y2) { 314 return FALSE; 315 } 316 if (y1 < y2) { 317 if (y < y1 || y > y2) { 318 return FALSE; 319 } 320 } else { 321 if (y < y2 || y > y1) { 322 return FALSE; 323 } 324 } 325 x = x1 + FXSYS_MulDiv(x2 - x1, y - y1, y2 - y1); 326 return TRUE; 327 } 328 static void DrawGouraud(CFX_DIBitmap* pBitmap, 329 int alpha, 330 CPDF_MeshVertex triangle[3]) { 331 FX_FLOAT min_y = triangle[0].y, max_y = triangle[0].y; 332 for (int i = 1; i < 3; i++) { 333 if (min_y > triangle[i].y) { 334 min_y = triangle[i].y; 335 } 336 if (max_y < triangle[i].y) { 337 max_y = triangle[i].y; 338 } 339 } 340 if (min_y == max_y) { 341 return; 342 } 343 int min_yi = (int)FXSYS_floor(min_y), max_yi = (int)FXSYS_ceil(max_y); 344 if (min_yi < 0) { 345 min_yi = 0; 346 } 347 if (max_yi >= pBitmap->GetHeight()) { 348 max_yi = pBitmap->GetHeight() - 1; 349 } 350 for (int y = min_yi; y <= max_yi; y++) { 351 int nIntersects = 0; 352 FX_FLOAT inter_x[3], r[3], g[3], b[3]; 353 for (int i = 0; i < 3; i++) { 354 CPDF_MeshVertex& vertex1 = triangle[i]; 355 CPDF_MeshVertex& vertex2 = triangle[(i + 1) % 3]; 356 FX_BOOL bIntersect = _GetScanlineIntersect( 357 y, vertex1.x, vertex1.y, vertex2.x, vertex2.y, inter_x[nIntersects]); 358 if (!bIntersect) { 359 continue; 360 } 361 r[nIntersects] = 362 vertex1.r + FXSYS_MulDiv(vertex2.r - vertex1.r, y - vertex1.y, 363 vertex2.y - vertex1.y); 364 g[nIntersects] = 365 vertex1.g + FXSYS_MulDiv(vertex2.g - vertex1.g, y - vertex1.y, 366 vertex2.y - vertex1.y); 367 b[nIntersects] = 368 vertex1.b + FXSYS_MulDiv(vertex2.b - vertex1.b, y - vertex1.y, 369 vertex2.y - vertex1.y); 370 nIntersects++; 371 } 372 if (nIntersects != 2) { 373 continue; 374 } 375 int min_x, max_x, start_index, end_index; 376 if (inter_x[0] < inter_x[1]) { 377 min_x = (int)FXSYS_floor(inter_x[0]); 378 max_x = (int)FXSYS_ceil(inter_x[1]); 379 start_index = 0; 380 end_index = 1; 381 } else { 382 min_x = (int)FXSYS_floor(inter_x[1]); 383 max_x = (int)FXSYS_ceil(inter_x[0]); 384 start_index = 1; 385 end_index = 0; 386 } 387 int start_x = min_x, end_x = max_x; 388 if (start_x < 0) { 389 start_x = 0; 390 } 391 if (end_x > pBitmap->GetWidth()) { 392 end_x = pBitmap->GetWidth(); 393 } 394 uint8_t* dib_buf = 395 pBitmap->GetBuffer() + y * pBitmap->GetPitch() + start_x * 4; 396 FX_FLOAT r_unit = (r[end_index] - r[start_index]) / (max_x - min_x); 397 FX_FLOAT g_unit = (g[end_index] - g[start_index]) / (max_x - min_x); 398 FX_FLOAT b_unit = (b[end_index] - b[start_index]) / (max_x - min_x); 399 FX_FLOAT R = r[start_index] + (start_x - min_x) * r_unit; 400 FX_FLOAT G = g[start_index] + (start_x - min_x) * g_unit; 401 FX_FLOAT B = b[start_index] + (start_x - min_x) * b_unit; 402 for (int x = start_x; x < end_x; x++) { 403 R += r_unit; 404 G += g_unit; 405 B += b_unit; 406 FXARGB_SETDIB(dib_buf, 407 FXARGB_MAKE(alpha, (int32_t)(R * 255), (int32_t)(G * 255), 408 (int32_t)(B * 255))); 409 dib_buf += 4; 410 } 411 } 412 } 413 static void DrawFreeGouraudShading(CFX_DIBitmap* pBitmap, 414 CFX_Matrix* pObject2Bitmap, 415 CPDF_Stream* pShadingStream, 416 CPDF_Function** pFuncs, 417 int nFuncs, 418 CPDF_ColorSpace* pCS, 419 int alpha) { 420 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 421 422 CPDF_MeshStream stream; 423 if (!stream.Load(pShadingStream, pFuncs, nFuncs, pCS)) 424 return; 425 426 CPDF_MeshVertex triangle[3]; 427 FXSYS_memset(triangle, 0, sizeof(triangle)); 428 429 while (!stream.m_BitStream.IsEOF()) { 430 CPDF_MeshVertex vertex; 431 FX_DWORD flag = stream.GetVertex(vertex, pObject2Bitmap); 432 if (flag == 0) { 433 triangle[0] = vertex; 434 for (int j = 1; j < 3; j++) { 435 stream.GetVertex(triangle[j], pObject2Bitmap); 436 } 437 } else { 438 if (flag == 1) { 439 triangle[0] = triangle[1]; 440 } 441 triangle[1] = triangle[2]; 442 triangle[2] = vertex; 443 } 444 DrawGouraud(pBitmap, alpha, triangle); 445 } 446 } 447 static void DrawLatticeGouraudShading(CFX_DIBitmap* pBitmap, 448 CFX_Matrix* pObject2Bitmap, 449 CPDF_Stream* pShadingStream, 450 CPDF_Function** pFuncs, 451 int nFuncs, 452 CPDF_ColorSpace* pCS, 453 int alpha) { 454 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 455 456 int row_verts = pShadingStream->GetDict()->GetInteger("VerticesPerRow"); 457 if (row_verts < 2) 458 return; 459 460 CPDF_MeshStream stream; 461 if (!stream.Load(pShadingStream, pFuncs, nFuncs, pCS)) 462 return; 463 464 CPDF_MeshVertex* vertex = FX_Alloc2D(CPDF_MeshVertex, row_verts, 2); 465 if (!stream.GetVertexRow(vertex, row_verts, pObject2Bitmap)) { 466 FX_Free(vertex); 467 return; 468 } 469 int last_index = 0; 470 while (1) { 471 CPDF_MeshVertex* last_row = vertex + last_index * row_verts; 472 CPDF_MeshVertex* this_row = vertex + (1 - last_index) * row_verts; 473 if (!stream.GetVertexRow(this_row, row_verts, pObject2Bitmap)) { 474 FX_Free(vertex); 475 return; 476 } 477 CPDF_MeshVertex triangle[3]; 478 for (int i = 1; i < row_verts; i++) { 479 triangle[0] = last_row[i]; 480 triangle[1] = this_row[i - 1]; 481 triangle[2] = last_row[i - 1]; 482 DrawGouraud(pBitmap, alpha, triangle); 483 triangle[2] = this_row[i]; 484 DrawGouraud(pBitmap, alpha, triangle); 485 } 486 last_index = 1 - last_index; 487 } 488 FX_Free(vertex); 489 } 490 struct Coon_BezierCoeff { 491 float a, b, c, d; 492 void FromPoints(float p0, float p1, float p2, float p3) { 493 a = -p0 + 3 * p1 - 3 * p2 + p3; 494 b = 3 * p0 - 6 * p1 + 3 * p2; 495 c = -3 * p0 + 3 * p1; 496 d = p0; 497 } 498 Coon_BezierCoeff first_half() { 499 Coon_BezierCoeff result; 500 result.a = a / 8; 501 result.b = b / 4; 502 result.c = c / 2; 503 result.d = d; 504 return result; 505 } 506 Coon_BezierCoeff second_half() { 507 Coon_BezierCoeff result; 508 result.a = a / 8; 509 result.b = 3 * a / 8 + b / 4; 510 result.c = 3 * a / 8 + b / 2 + c / 2; 511 result.d = a / 8 + b / 4 + c / 2 + d; 512 return result; 513 } 514 void GetPoints(float p[4]) { 515 p[0] = d; 516 p[1] = c / 3 + p[0]; 517 p[2] = b / 3 - p[0] + 2 * p[1]; 518 p[3] = a + p[0] - 3 * p[1] + 3 * p[2]; 519 } 520 void GetPointsReverse(float p[4]) { 521 p[3] = d; 522 p[2] = c / 3 + p[3]; 523 p[1] = b / 3 - p[3] + 2 * p[2]; 524 p[0] = a + p[3] - 3 * p[2] + 3 * p[1]; 525 } 526 void BezierInterpol(Coon_BezierCoeff& C1, 527 Coon_BezierCoeff& C2, 528 Coon_BezierCoeff& D1, 529 Coon_BezierCoeff& D2) { 530 a = (D1.a + D2.a) / 2; 531 b = (D1.b + D2.b) / 2; 532 c = (D1.c + D2.c) / 2 - (C1.a / 8 + C1.b / 4 + C1.c / 2) + 533 (C2.a / 8 + C2.b / 4) + (-C1.d + D2.d) / 2 - (C2.a + C2.b) / 2; 534 d = C1.a / 8 + C1.b / 4 + C1.c / 2 + C1.d; 535 } 536 float Distance() { 537 float dis = a + b + c; 538 return dis < 0 ? -dis : dis; 539 } 540 }; 541 struct Coon_Bezier { 542 Coon_BezierCoeff x, y; 543 void FromPoints(float x0, 544 float y0, 545 float x1, 546 float y1, 547 float x2, 548 float y2, 549 float x3, 550 float y3) { 551 x.FromPoints(x0, x1, x2, x3); 552 y.FromPoints(y0, y1, y2, y3); 553 } 554 Coon_Bezier first_half() { 555 Coon_Bezier result; 556 result.x = x.first_half(); 557 result.y = y.first_half(); 558 return result; 559 } 560 Coon_Bezier second_half() { 561 Coon_Bezier result; 562 result.x = x.second_half(); 563 result.y = y.second_half(); 564 return result; 565 } 566 void BezierInterpol(Coon_Bezier& C1, 567 Coon_Bezier& C2, 568 Coon_Bezier& D1, 569 Coon_Bezier& D2) { 570 x.BezierInterpol(C1.x, C2.x, D1.x, D2.x); 571 y.BezierInterpol(C1.y, C2.y, D1.y, D2.y); 572 } 573 void GetPoints(FX_PATHPOINT* pPoints) { 574 float p[4]; 575 int i; 576 x.GetPoints(p); 577 for (i = 0; i < 4; i++) { 578 pPoints[i].m_PointX = p[i]; 579 } 580 y.GetPoints(p); 581 for (i = 0; i < 4; i++) { 582 pPoints[i].m_PointY = p[i]; 583 } 584 } 585 void GetPointsReverse(FX_PATHPOINT* pPoints) { 586 float p[4]; 587 int i; 588 x.GetPointsReverse(p); 589 for (i = 0; i < 4; i++) { 590 pPoints[i].m_PointX = p[i]; 591 } 592 y.GetPointsReverse(p); 593 for (i = 0; i < 4; i++) { 594 pPoints[i].m_PointY = p[i]; 595 } 596 } 597 float Distance() { return x.Distance() + y.Distance(); } 598 }; 599 static int _BiInterpol(int c0, 600 int c1, 601 int c2, 602 int c3, 603 int x, 604 int y, 605 int x_scale, 606 int y_scale) { 607 int x1 = c0 + (c3 - c0) * x / x_scale; 608 int x2 = c1 + (c2 - c1) * x / x_scale; 609 return x1 + (x2 - x1) * y / y_scale; 610 } 611 struct Coon_Color { 612 Coon_Color() { FXSYS_memset(comp, 0, sizeof(int) * 3); } 613 int comp[3]; 614 void BiInterpol(Coon_Color colors[4], 615 int x, 616 int y, 617 int x_scale, 618 int y_scale) { 619 for (int i = 0; i < 3; i++) 620 comp[i] = 621 _BiInterpol(colors[0].comp[i], colors[1].comp[i], colors[2].comp[i], 622 colors[3].comp[i], x, y, x_scale, y_scale); 623 } 624 int Distance(Coon_Color& o) { 625 int max, diff; 626 max = FXSYS_abs(comp[0] - o.comp[0]); 627 diff = FXSYS_abs(comp[1] - o.comp[1]); 628 if (max < diff) { 629 max = diff; 630 } 631 diff = FXSYS_abs(comp[2] - o.comp[2]); 632 if (max < diff) { 633 max = diff; 634 } 635 return max; 636 } 637 }; 638 struct CPDF_PatchDrawer { 639 Coon_Color patch_colors[4]; 640 int max_delta; 641 CFX_PathData path; 642 CFX_RenderDevice* pDevice; 643 int fill_mode; 644 int alpha; 645 void Draw(int x_scale, 646 int y_scale, 647 int left, 648 int bottom, 649 Coon_Bezier C1, 650 Coon_Bezier C2, 651 Coon_Bezier D1, 652 Coon_Bezier D2) { 653 FX_BOOL bSmall = C1.Distance() < 2 && C2.Distance() < 2 && 654 D1.Distance() < 2 && D2.Distance() < 2; 655 Coon_Color div_colors[4]; 656 int d_bottom, d_left, d_top, d_right; 657 div_colors[0].BiInterpol(patch_colors, left, bottom, x_scale, y_scale); 658 if (!bSmall) { 659 div_colors[1].BiInterpol(patch_colors, left, bottom + 1, x_scale, 660 y_scale); 661 div_colors[2].BiInterpol(patch_colors, left + 1, bottom + 1, x_scale, 662 y_scale); 663 div_colors[3].BiInterpol(patch_colors, left + 1, bottom, x_scale, 664 y_scale); 665 d_bottom = div_colors[3].Distance(div_colors[0]); 666 d_left = div_colors[1].Distance(div_colors[0]); 667 d_top = div_colors[1].Distance(div_colors[2]); 668 d_right = div_colors[2].Distance(div_colors[3]); 669 } 670 #define COONCOLOR_THRESHOLD 4 671 if (bSmall || 672 (d_bottom < COONCOLOR_THRESHOLD && d_left < COONCOLOR_THRESHOLD && 673 d_top < COONCOLOR_THRESHOLD && d_right < COONCOLOR_THRESHOLD)) { 674 FX_PATHPOINT* pPoints = path.GetPoints(); 675 C1.GetPoints(pPoints); 676 D2.GetPoints(pPoints + 3); 677 C2.GetPointsReverse(pPoints + 6); 678 D1.GetPointsReverse(pPoints + 9); 679 int fillFlags = FXFILL_WINDING | FXFILL_FULLCOVER; 680 if (fill_mode & RENDER_NOPATHSMOOTH) { 681 fillFlags |= FXFILL_NOPATHSMOOTH; 682 } 683 pDevice->DrawPath( 684 &path, NULL, NULL, 685 FXARGB_MAKE(alpha, div_colors[0].comp[0], div_colors[0].comp[1], 686 div_colors[0].comp[2]), 687 0, fillFlags); 688 } else { 689 if (d_bottom < COONCOLOR_THRESHOLD && d_top < COONCOLOR_THRESHOLD) { 690 Coon_Bezier m1; 691 m1.BezierInterpol(D1, D2, C1, C2); 692 y_scale *= 2; 693 bottom *= 2; 694 Draw(x_scale, y_scale, left, bottom, C1, m1, D1.first_half(), 695 D2.first_half()); 696 Draw(x_scale, y_scale, left, bottom + 1, m1, C2, D1.second_half(), 697 D2.second_half()); 698 } else if (d_left < COONCOLOR_THRESHOLD && 699 d_right < COONCOLOR_THRESHOLD) { 700 Coon_Bezier m2; 701 m2.BezierInterpol(C1, C2, D1, D2); 702 x_scale *= 2; 703 left *= 2; 704 Draw(x_scale, y_scale, left, bottom, C1.first_half(), C2.first_half(), 705 D1, m2); 706 Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(), 707 C2.second_half(), m2, D2); 708 } else { 709 Coon_Bezier m1, m2; 710 m1.BezierInterpol(D1, D2, C1, C2); 711 m2.BezierInterpol(C1, C2, D1, D2); 712 Coon_Bezier m1f = m1.first_half(); 713 Coon_Bezier m1s = m1.second_half(); 714 Coon_Bezier m2f = m2.first_half(); 715 Coon_Bezier m2s = m2.second_half(); 716 x_scale *= 2; 717 y_scale *= 2; 718 left *= 2; 719 bottom *= 2; 720 Draw(x_scale, y_scale, left, bottom, C1.first_half(), m1f, 721 D1.first_half(), m2f); 722 Draw(x_scale, y_scale, left, bottom + 1, m1f, C2.first_half(), 723 D1.second_half(), m2s); 724 Draw(x_scale, y_scale, left + 1, bottom, C1.second_half(), m1s, m2f, 725 D2.first_half()); 726 Draw(x_scale, y_scale, left + 1, bottom + 1, m1s, C2.second_half(), m2s, 727 D2.second_half()); 728 } 729 } 730 } 731 }; 732 733 FX_BOOL _CheckCoonTensorPara(const CPDF_MeshStream& stream) { 734 FX_BOOL bCoorBits = (stream.m_nCoordBits == 1 || stream.m_nCoordBits == 2 || 735 stream.m_nCoordBits == 4 || stream.m_nCoordBits == 8 || 736 stream.m_nCoordBits == 12 || stream.m_nCoordBits == 16 || 737 stream.m_nCoordBits == 24 || stream.m_nCoordBits == 32); 738 739 FX_BOOL bCompBits = (stream.m_nCompBits == 1 || stream.m_nCompBits == 2 || 740 stream.m_nCompBits == 4 || stream.m_nCompBits == 8 || 741 stream.m_nCompBits == 12 || stream.m_nCompBits == 16); 742 743 FX_BOOL bFlagBits = (stream.m_nFlagBits == 2 || stream.m_nFlagBits == 4 || 744 stream.m_nFlagBits == 8); 745 746 return bCoorBits && bCompBits && bFlagBits; 747 } 748 749 static void DrawCoonPatchMeshes(FX_BOOL bTensor, 750 CFX_DIBitmap* pBitmap, 751 CFX_Matrix* pObject2Bitmap, 752 CPDF_Stream* pShadingStream, 753 CPDF_Function** pFuncs, 754 int nFuncs, 755 CPDF_ColorSpace* pCS, 756 int fill_mode, 757 int alpha) { 758 ASSERT(pBitmap->GetFormat() == FXDIB_Argb); 759 760 CFX_FxgeDevice device; 761 device.Attach(pBitmap); 762 CPDF_MeshStream stream; 763 if (!stream.Load(pShadingStream, pFuncs, nFuncs, pCS)) 764 return; 765 if (!_CheckCoonTensorPara(stream)) 766 return; 767 768 CPDF_PatchDrawer patch; 769 patch.alpha = alpha; 770 patch.pDevice = &device; 771 patch.fill_mode = fill_mode; 772 patch.path.SetPointCount(13); 773 FX_PATHPOINT* pPoints = patch.path.GetPoints(); 774 pPoints[0].m_Flag = FXPT_MOVETO; 775 for (int i = 1; i < 13; i++) { 776 pPoints[i].m_Flag = FXPT_BEZIERTO; 777 } 778 CFX_FloatPoint coords[16]; 779 for (int i = 0; i < 16; i++) { 780 coords[i].Set(0.0f, 0.0f); 781 } 782 783 int point_count = bTensor ? 16 : 12; 784 while (!stream.m_BitStream.IsEOF()) { 785 FX_DWORD flag = stream.GetFlag(); 786 int iStartPoint = 0, iStartColor = 0, i = 0; 787 if (flag) { 788 iStartPoint = 4; 789 iStartColor = 2; 790 CFX_FloatPoint tempCoords[4]; 791 for (i = 0; i < 4; i++) { 792 tempCoords[i] = coords[(flag * 3 + i) % 12]; 793 } 794 FXSYS_memcpy(coords, tempCoords, sizeof(CFX_FloatPoint) * 4); 795 Coon_Color tempColors[2]; 796 tempColors[0] = patch.patch_colors[flag]; 797 tempColors[1] = patch.patch_colors[(flag + 1) % 4]; 798 FXSYS_memcpy(patch.patch_colors, tempColors, sizeof(Coon_Color) * 2); 799 } 800 for (i = iStartPoint; i < point_count; i++) { 801 stream.GetCoords(coords[i].x, coords[i].y); 802 pObject2Bitmap->Transform(coords[i].x, coords[i].y); 803 } 804 for (i = iStartColor; i < 4; i++) { 805 FX_FLOAT r = 0.0f, g = 0.0f, b = 0.0f; 806 stream.GetColor(r, g, b); 807 patch.patch_colors[i].comp[0] = (int32_t)(r * 255); 808 patch.patch_colors[i].comp[1] = (int32_t)(g * 255); 809 patch.patch_colors[i].comp[2] = (int32_t)(b * 255); 810 } 811 CFX_FloatRect bbox = CFX_FloatRect::GetBBox(coords, point_count); 812 if (bbox.right <= 0 || bbox.left >= (FX_FLOAT)pBitmap->GetWidth() || 813 bbox.top <= 0 || bbox.bottom >= (FX_FLOAT)pBitmap->GetHeight()) { 814 continue; 815 } 816 Coon_Bezier C1, C2, D1, D2; 817 C1.FromPoints(coords[0].x, coords[0].y, coords[11].x, coords[11].y, 818 coords[10].x, coords[10].y, coords[9].x, coords[9].y); 819 C2.FromPoints(coords[3].x, coords[3].y, coords[4].x, coords[4].y, 820 coords[5].x, coords[5].y, coords[6].x, coords[6].y); 821 D1.FromPoints(coords[0].x, coords[0].y, coords[1].x, coords[1].y, 822 coords[2].x, coords[2].y, coords[3].x, coords[3].y); 823 D2.FromPoints(coords[9].x, coords[9].y, coords[8].x, coords[8].y, 824 coords[7].x, coords[7].y, coords[6].x, coords[6].y); 825 patch.Draw(1, 1, 0, 0, C1, C2, D1, D2); 826 } 827 } 828 void CPDF_RenderStatus::DrawShading(CPDF_ShadingPattern* pPattern, 829 CFX_Matrix* pMatrix, 830 FX_RECT& clip_rect, 831 int alpha, 832 FX_BOOL bAlphaMode) { 833 CPDF_Function** pFuncs = pPattern->m_pFunctions; 834 int nFuncs = pPattern->m_nFuncs; 835 CPDF_Dictionary* pDict = pPattern->m_pShadingObj->GetDict(); 836 CPDF_ColorSpace* pColorSpace = pPattern->m_pCS; 837 if (!pColorSpace) { 838 return; 839 } 840 FX_ARGB background = 0; 841 if (!pPattern->m_bShadingObj && 842 pPattern->m_pShadingObj->GetDict()->KeyExist("Background")) { 843 CPDF_Array* pBackColor = 844 pPattern->m_pShadingObj->GetDict()->GetArray("Background"); 845 if (pBackColor && 846 pBackColor->GetCount() >= (FX_DWORD)pColorSpace->CountComponents()) { 847 CFX_FixedBufGrow<FX_FLOAT, 16> comps(pColorSpace->CountComponents()); 848 for (int i = 0; i < pColorSpace->CountComponents(); i++) { 849 comps[i] = pBackColor->GetNumber(i); 850 } 851 FX_FLOAT R = 0.0f, G = 0.0f, B = 0.0f; 852 pColorSpace->GetRGB(comps, R, G, B); 853 background = ArgbEncode(255, (int32_t)(R * 255), (int32_t)(G * 255), 854 (int32_t)(B * 255)); 855 } 856 } 857 if (pDict->KeyExist("BBox")) { 858 CFX_FloatRect rect = pDict->GetRect("BBox"); 859 rect.Transform(pMatrix); 860 clip_rect.Intersect(rect.GetOutterRect()); 861 } 862 CPDF_DeviceBuffer buffer; 863 buffer.Initialize(m_pContext, m_pDevice, &clip_rect, m_pCurObj, 150); 864 CFX_Matrix FinalMatrix = *pMatrix; 865 FinalMatrix.Concat(*buffer.GetMatrix()); 866 CFX_DIBitmap* pBitmap = buffer.GetBitmap(); 867 if (!pBitmap->GetBuffer()) { 868 return; 869 } 870 pBitmap->Clear(background); 871 int fill_mode = m_Options.m_Flags; 872 switch (pPattern->m_ShadingType) { 873 case kInvalidShading: 874 case kMaxShading: 875 return; 876 case kFunctionBasedShading: 877 DrawFuncShading(pBitmap, &FinalMatrix, pDict, pFuncs, nFuncs, pColorSpace, 878 alpha); 879 break; 880 case kAxialShading: 881 DrawAxialShading(pBitmap, &FinalMatrix, pDict, pFuncs, nFuncs, 882 pColorSpace, alpha); 883 break; 884 case kRadialShading: 885 DrawRadialShading(pBitmap, &FinalMatrix, pDict, pFuncs, nFuncs, 886 pColorSpace, alpha); 887 break; 888 case kFreeFormGouraudTriangleMeshShading: { 889 DrawFreeGouraudShading(pBitmap, &FinalMatrix, 890 ToStream(pPattern->m_pShadingObj), pFuncs, nFuncs, 891 pColorSpace, alpha); 892 } break; 893 case kLatticeFormGouraudTriangleMeshShading: { 894 DrawLatticeGouraudShading(pBitmap, &FinalMatrix, 895 ToStream(pPattern->m_pShadingObj), pFuncs, 896 nFuncs, pColorSpace, alpha); 897 } break; 898 case kCoonsPatchMeshShading: 899 case kTensorProductPatchMeshShading: { 900 DrawCoonPatchMeshes( 901 pPattern->m_ShadingType == kTensorProductPatchMeshShading, pBitmap, 902 &FinalMatrix, ToStream(pPattern->m_pShadingObj), pFuncs, nFuncs, 903 pColorSpace, fill_mode, alpha); 904 } break; 905 } 906 if (bAlphaMode) { 907 pBitmap->LoadChannel(FXDIB_Red, pBitmap, FXDIB_Alpha); 908 } 909 if (m_Options.m_ColorMode == RENDER_COLOR_GRAY) { 910 pBitmap->ConvertColorScale(m_Options.m_ForeColor, m_Options.m_BackColor); 911 } 912 buffer.OutputToDevice(); 913 } 914 void CPDF_RenderStatus::DrawShadingPattern(CPDF_ShadingPattern* pattern, 915 CPDF_PageObject* pPageObj, 916 const CFX_Matrix* pObj2Device, 917 FX_BOOL bStroke) { 918 if (!pattern->Load()) { 919 return; 920 } 921 m_pDevice->SaveState(); 922 if (pPageObj->m_Type == PDFPAGE_PATH) { 923 if (!SelectClipPath((CPDF_PathObject*)pPageObj, pObj2Device, bStroke)) { 924 m_pDevice->RestoreState(); 925 return; 926 } 927 } else if (pPageObj->m_Type == PDFPAGE_IMAGE) { 928 FX_RECT rect = pPageObj->GetBBox(pObj2Device); 929 m_pDevice->SetClip_Rect(&rect); 930 } else { 931 return; 932 } 933 FX_RECT rect; 934 if (GetObjectClippedRect(pPageObj, pObj2Device, FALSE, rect)) { 935 m_pDevice->RestoreState(); 936 return; 937 } 938 CFX_Matrix matrix = pattern->m_Pattern2Form; 939 matrix.Concat(*pObj2Device); 940 GetScaledMatrix(matrix); 941 int alpha = pPageObj->m_GeneralState.GetAlpha(bStroke); 942 DrawShading(pattern, &matrix, rect, alpha, 943 m_Options.m_ColorMode == RENDER_COLOR_ALPHA); 944 m_pDevice->RestoreState(); 945 } 946 FX_BOOL CPDF_RenderStatus::ProcessShading(CPDF_ShadingObject* pShadingObj, 947 const CFX_Matrix* pObj2Device) { 948 FX_RECT rect = pShadingObj->GetBBox(pObj2Device); 949 FX_RECT clip_box = m_pDevice->GetClipBox(); 950 rect.Intersect(clip_box); 951 if (rect.IsEmpty()) { 952 return TRUE; 953 } 954 CFX_Matrix matrix = pShadingObj->m_Matrix; 955 matrix.Concat(*pObj2Device); 956 DrawShading(pShadingObj->m_pShading, &matrix, rect, 957 pShadingObj->m_GeneralState.GetAlpha(FALSE), 958 m_Options.m_ColorMode == RENDER_COLOR_ALPHA); 959 return TRUE; 960 } 961 static CFX_DIBitmap* DrawPatternBitmap(CPDF_Document* pDoc, 962 CPDF_PageRenderCache* pCache, 963 CPDF_TilingPattern* pPattern, 964 const CFX_Matrix* pObject2Device, 965 int width, 966 int height, 967 int flags) { 968 CFX_DIBitmap* pBitmap = new CFX_DIBitmap; 969 if (!pBitmap->Create(width, height, 970 pPattern->m_bColored ? FXDIB_Argb : FXDIB_8bppMask)) { 971 delete pBitmap; 972 return NULL; 973 } 974 CFX_FxgeDevice bitmap_device; 975 bitmap_device.Attach(pBitmap); 976 pBitmap->Clear(0); 977 CFX_FloatRect cell_bbox = pPattern->m_BBox; 978 pPattern->m_Pattern2Form.TransformRect(cell_bbox); 979 pObject2Device->TransformRect(cell_bbox); 980 CFX_FloatRect bitmap_rect(0.0f, 0.0f, (FX_FLOAT)width, (FX_FLOAT)height); 981 CFX_Matrix mtAdjust; 982 mtAdjust.MatchRect(bitmap_rect, cell_bbox); 983 CFX_Matrix mtPattern2Bitmap = *pObject2Device; 984 mtPattern2Bitmap.Concat(mtAdjust); 985 CPDF_RenderOptions options; 986 if (!pPattern->m_bColored) { 987 options.m_ColorMode = RENDER_COLOR_ALPHA; 988 } 989 flags |= RENDER_FORCE_HALFTONE; 990 options.m_Flags = flags; 991 CPDF_RenderContext context(pDoc, pCache); 992 context.DrawObjectList(&bitmap_device, pPattern->m_pForm, &mtPattern2Bitmap, 993 &options); 994 return pBitmap; 995 } 996 void CPDF_RenderStatus::DrawTilingPattern(CPDF_TilingPattern* pPattern, 997 CPDF_PageObject* pPageObj, 998 const CFX_Matrix* pObj2Device, 999 FX_BOOL bStroke) { 1000 if (!pPattern->Load()) { 1001 return; 1002 } 1003 m_pDevice->SaveState(); 1004 if (pPageObj->m_Type == PDFPAGE_PATH) { 1005 if (!SelectClipPath((CPDF_PathObject*)pPageObj, pObj2Device, bStroke)) { 1006 m_pDevice->RestoreState(); 1007 return; 1008 } 1009 } else if (pPageObj->m_Type == PDFPAGE_IMAGE) { 1010 FX_RECT rect = pPageObj->GetBBox(pObj2Device); 1011 m_pDevice->SetClip_Rect(&rect); 1012 } else { 1013 return; 1014 } 1015 FX_RECT clip_box = m_pDevice->GetClipBox(); 1016 if (clip_box.IsEmpty()) { 1017 m_pDevice->RestoreState(); 1018 return; 1019 } 1020 CFX_Matrix dCTM = m_pDevice->GetCTM(); 1021 FX_FLOAT sa = FXSYS_fabs(dCTM.a); 1022 FX_FLOAT sd = FXSYS_fabs(dCTM.d); 1023 clip_box.right = clip_box.left + (int32_t)FXSYS_ceil(clip_box.Width() * sa); 1024 clip_box.bottom = clip_box.top + (int32_t)FXSYS_ceil(clip_box.Height() * sd); 1025 CFX_Matrix mtPattern2Device = pPattern->m_Pattern2Form; 1026 mtPattern2Device.Concat(*pObj2Device); 1027 GetScaledMatrix(mtPattern2Device); 1028 FX_BOOL bAligned = FALSE; 1029 if (pPattern->m_BBox.left == 0 && pPattern->m_BBox.bottom == 0 && 1030 pPattern->m_BBox.right == pPattern->m_XStep && 1031 pPattern->m_BBox.top == pPattern->m_YStep && 1032 (mtPattern2Device.IsScaled() || mtPattern2Device.Is90Rotated())) { 1033 bAligned = TRUE; 1034 } 1035 CFX_FloatRect cell_bbox = pPattern->m_BBox; 1036 mtPattern2Device.TransformRect(cell_bbox); 1037 int width = (int)FXSYS_ceil(cell_bbox.Width()); 1038 int height = (int)FXSYS_ceil(cell_bbox.Height()); 1039 if (width == 0) { 1040 width = 1; 1041 } 1042 if (height == 0) { 1043 height = 1; 1044 } 1045 int min_col, max_col, min_row, max_row; 1046 CFX_Matrix mtDevice2Pattern; 1047 mtDevice2Pattern.SetReverse(mtPattern2Device); 1048 CFX_FloatRect clip_box_p(clip_box); 1049 clip_box_p.Transform(&mtDevice2Pattern); 1050 min_col = (int)FXSYS_ceil( 1051 FXSYS_Div(clip_box_p.left - pPattern->m_BBox.right, pPattern->m_XStep)); 1052 max_col = (int)FXSYS_floor( 1053 FXSYS_Div(clip_box_p.right - pPattern->m_BBox.left, pPattern->m_XStep)); 1054 min_row = (int)FXSYS_ceil( 1055 FXSYS_Div(clip_box_p.bottom - pPattern->m_BBox.top, pPattern->m_YStep)); 1056 max_row = (int)FXSYS_floor( 1057 FXSYS_Div(clip_box_p.top - pPattern->m_BBox.bottom, pPattern->m_YStep)); 1058 if (width > clip_box.Width() || height > clip_box.Height() || 1059 width * height > clip_box.Width() * clip_box.Height()) { 1060 CPDF_GraphicStates* pStates = NULL; 1061 if (!pPattern->m_bColored) { 1062 pStates = CloneObjStates(pPageObj, bStroke); 1063 } 1064 CPDF_Dictionary* pFormResource = NULL; 1065 if (pPattern->m_pForm->m_pFormDict) { 1066 pFormResource = pPattern->m_pForm->m_pFormDict->GetDict("Resources"); 1067 } 1068 for (int col = min_col; col <= max_col; col++) 1069 for (int row = min_row; row <= max_row; row++) { 1070 FX_FLOAT orig_x, orig_y; 1071 orig_x = col * pPattern->m_XStep; 1072 orig_y = row * pPattern->m_YStep; 1073 mtPattern2Device.Transform(orig_x, orig_y); 1074 CFX_Matrix matrix = *pObj2Device; 1075 matrix.Translate(orig_x - mtPattern2Device.e, 1076 orig_y - mtPattern2Device.f); 1077 m_pDevice->SaveState(); 1078 CPDF_RenderStatus status; 1079 status.Initialize(m_pContext, m_pDevice, NULL, NULL, this, pStates, 1080 &m_Options, pPattern->m_pForm->m_Transparency, 1081 m_bDropObjects, pFormResource); 1082 status.RenderObjectList(pPattern->m_pForm, &matrix); 1083 m_pDevice->RestoreState(); 1084 } 1085 m_pDevice->RestoreState(); 1086 delete pStates; 1087 return; 1088 } 1089 if (bAligned) { 1090 int orig_x = FXSYS_round(mtPattern2Device.e); 1091 int orig_y = FXSYS_round(mtPattern2Device.f); 1092 min_col = (clip_box.left - orig_x) / width; 1093 if (clip_box.left < orig_x) { 1094 min_col--; 1095 } 1096 max_col = (clip_box.right - orig_x) / width; 1097 if (clip_box.right <= orig_x) { 1098 max_col--; 1099 } 1100 min_row = (clip_box.top - orig_y) / height; 1101 if (clip_box.top < orig_y) { 1102 min_row--; 1103 } 1104 max_row = (clip_box.bottom - orig_y) / height; 1105 if (clip_box.bottom <= orig_y) { 1106 max_row--; 1107 } 1108 } 1109 FX_FLOAT left_offset = cell_bbox.left - mtPattern2Device.e; 1110 FX_FLOAT top_offset = cell_bbox.bottom - mtPattern2Device.f; 1111 CFX_DIBitmap* pPatternBitmap = NULL; 1112 if (width * height < 16) { 1113 CFX_DIBitmap* pEnlargedBitmap = 1114 DrawPatternBitmap(m_pContext->m_pDocument, m_pContext->m_pPageCache, 1115 pPattern, pObj2Device, 8, 8, m_Options.m_Flags); 1116 pPatternBitmap = pEnlargedBitmap->StretchTo(width, height); 1117 delete pEnlargedBitmap; 1118 } else { 1119 pPatternBitmap = DrawPatternBitmap( 1120 m_pContext->m_pDocument, m_pContext->m_pPageCache, pPattern, 1121 pObj2Device, width, height, m_Options.m_Flags); 1122 } 1123 if (!pPatternBitmap) { 1124 m_pDevice->RestoreState(); 1125 return; 1126 } 1127 if (m_Options.m_ColorMode == RENDER_COLOR_GRAY) { 1128 pPatternBitmap->ConvertColorScale(m_Options.m_ForeColor, 1129 m_Options.m_BackColor); 1130 } 1131 FX_ARGB fill_argb = GetFillArgb(pPageObj); 1132 int clip_width = clip_box.right - clip_box.left; 1133 int clip_height = clip_box.bottom - clip_box.top; 1134 CFX_DIBitmap screen; 1135 if (!screen.Create(clip_width, clip_height, FXDIB_Argb)) { 1136 return; 1137 } 1138 screen.Clear(0); 1139 FX_DWORD* src_buf = (FX_DWORD*)pPatternBitmap->GetBuffer(); 1140 for (int col = min_col; col <= max_col; col++) { 1141 for (int row = min_row; row <= max_row; row++) { 1142 int start_x, start_y; 1143 if (bAligned) { 1144 start_x = FXSYS_round(mtPattern2Device.e) + col * width - clip_box.left; 1145 start_y = FXSYS_round(mtPattern2Device.f) + row * height - clip_box.top; 1146 } else { 1147 FX_FLOAT orig_x = col * pPattern->m_XStep; 1148 FX_FLOAT orig_y = row * pPattern->m_YStep; 1149 mtPattern2Device.Transform(orig_x, orig_y); 1150 start_x = FXSYS_round(orig_x + left_offset) - clip_box.left; 1151 start_y = FXSYS_round(orig_y + top_offset) - clip_box.top; 1152 } 1153 if (width == 1 && height == 1) { 1154 if (start_x < 0 || start_x >= clip_box.Width() || start_y < 0 || 1155 start_y >= clip_box.Height()) { 1156 continue; 1157 } 1158 FX_DWORD* dest_buf = 1159 (FX_DWORD*)(screen.GetBuffer() + screen.GetPitch() * start_y + 1160 start_x * 4); 1161 if (pPattern->m_bColored) { 1162 *dest_buf = *src_buf; 1163 } else { 1164 *dest_buf = (*(uint8_t*)src_buf << 24) | (fill_argb & 0xffffff); 1165 } 1166 } else { 1167 if (pPattern->m_bColored) { 1168 screen.CompositeBitmap(start_x, start_y, width, height, 1169 pPatternBitmap, 0, 0); 1170 } else { 1171 screen.CompositeMask(start_x, start_y, width, height, pPatternBitmap, 1172 fill_argb, 0, 0); 1173 } 1174 } 1175 } 1176 } 1177 CompositeDIBitmap(&screen, clip_box.left, clip_box.top, 0, 255, 1178 FXDIB_BLEND_NORMAL, FALSE); 1179 m_pDevice->RestoreState(); 1180 delete pPatternBitmap; 1181 } 1182 void CPDF_RenderStatus::DrawPathWithPattern(CPDF_PathObject* pPathObj, 1183 const CFX_Matrix* pObj2Device, 1184 CPDF_Color* pColor, 1185 FX_BOOL bStroke) { 1186 CPDF_Pattern* pattern = pColor->GetPattern(); 1187 if (!pattern) { 1188 return; 1189 } 1190 if (pattern->m_PatternType == CPDF_Pattern::TILING) { 1191 DrawTilingPattern(static_cast<CPDF_TilingPattern*>(pattern), pPathObj, 1192 pObj2Device, bStroke); 1193 } else { 1194 DrawShadingPattern(static_cast<CPDF_ShadingPattern*>(pattern), pPathObj, 1195 pObj2Device, bStroke); 1196 } 1197 } 1198 void CPDF_RenderStatus::ProcessPathPattern(CPDF_PathObject* pPathObj, 1199 const CFX_Matrix* pObj2Device, 1200 int& filltype, 1201 FX_BOOL& bStroke) { 1202 if (filltype) { 1203 CPDF_Color& FillColor = *pPathObj->m_ColorState.GetFillColor(); 1204 if (FillColor.m_pCS && FillColor.m_pCS->GetFamily() == PDFCS_PATTERN) { 1205 DrawPathWithPattern(pPathObj, pObj2Device, &FillColor, FALSE); 1206 filltype = 0; 1207 } 1208 } 1209 if (bStroke) { 1210 CPDF_Color& StrokeColor = *pPathObj->m_ColorState.GetStrokeColor(); 1211 if (StrokeColor.m_pCS && StrokeColor.m_pCS->GetFamily() == PDFCS_PATTERN) { 1212 DrawPathWithPattern(pPathObj, pObj2Device, &StrokeColor, TRUE); 1213 bStroke = FALSE; 1214 } 1215 } 1216 } 1217