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