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