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
69namespace {
70
71void 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
80class CPDF_RefType3Cache {
81 public:
82  explicit CPDF_RefType3Cache(CPDF_Type3Font* pType3Font)
83      : m_dwCount(0), m_pType3Font(pType3Font) {}
84
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
94uint32_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
104void 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
189void 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
321void 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
375bool 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
392void 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
473void 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
514void 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
556struct Coon_BezierCoeff {
557  float a, b, c, d;
558  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  }
564  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  }
572  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  }
580  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  }
586  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  }
592  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  }
602  float Distance() {
603    float dis = a + b + c;
604    return dis < 0 ? -dis : dis;
605  }
606};
607
608struct Coon_Bezier {
609  Coon_BezierCoeff x, y;
610  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
622  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
629  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
636  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
644  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
656  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
668  float Distance() { return x.Distance() + y.Distance(); }
669};
670
671int 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
682int 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
696struct Coon_Color {
697  Coon_Color() { memset(comp, 0, sizeof(int) * 3); }
698  int comp[3];
699
700  // Returns true if successful, false if overflow detected.
701  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
715  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
722struct 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;
729  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
829void 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
915RetainPtr<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
956bool 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
966bool MissingFillColor(const CPDF_ColorState* pColorState) {
967  return !pColorState->HasRef() || pColorState->GetFillColor()->IsNull();
968}
969
970bool MissingStrokeColor(const CPDF_ColorState* pColorState) {
971  return !pColorState->HasRef() || pColorState->GetStrokeColor()->IsNull();
972}
973
974bool Type3CharMissingFillColor(const CPDF_Type3Char* pChar,
975                               const CPDF_ColorState* pColorState) {
976  return pChar && (!pChar->colored() ||
977                   (pChar->colored() && MissingFillColor(pColorState)));
978}
979
980bool 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
989int CPDF_RenderStatus::s_CurrentRecursionDepth = 0;
990
991CPDF_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
1009CPDF_RenderStatus::~CPDF_RenderStatus() {}
1010
1011bool 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
1068void 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
1099void 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
1124bool 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
1163bool 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
1184void 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
1214bool 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
1233void 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
1239void 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
1273bool 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
1304bool 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
1343RetainPtr<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
1350FX_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
1376FX_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
1401void 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
1459bool 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
1479bool 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
1655RetainPtr<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
1700std::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_
1721void CPDF_RenderStatus::DebugVerifyDeviceIsPreMultiplied() const {
1722  m_pDevice->DebugVerifyBitmapIsPreMultiplied();
1723}
1724#endif
1725
1726bool 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
1833RetainPtr<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!!)
1844bool 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
2010void 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
2068void 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
2162void 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
2192void 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
2207void 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
2401void 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
2415void 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
2435bool 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
2443void 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
2562RetainPtr<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