Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Side by Side Diff: core/fpdfapi/fpdf_render/fpdf_render_pattern.cpp

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

Powered by Google App Engine
This is Rietveld 408576698