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