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