• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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