Home | History | Annotate | Download | only in skia
      1 // Copyright 2014 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 #include <algorithm>
      6 #include <utility>
      7 #include <vector>
      8 
      9 #include "core/fpdfapi/page/cpdf_expintfunc.h"
     10 #include "core/fpdfapi/page/cpdf_function.h"
     11 #include "core/fpdfapi/page/cpdf_meshstream.h"
     12 #include "core/fpdfapi/page/cpdf_sampledfunc.h"
     13 #include "core/fpdfapi/page/cpdf_shadingpattern.h"
     14 #include "core/fpdfapi/page/cpdf_stitchfunc.h"
     15 #include "core/fpdfapi/parser/cpdf_array.h"
     16 #include "core/fpdfapi/parser/cpdf_dictionary.h"
     17 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
     18 #include "core/fxcrt/fx_extension.h"
     19 #include "core/fxcrt/fx_memory.h"
     20 #include "core/fxge/cfx_defaultrenderdevice.h"
     21 #include "core/fxge/cfx_font.h"
     22 #include "core/fxge/cfx_graphstatedata.h"
     23 #include "core/fxge/cfx_pathdata.h"
     24 #include "core/fxge/cfx_renderdevice.h"
     25 #include "core/fxge/dib/cfx_bitmapcomposer.h"
     26 #include "core/fxge/dib/cfx_imagerenderer.h"
     27 #include "core/fxge/dib/cfx_imagestretcher.h"
     28 #include "core/fxge/skia/fx_skia_device.h"
     29 #include "third_party/base/logging.h"
     30 #include "third_party/base/ptr_util.h"
     31 #include "third_party/skia/include/core/SkCanvas.h"
     32 #include "third_party/skia/include/core/SkClipOp.h"
     33 #include "third_party/skia/include/core/SkImage.h"
     34 #include "third_party/skia/include/core/SkPaint.h"
     35 #include "third_party/skia/include/core/SkPath.h"
     36 #include "third_party/skia/include/core/SkRSXform.h"
     37 #include "third_party/skia/include/core/SkShader.h"
     38 #include "third_party/skia/include/core/SkStream.h"
     39 #include "third_party/skia/include/core/SkTypeface.h"
     40 #include "third_party/skia/include/effects/SkDashPathEffect.h"
     41 #include "third_party/skia/include/effects/SkGradientShader.h"
     42 #include "third_party/skia/include/pathops/SkPathOps.h"
     43 
     44 #ifdef _SKIA_SUPPORT_PATHS_
     45 #include "core/fxge/cfx_cliprgn.h"
     46 #endif  // _SKIA_SUPPORT_PATHS_
     47 
     48 #ifdef _SKIA_SUPPORT_
     49 #include "third_party/skia/include/core/SkColorFilter.h"
     50 #include "third_party/skia/include/core/SkColorPriv.h"
     51 #include "third_party/skia/include/core/SkMaskFilter.h"
     52 #include "third_party/skia/include/core/SkPictureRecorder.h"
     53 #endif  // _SKIA_SUPPORT_
     54 
     55 namespace {
     56 
     57 #ifdef _SKIA_SUPPORT_PATHS_
     58 void RgbByteOrderTransferBitmap(const RetainPtr<CFX_DIBitmap>& pBitmap,
     59                                 int dest_left,
     60                                 int dest_top,
     61                                 int width,
     62                                 int height,
     63                                 const RetainPtr<CFX_DIBSource>& pSrcBitmap,
     64                                 int src_left,
     65                                 int src_top) {
     66   if (!pBitmap)
     67     return;
     68 
     69   pBitmap->GetOverlapRect(dest_left, dest_top, width, height,
     70                           pSrcBitmap->GetWidth(), pSrcBitmap->GetHeight(),
     71                           src_left, src_top, nullptr);
     72   if (width == 0 || height == 0)
     73     return;
     74 
     75   int Bpp = pBitmap->GetBPP() / 8;
     76   FXDIB_Format dest_format = pBitmap->GetFormat();
     77   FXDIB_Format src_format = pSrcBitmap->GetFormat();
     78   int pitch = pBitmap->GetPitch();
     79   uint8_t* buffer = pBitmap->GetBuffer();
     80   if (dest_format == src_format) {
     81     for (int row = 0; row < height; row++) {
     82       uint8_t* dest_scan = buffer + (dest_top + row) * pitch + dest_left * Bpp;
     83       uint8_t* src_scan =
     84           (uint8_t*)pSrcBitmap->GetScanline(src_top + row) + src_left * Bpp;
     85       if (Bpp == 4) {
     86         for (int col = 0; col < width; col++) {
     87           FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_scan[3], src_scan[0],
     88                                                src_scan[1], src_scan[2]));
     89           dest_scan += 4;
     90           src_scan += 4;
     91         }
     92       } else {
     93         for (int col = 0; col < width; col++) {
     94           *dest_scan++ = src_scan[2];
     95           *dest_scan++ = src_scan[1];
     96           *dest_scan++ = src_scan[0];
     97           src_scan += 3;
     98         }
     99       }
    100     }
    101     return;
    102   }
    103 
    104   uint8_t* dest_buf = buffer + dest_top * pitch + dest_left * Bpp;
    105   if (dest_format == FXDIB_Rgb) {
    106     if (src_format == FXDIB_Rgb32) {
    107       for (int row = 0; row < height; row++) {
    108         uint8_t* dest_scan = dest_buf + row * pitch;
    109         uint8_t* src_scan =
    110             (uint8_t*)pSrcBitmap->GetScanline(src_top + row) + src_left * 4;
    111         for (int col = 0; col < width; col++) {
    112           *dest_scan++ = src_scan[2];
    113           *dest_scan++ = src_scan[1];
    114           *dest_scan++ = src_scan[0];
    115           src_scan += 4;
    116         }
    117       }
    118     } else {
    119       NOTREACHED();
    120     }
    121     return;
    122   }
    123 
    124   if (dest_format == FXDIB_Argb || dest_format == FXDIB_Rgb32) {
    125     if (src_format == FXDIB_Rgb) {
    126       for (int row = 0; row < height; row++) {
    127         uint8_t* dest_scan = (uint8_t*)(dest_buf + row * pitch);
    128         uint8_t* src_scan =
    129             (uint8_t*)pSrcBitmap->GetScanline(src_top + row) + src_left * 3;
    130         for (int col = 0; col < width; col++) {
    131           FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[0], src_scan[1],
    132                                                src_scan[2]));
    133           dest_scan += 4;
    134           src_scan += 3;
    135         }
    136       }
    137     } else if (src_format == FXDIB_Rgb32) {
    138       ASSERT(dest_format == FXDIB_Argb);
    139       for (int row = 0; row < height; row++) {
    140         uint8_t* dest_scan = dest_buf + row * pitch;
    141         uint8_t* src_scan =
    142             (uint8_t*)(pSrcBitmap->GetScanline(src_top + row) + src_left * 4);
    143         for (int col = 0; col < width; col++) {
    144           FXARGB_SETDIB(dest_scan, FXARGB_MAKE(0xff, src_scan[0], src_scan[1],
    145                                                src_scan[2]));
    146           src_scan += 4;
    147           dest_scan += 4;
    148         }
    149       }
    150     }
    151     return;
    152   }
    153 
    154   NOTREACHED();
    155 }
    156 
    157 #endif  // _SKIA_SUPPORT_PATHS_
    158 
    159 #define SHOW_SKIA_PATH 0  // set to 1 to print the path contents
    160 #if SHOW_SKIA_PATH
    161 #define SHOW_SKIA_PATH_SHORTHAND 0  // set to 1 for abbreviated path contents
    162 #endif
    163 #define DRAW_SKIA_CLIP 0  // set to 1 to draw a green rectangle around the clip
    164 #define SHOW_TEXT_GLYPHS 0  // set to 1 to print unichar equivalent of glyph
    165 
    166 #if SHOW_SKIA_PATH
    167 void DebugShowSkiaPaint(const SkPaint& paint) {
    168   if (SkPaint::kFill_Style == paint.getStyle()) {
    169     printf("fill 0x%08x\n", paint.getColor());
    170   } else {
    171     printf("stroke 0x%08x width %g\n", paint.getColor(),
    172            paint.getStrokeWidth());
    173   }
    174 }
    175 #endif  // SHOW_SKIA_PATH
    176 
    177 void DebugShowSkiaPath(const SkPath& path) {
    178 #if SHOW_SKIA_PATH
    179 #if SHOW_SKIA_PATH_SHORTHAND
    180   printf(" **\n");
    181 #else
    182   SkDynamicMemoryWStream stream;
    183   path.dump(&stream, false, false);
    184   std::unique_ptr<char, FxFreeDeleter> storage;
    185   storage.reset(FX_Alloc(char, stream.bytesWritten()));
    186   stream.copyTo(storage.get());
    187   printf("%.*s", (int)stream.bytesWritten(), storage.get());
    188 #endif  // SHOW_SKIA_PATH_SHORTHAND
    189 #endif  // SHOW_SKIA_PATH
    190 }
    191 
    192 void DebugShowCanvasClip(CFX_SkiaDeviceDriver* driver, const SkCanvas* canvas) {
    193 #if SHOW_SKIA_PATH
    194   SkMatrix matrix = canvas->getTotalMatrix();
    195   SkScalar m[9];
    196   matrix.get9(m);
    197   printf("matrix (%g,%g,%g) (%g,%g,%g) (%g,%g,%g)\n", m[0], m[1], m[2], m[3],
    198          m[4], m[5], m[6], m[7], m[8]);
    199   SkRect local = canvas->getLocalClipBounds();
    200   SkIRect device = canvas->getDeviceClipBounds();
    201 
    202   printf("local bounds %g %g %g %g\n", local.fLeft, local.fTop, local.fRight,
    203          local.fBottom);
    204   printf("device bounds %d %d %d %d\n", device.fLeft, device.fTop,
    205          device.fRight, device.fBottom);
    206   FX_RECT clipBox;
    207   driver->GetClipBox(&clipBox);
    208   printf("reported bounds %d %d %d %d\n", clipBox.left, clipBox.top,
    209          clipBox.right, clipBox.bottom);
    210 #endif  // SHOW_SKIA_PATH
    211 }
    212 
    213 void DebugShowSkiaDrawPath(CFX_SkiaDeviceDriver* driver,
    214                            const SkCanvas* canvas,
    215                            const SkPaint& paint,
    216                            const SkPath& path) {
    217 #if SHOW_SKIA_PATH
    218   DebugShowSkiaPaint(paint);
    219   DebugShowCanvasClip(driver, canvas);
    220   DebugShowSkiaPath(path);
    221   printf("\n");
    222 #endif  // SHOW_SKIA_PATH
    223 }
    224 
    225 void DebugShowSkiaDrawRect(CFX_SkiaDeviceDriver* driver,
    226                            const SkCanvas* canvas,
    227                            const SkPaint& paint,
    228                            const SkRect& rect) {
    229 #if SHOW_SKIA_PATH
    230   DebugShowSkiaPaint(paint);
    231   DebugShowCanvasClip(driver, canvas);
    232   printf("rect %g %g %g %g\n", rect.fLeft, rect.fTop, rect.fRight,
    233          rect.fBottom);
    234 #endif  // SHOW_SKIA_PATH
    235 }
    236 
    237 #if DRAW_SKIA_CLIP
    238 
    239 SkPaint DebugClipPaint() {
    240   SkPaint paint;
    241   paint.setAntiAlias(true);
    242   paint.setColor(SK_ColorGREEN);
    243   paint.setStyle(SkPaint::kStroke_Style);
    244   return paint;
    245 }
    246 
    247 void DebugDrawSkiaClipRect(SkCanvas* canvas, const SkRect& rect) {
    248   SkPaint paint = DebugClipPaint();
    249   canvas->drawRect(rect, paint);
    250 }
    251 
    252 void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) {
    253   SkPaint paint = DebugClipPaint();
    254   canvas->drawPath(path, paint);
    255 }
    256 
    257 #else  // DRAW_SKIA_CLIP
    258 
    259 void DebugDrawSkiaClipRect(SkCanvas* canvas, const SkRect& rect) {}
    260 
    261 void DebugDrawSkiaClipPath(SkCanvas* canvas, const SkPath& path) {}
    262 
    263 #endif  // DRAW_SKIA_CLIP
    264 
    265 #ifdef _SKIA_SUPPORT_
    266 static void DebugValidate(const RetainPtr<CFX_DIBitmap>& bitmap,
    267                           const RetainPtr<CFX_DIBitmap>& device) {
    268   if (bitmap) {
    269     SkASSERT(bitmap->GetBPP() == 8 || bitmap->GetBPP() == 32);
    270     if (bitmap->GetBPP() == 32) {
    271       bitmap->DebugVerifyBitmapIsPreMultiplied(nullptr);
    272     }
    273   }
    274   if (device) {
    275     SkASSERT(device->GetBPP() == 8 || device->GetBPP() == 32);
    276     if (device->GetBPP() == 32) {
    277       device->DebugVerifyBitmapIsPreMultiplied(nullptr);
    278     }
    279   }
    280 }
    281 #endif  // _SKIA_SUPPORT_
    282 
    283 SkPath BuildPath(const CFX_PathData* pPathData) {
    284   SkPath skPath;
    285   const CFX_PathData* pFPath = pPathData;
    286   const std::vector<FX_PATHPOINT>& pPoints = pFPath->GetPoints();
    287   for (size_t i = 0; i < pPoints.size(); i++) {
    288     CFX_PointF point = pPoints[i].m_Point;
    289     FXPT_TYPE point_type = pPoints[i].m_Type;
    290     if (point_type == FXPT_TYPE::MoveTo) {
    291       skPath.moveTo(point.x, point.y);
    292     } else if (point_type == FXPT_TYPE::LineTo) {
    293       skPath.lineTo(point.x, point.y);
    294     } else if (point_type == FXPT_TYPE::BezierTo) {
    295       CFX_PointF point2 = pPoints[i + 1].m_Point;
    296       CFX_PointF point3 = pPoints[i + 2].m_Point;
    297       skPath.cubicTo(point.x, point.y, point2.x, point2.y, point3.x, point3.y);
    298       i += 2;
    299     }
    300     if (pPoints[i].m_CloseFigure)
    301       skPath.close();
    302   }
    303   return skPath;
    304 }
    305 
    306 SkMatrix ToSkMatrix(const CFX_Matrix& m) {
    307   SkMatrix skMatrix;
    308   skMatrix.setAll(m.a, m.c, m.e, m.b, m.d, m.f, 0, 0, 1);
    309   return skMatrix;
    310 }
    311 
    312 // use when pdf's y-axis points up instead of down
    313 SkMatrix ToFlippedSkMatrix(const CFX_Matrix& m, SkScalar flip) {
    314   SkMatrix skMatrix;
    315   skMatrix.setAll(m.a * flip, -m.c * flip, m.e, m.b * flip, -m.d * flip, m.f, 0,
    316                   0, 1);
    317   return skMatrix;
    318 }
    319 
    320 SkBlendMode GetSkiaBlendMode(int blend_type) {
    321   switch (blend_type) {
    322     case FXDIB_BLEND_MULTIPLY:
    323       return SkBlendMode::kMultiply;
    324     case FXDIB_BLEND_SCREEN:
    325       return SkBlendMode::kScreen;
    326     case FXDIB_BLEND_OVERLAY:
    327       return SkBlendMode::kOverlay;
    328     case FXDIB_BLEND_DARKEN:
    329       return SkBlendMode::kDarken;
    330     case FXDIB_BLEND_LIGHTEN:
    331       return SkBlendMode::kLighten;
    332     case FXDIB_BLEND_COLORDODGE:
    333       return SkBlendMode::kColorDodge;
    334     case FXDIB_BLEND_COLORBURN:
    335       return SkBlendMode::kColorBurn;
    336     case FXDIB_BLEND_HARDLIGHT:
    337       return SkBlendMode::kHardLight;
    338     case FXDIB_BLEND_SOFTLIGHT:
    339       return SkBlendMode::kSoftLight;
    340     case FXDIB_BLEND_DIFFERENCE:
    341       return SkBlendMode::kDifference;
    342     case FXDIB_BLEND_EXCLUSION:
    343       return SkBlendMode::kExclusion;
    344     case FXDIB_BLEND_HUE:
    345       return SkBlendMode::kHue;
    346     case FXDIB_BLEND_SATURATION:
    347       return SkBlendMode::kSaturation;
    348     case FXDIB_BLEND_COLOR:
    349       return SkBlendMode::kColor;
    350     case FXDIB_BLEND_LUMINOSITY:
    351       return SkBlendMode::kLuminosity;
    352     case FXDIB_BLEND_NORMAL:
    353     default:
    354       return SkBlendMode::kSrcOver;
    355   }
    356 }
    357 
    358 bool AddColors(const CPDF_ExpIntFunc* pFunc, SkTDArray<SkColor>* skColors) {
    359   if (pFunc->CountInputs() != 1)
    360     return false;
    361   if (pFunc->m_Exponent != 1)
    362     return false;
    363   if (pFunc->m_nOrigOutputs != 3)
    364     return false;
    365   skColors->push(
    366       SkColorSetARGB(0xFF, SkUnitScalarClampToByte(pFunc->m_pBeginValues[0]),
    367                      SkUnitScalarClampToByte(pFunc->m_pBeginValues[1]),
    368                      SkUnitScalarClampToByte(pFunc->m_pBeginValues[2])));
    369   skColors->push(
    370       SkColorSetARGB(0xFF, SkUnitScalarClampToByte(pFunc->m_pEndValues[0]),
    371                      SkUnitScalarClampToByte(pFunc->m_pEndValues[1]),
    372                      SkUnitScalarClampToByte(pFunc->m_pEndValues[2])));
    373   return true;
    374 }
    375 
    376 uint8_t FloatToByte(float f) {
    377   ASSERT(0 <= f && f <= 1);
    378   return (uint8_t)(f * 255.99f);
    379 }
    380 
    381 bool AddSamples(const CPDF_SampledFunc* pFunc,
    382                 SkTDArray<SkColor>* skColors,
    383                 SkTDArray<SkScalar>* skPos) {
    384   if (pFunc->CountInputs() != 1)
    385     return false;
    386   if (pFunc->CountOutputs() != 3)  // expect rgb
    387     return false;
    388   if (pFunc->GetEncodeInfo().empty())
    389     return false;
    390   const CPDF_SampledFunc::SampleEncodeInfo& encodeInfo =
    391       pFunc->GetEncodeInfo()[0];
    392   if (encodeInfo.encode_min != 0)
    393     return false;
    394   if (encodeInfo.encode_max != encodeInfo.sizes - 1)
    395     return false;
    396   uint32_t sampleSize = pFunc->GetBitsPerSample();
    397   uint32_t sampleCount = encodeInfo.sizes;
    398   if (sampleCount != 1U << sampleSize)
    399     return false;
    400   if (pFunc->GetSampleStream()->GetSize() < sampleCount * 3 * sampleSize / 8)
    401     return false;
    402 
    403   float colorsMin[3];
    404   float colorsMax[3];
    405   for (int i = 0; i < 3; ++i) {
    406     colorsMin[i] = pFunc->GetRange(i * 2);
    407     colorsMax[i] = pFunc->GetRange(i * 2 + 1);
    408   }
    409   const uint8_t* pSampleData = pFunc->GetSampleStream()->GetData();
    410   for (uint32_t i = 0; i < sampleCount; ++i) {
    411     float floatColors[3];
    412     for (uint32_t j = 0; j < 3; ++j) {
    413       int sample = GetBits32(pSampleData, (i * 3 + j) * sampleSize, sampleSize);
    414       float interp = (float)sample / (sampleCount - 1);
    415       floatColors[j] = colorsMin[j] + (colorsMax[j] - colorsMin[j]) * interp;
    416     }
    417     SkColor color =
    418         SkPackARGB32(0xFF, FloatToByte(floatColors[0]),
    419                      FloatToByte(floatColors[1]), FloatToByte(floatColors[2]));
    420     skColors->push(color);
    421     skPos->push((float)i / (sampleCount - 1));
    422   }
    423   return true;
    424 }
    425 
    426 bool AddStitching(const CPDF_StitchFunc* pFunc,
    427                   SkTDArray<SkColor>* skColors,
    428                   SkTDArray<SkScalar>* skPos) {
    429   float boundsStart = pFunc->GetDomain(0);
    430 
    431   const auto& subFunctions = pFunc->GetSubFunctions();
    432   int subFunctionCount = subFunctions.size();
    433   for (int i = 0; i < subFunctionCount; ++i) {
    434     const CPDF_ExpIntFunc* pSubFunc = subFunctions[i]->ToExpIntFunc();
    435     if (!pSubFunc)
    436       return false;
    437     if (!AddColors(pSubFunc, skColors))
    438       return false;
    439     float boundsEnd =
    440         i < subFunctionCount - 1 ? pFunc->GetBound(i + 1) : pFunc->GetDomain(1);
    441     skPos->push(boundsStart);
    442     skPos->push(boundsEnd);
    443     boundsStart = boundsEnd;
    444   }
    445   return true;
    446 }
    447 
    448 // see https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
    449 SkScalar LineSide(const SkPoint line[2], const SkPoint& pt) {
    450   return (line[1].fY - line[0].fY) * pt.fX - (line[1].fX - line[0].fX) * pt.fY +
    451          line[1].fX * line[0].fY - line[1].fY * line[0].fX;
    452 }
    453 
    454 SkPoint IntersectSides(const SkPoint& parallelPt,
    455                        const SkVector& paraRay,
    456                        const SkPoint& perpendicularPt) {
    457   SkVector perpRay = {paraRay.fY, -paraRay.fX};
    458   SkScalar denom = perpRay.fY * paraRay.fX - paraRay.fY * perpRay.fX;
    459   if (!denom) {
    460     SkPoint zeroPt = {0, 0};
    461     return zeroPt;
    462   }
    463   SkVector ab0 = parallelPt - perpendicularPt;
    464   SkScalar numerA = ab0.fY * perpRay.fX - perpRay.fY * ab0.fX;
    465   numerA /= denom;
    466   SkPoint result = {parallelPt.fX + paraRay.fX * numerA,
    467                     parallelPt.fY + paraRay.fY * numerA};
    468   return result;
    469 }
    470 
    471 void ClipAngledGradient(const SkPoint pts[2],
    472                         SkPoint rectPts[4],
    473                         bool clipStart,
    474                         bool clipEnd,
    475                         SkPath* clip) {
    476   // find the corners furthest from the gradient perpendiculars
    477   SkScalar minPerpDist = SK_ScalarMax;
    478   SkScalar maxPerpDist = SK_ScalarMin;
    479   int minPerpPtIndex = -1;
    480   int maxPerpPtIndex = -1;
    481   SkVector slope = pts[1] - pts[0];
    482   SkPoint startPerp[2] = {pts[0], {pts[0].fX + slope.fY, pts[0].fY - slope.fX}};
    483   SkPoint endPerp[2] = {pts[1], {pts[1].fX + slope.fY, pts[1].fY - slope.fX}};
    484   for (int i = 0; i < 4; ++i) {
    485     SkScalar sDist = LineSide(startPerp, rectPts[i]);
    486     SkScalar eDist = LineSide(endPerp, rectPts[i]);
    487     if (sDist * eDist <= 0)  // if the signs are different,
    488       continue;              // the point is inside the gradient
    489     if (sDist < 0) {
    490       SkScalar smaller = SkTMin(sDist, eDist);
    491       if (minPerpDist > smaller) {
    492         minPerpDist = smaller;
    493         minPerpPtIndex = i;
    494       }
    495     } else {
    496       SkScalar larger = SkTMax(sDist, eDist);
    497       if (maxPerpDist < larger) {
    498         maxPerpDist = larger;
    499         maxPerpPtIndex = i;
    500       }
    501     }
    502   }
    503   if (minPerpPtIndex < 0 && maxPerpPtIndex < 0)  // nothing's outside
    504     return;
    505   // determine if negative distances are before start or after end
    506   SkPoint beforeStart = {pts[0].fX * 2 - pts[1].fX, pts[0].fY * 2 - pts[1].fY};
    507   bool beforeNeg = LineSide(startPerp, beforeStart) < 0;
    508   const SkPoint& startEdgePt =
    509       clipStart ? pts[0] : beforeNeg ? rectPts[minPerpPtIndex]
    510                                      : rectPts[maxPerpPtIndex];
    511   const SkPoint& endEdgePt = clipEnd ? pts[1] : beforeNeg
    512                                                     ? rectPts[maxPerpPtIndex]
    513                                                     : rectPts[minPerpPtIndex];
    514   // find the corners that bound the gradient
    515   SkScalar minDist = SK_ScalarMax;
    516   SkScalar maxDist = SK_ScalarMin;
    517   int minBounds = -1;
    518   int maxBounds = -1;
    519   for (int i = 0; i < 4; ++i) {
    520     SkScalar dist = LineSide(pts, rectPts[i]);
    521     if (minDist > dist) {
    522       minDist = dist;
    523       minBounds = i;
    524     }
    525     if (maxDist < dist) {
    526       maxDist = dist;
    527       maxBounds = i;
    528     }
    529   }
    530   if (minBounds < 0 || maxBounds < 0)
    531     return;
    532   if (minBounds == maxBounds)
    533     return;
    534   // construct a clip parallel to the gradient that goes through
    535   // rectPts[minBounds] and rectPts[maxBounds] and perpendicular to the
    536   // gradient that goes through startEdgePt, endEdgePt.
    537   clip->moveTo(IntersectSides(rectPts[minBounds], slope, startEdgePt));
    538   clip->lineTo(IntersectSides(rectPts[minBounds], slope, endEdgePt));
    539   clip->lineTo(IntersectSides(rectPts[maxBounds], slope, endEdgePt));
    540   clip->lineTo(IntersectSides(rectPts[maxBounds], slope, startEdgePt));
    541 }
    542 
    543 #ifdef _SKIA_SUPPORT_
    544 void SetBitmapMatrix(const CFX_Matrix* pMatrix,
    545                      int width,
    546                      int height,
    547                      SkMatrix* skMatrix) {
    548   const CFX_Matrix& m = *pMatrix;
    549   skMatrix->setAll(m.a / width, -m.c / height, m.c + m.e, m.b / width,
    550                    -m.d / height, m.d + m.f, 0, 0, 1);
    551 }
    552 
    553 void SetBitmapPaint(bool isAlphaMask,
    554                     uint32_t argb,
    555                     int bitmap_alpha,
    556                     int blend_type,
    557                     SkPaint* paint) {
    558   paint->setAntiAlias(true);
    559   if (isAlphaMask) {
    560     paint->setColorFilter(
    561         SkColorFilter::MakeModeFilter(argb, SkBlendMode::kSrc));
    562   }
    563   // paint->setFilterQuality(kHigh_SkFilterQuality);
    564   paint->setBlendMode(GetSkiaBlendMode(blend_type));
    565   paint->setAlpha(bitmap_alpha);
    566 }
    567 
    568 bool Upsample(const RetainPtr<CFX_DIBSource>& pSource,
    569               std::unique_ptr<uint8_t, FxFreeDeleter>& dst8Storage,
    570               std::unique_ptr<uint32_t, FxFreeDeleter>& dst32Storage,
    571               SkBitmap* skBitmap,
    572               int* widthPtr,
    573               int* heightPtr,
    574               bool forceAlpha) {
    575   void* buffer = pSource->GetBuffer();
    576   if (!buffer)
    577     return false;
    578   SkColorType colorType = forceAlpha || pSource->IsAlphaMask()
    579                               ? SkColorType::kAlpha_8_SkColorType
    580                               : SkColorType::kGray_8_SkColorType;
    581   SkAlphaType alphaType =
    582       pSource->IsAlphaMask() ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
    583   int width = pSource->GetWidth();
    584   int height = pSource->GetHeight();
    585   int rowBytes = pSource->GetPitch();
    586   switch (pSource->GetBPP()) {
    587     case 1: {
    588       dst8Storage.reset(FX_Alloc2D(uint8_t, width, height));
    589       uint8_t* dst8Pixels = dst8Storage.get();
    590       for (int y = 0; y < height; ++y) {
    591         const uint8_t* srcRow =
    592             static_cast<const uint8_t*>(buffer) + y * rowBytes;
    593         uint8_t* dstRow = dst8Pixels + y * width;
    594         for (int x = 0; x < width; ++x)
    595           dstRow[x] = srcRow[x >> 3] & (1 << (~x & 0x07)) ? 0xFF : 0x00;
    596       }
    597       buffer = dst8Storage.get();
    598       rowBytes = width;
    599       break;
    600     }
    601     case 8:
    602       // we upscale ctables to 32bit.
    603       if (pSource->GetPalette()) {
    604         dst32Storage.reset(FX_Alloc2D(uint32_t, width, height));
    605         SkPMColor* dst32Pixels = dst32Storage.get();
    606         const SkPMColor* ctable = pSource->GetPalette();
    607         const unsigned ctableSize = pSource->GetPaletteSize();
    608         for (int y = 0; y < height; ++y) {
    609           const uint8_t* srcRow =
    610               static_cast<const uint8_t*>(buffer) + y * rowBytes;
    611           uint32_t* dstRow = dst32Pixels + y * width;
    612           for (int x = 0; x < width; ++x) {
    613             unsigned index = srcRow[x];
    614             if (index >= ctableSize) {
    615               index = 0;
    616             }
    617             dstRow[x] = ctable[index];
    618           }
    619         }
    620         buffer = dst32Storage.get();
    621         rowBytes = width * sizeof(uint32_t);
    622         colorType = SkColorType::kN32_SkColorType;
    623       }
    624       break;
    625     case 24: {
    626       dst32Storage.reset(FX_Alloc2D(uint32_t, width, height));
    627       uint32_t* dst32Pixels = dst32Storage.get();
    628       for (int y = 0; y < height; ++y) {
    629         const uint8_t* srcRow =
    630             static_cast<const uint8_t*>(buffer) + y * rowBytes;
    631         uint32_t* dstRow = dst32Pixels + y * width;
    632         for (int x = 0; x < width; ++x) {
    633           dstRow[x] = SkPackARGB32(0xFF, srcRow[x * 3 + 2], srcRow[x * 3 + 1],
    634                                    srcRow[x * 3 + 0]);
    635         }
    636       }
    637       buffer = dst32Storage.get();
    638       rowBytes = width * sizeof(uint32_t);
    639       colorType = SkColorType::kN32_SkColorType;
    640       alphaType = kOpaque_SkAlphaType;
    641       break;
    642     }
    643     case 32:
    644       colorType = SkColorType::kN32_SkColorType;
    645       alphaType = kPremul_SkAlphaType;
    646       pSource->DebugVerifyBitmapIsPreMultiplied(buffer);
    647       break;
    648     default:
    649       SkASSERT(0);  // TODO(caryclark) ensure that all cases are covered
    650       colorType = SkColorType::kUnknown_SkColorType;
    651   }
    652   SkImageInfo imageInfo =
    653       SkImageInfo::Make(width, height, colorType, alphaType);
    654   skBitmap->installPixels(imageInfo, buffer, rowBytes);
    655   *widthPtr = width;
    656   *heightPtr = height;
    657   return true;
    658 }
    659 #endif  // _SKIA_SUPPORT_
    660 
    661 }  // namespace
    662 
    663 // Encapsulate the state used for successive text and path draws so that
    664 // they can be combined.
    665 class SkiaState {
    666  public:
    667   enum class Clip {
    668     kSave,
    669     kPath,
    670   };
    671 
    672   enum class Accumulator {
    673     kNone,
    674     kPath,
    675     kText,
    676     kOther,
    677   };
    678 
    679   // mark all cached state as uninitialized
    680   explicit SkiaState(CFX_SkiaDeviceDriver* pDriver)
    681       : m_pDriver(pDriver),
    682         m_pTypeFace(nullptr),
    683         m_fontSize(0),
    684         m_scaleX(0),
    685         m_fillColor(0),
    686         m_strokeColor(0),
    687         m_blendType(0),
    688         m_commandIndex(0),
    689         m_drawIndex(INT_MAX),
    690         m_clipIndex(0),
    691         m_type(Accumulator::kNone),
    692         m_fillFullCover(false),
    693         m_fillPath(false),
    694         m_groupKnockout(false),
    695         m_debugDisable(false)
    696 #if SHOW_SKIA_PATH
    697         ,
    698         m_debugSaveCounter(0)
    699 #endif
    700   {
    701   }
    702 
    703   bool DrawPath(const CFX_PathData* pPathData,
    704                 const CFX_Matrix* pMatrix,
    705                 const CFX_GraphStateData* pDrawState,
    706                 uint32_t fill_color,
    707                 uint32_t stroke_color,
    708                 int fill_mode,
    709                 int blend_type) {
    710     if (m_debugDisable)
    711       return false;
    712     Dump(__func__);
    713     int drawIndex = SkTMin(m_drawIndex, m_commands.count());
    714     if (Accumulator::kText == m_type || drawIndex != m_commandIndex ||
    715         (Accumulator::kPath == m_type &&
    716          DrawChanged(pMatrix, pDrawState, fill_color, stroke_color, fill_mode,
    717                      blend_type, m_pDriver->GetGroupKnockout()))) {
    718       Flush();
    719     }
    720     if (Accumulator::kPath != m_type) {
    721       m_skPath.reset();
    722       m_fillFullCover = !!(fill_mode & FXFILL_FULLCOVER);
    723       m_fillPath = (fill_mode & 3) && fill_color;
    724       m_skPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE
    725                                ? SkPath::kEvenOdd_FillType
    726                                : SkPath::kWinding_FillType);
    727       if (pDrawState)
    728         m_drawState.Copy(*pDrawState);
    729       m_fillColor = fill_color;
    730       m_strokeColor = stroke_color;
    731       m_blendType = blend_type;
    732       m_groupKnockout = m_pDriver->GetGroupKnockout();
    733       if (pMatrix)
    734         m_drawMatrix = *pMatrix;
    735       m_drawIndex = m_commandIndex;
    736       m_type = Accumulator::kPath;
    737     }
    738     SkPath skPath = BuildPath(pPathData);
    739     SkPoint delta;
    740     if (MatrixOffset(pMatrix, &delta))
    741       skPath.offset(delta.fX, delta.fY);
    742     m_skPath.addPath(skPath);
    743     return true;
    744   }
    745 
    746   void FlushPath() {
    747     Dump(__func__);
    748     SkMatrix skMatrix = ToSkMatrix(m_drawMatrix);
    749     SkPaint skPaint;
    750     skPaint.setAntiAlias(true);
    751     if (m_fillFullCover)
    752       skPaint.setBlendMode(SkBlendMode::kPlus);
    753     int stroke_alpha = FXARGB_A(m_strokeColor);
    754     if (stroke_alpha)
    755       m_pDriver->PaintStroke(&skPaint, &m_drawState, skMatrix);
    756     SkCanvas* skCanvas = m_pDriver->SkiaCanvas();
    757     skCanvas->save();
    758     skCanvas->concat(skMatrix);
    759     if (m_fillPath) {
    760       SkPath strokePath;
    761       const SkPath* fillPath = &m_skPath;
    762       if (stroke_alpha) {
    763         if (m_groupKnockout) {
    764           skPaint.getFillPath(m_skPath, &strokePath);
    765           if (Op(m_skPath, strokePath, SkPathOp::kDifference_SkPathOp,
    766                  &strokePath)) {
    767             fillPath = &strokePath;
    768           }
    769         }
    770       }
    771       skPaint.setStyle(SkPaint::kFill_Style);
    772       skPaint.setColor(m_fillColor);
    773 #ifdef _SKIA_SUPPORT_PATHS_
    774       m_pDriver->PreMultiply();
    775 #endif  // _SKIA_SUPPORT_PATHS_
    776       DebugShowSkiaDrawPath(m_pDriver.Get(), skCanvas, skPaint, *fillPath);
    777       skCanvas->drawPath(*fillPath, skPaint);
    778     }
    779     if (stroke_alpha) {
    780       skPaint.setStyle(SkPaint::kStroke_Style);
    781       skPaint.setColor(m_strokeColor);
    782 #ifdef _SKIA_SUPPORT_PATHS_
    783       m_pDriver->PreMultiply();
    784 #endif  // _SKIA_SUPPORT_PATHS_
    785       DebugShowSkiaDrawPath(m_pDriver.Get(), skCanvas, skPaint, m_skPath);
    786       skCanvas->drawPath(m_skPath, skPaint);
    787     }
    788     skCanvas->restore();
    789     m_drawIndex = INT_MAX;
    790     m_type = Accumulator::kNone;
    791   }
    792 
    793   bool HasRSX(int nChars,
    794               const FXTEXT_CHARPOS* pCharPos,
    795               float* scaleXPtr,
    796               bool* oneAtATimePtr) {
    797     bool useRSXform = false;
    798     bool oneAtATime = false;
    799     float scaleX = 1;
    800     for (int index = 0; index < nChars; ++index) {
    801       const FXTEXT_CHARPOS& cp = pCharPos[index];
    802       if (!cp.m_bGlyphAdjust)
    803         continue;
    804       bool upright = 0 == cp.m_AdjustMatrix[1] && 0 == cp.m_AdjustMatrix[2];
    805       if (cp.m_AdjustMatrix[0] != cp.m_AdjustMatrix[3]) {
    806         if (upright && 1 == cp.m_AdjustMatrix[3]) {
    807           if (1 == scaleX)
    808             scaleX = cp.m_AdjustMatrix[0];
    809           else if (scaleX != cp.m_AdjustMatrix[0])
    810             oneAtATime = true;
    811         } else {
    812           oneAtATime = true;
    813         }
    814       } else if (cp.m_AdjustMatrix[1] != -cp.m_AdjustMatrix[2]) {
    815         oneAtATime = true;
    816       } else {
    817         useRSXform = true;
    818       }
    819     }
    820     *oneAtATimePtr = oneAtATime;
    821     *scaleXPtr = oneAtATime ? 1 : scaleX;
    822     return oneAtATime ? false : useRSXform;
    823   }
    824 
    825   bool DrawText(int nChars,
    826                 const FXTEXT_CHARPOS* pCharPos,
    827                 CFX_Font* pFont,
    828                 const CFX_Matrix* pMatrix,
    829                 float font_size,
    830                 uint32_t color) {
    831     if (m_debugDisable)
    832       return false;
    833     Dump(__func__);
    834     float scaleX = 1;
    835     bool oneAtATime = false;
    836     bool hasRSX = HasRSX(nChars, pCharPos, &scaleX, &oneAtATime);
    837     if (oneAtATime) {
    838       Flush();
    839       return false;
    840     }
    841     int drawIndex = SkTMin(m_drawIndex, m_commands.count());
    842     if (Accumulator::kPath == m_type || drawIndex != m_commandIndex ||
    843         (Accumulator::kText == m_type &&
    844          (FontChanged(pFont, pMatrix, font_size, scaleX, color) ||
    845           hasRSX == !m_rsxform.count()))) {
    846       Flush();
    847     }
    848     if (Accumulator::kText != m_type) {
    849       m_positions.setCount(0);
    850       m_glyphs.setCount(0);
    851       m_pTypeFace = pFont->GetFace() ? pFont->GetDeviceCache() : nullptr;
    852       m_fontSize = font_size;
    853       m_scaleX = scaleX;
    854       m_fillColor = color;
    855       m_drawMatrix = *pMatrix;
    856       m_drawIndex = m_commandIndex;
    857       m_type = Accumulator::kText;
    858     }
    859     int count = m_positions.count();
    860     m_positions.setCount(nChars + count);
    861     m_glyphs.setCount(nChars + count);
    862     if (hasRSX) {
    863       m_rsxform.setCount(nChars + count);
    864     }
    865     SkScalar flip = m_fontSize < 0 ? -1 : 1;
    866     SkScalar vFlip = flip;
    867     if (pFont->IsVertical())
    868       vFlip *= -1;
    869     for (int index = 0; index < nChars; ++index) {
    870       const FXTEXT_CHARPOS& cp = pCharPos[index];
    871       m_positions[index + count] = {cp.m_Origin.x * flip,
    872                                     cp.m_Origin.y * vFlip};
    873       m_glyphs[index + count] = static_cast<uint16_t>(cp.m_GlyphIndex);
    874 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
    875       if (cp.m_ExtGID)
    876         m_glyphs[index + count] = static_cast<uint16_t>(cp.m_ExtGID);
    877 #endif
    878     }
    879     SkPoint delta;
    880     if (MatrixOffset(pMatrix, &delta)) {
    881       for (int index = 0; index < nChars; ++index)
    882         m_positions[index + count].offset(delta.fX * flip, -delta.fY * flip);
    883     }
    884     if (hasRSX) {
    885       for (int index = 0; index < nChars; ++index) {
    886         const FXTEXT_CHARPOS& cp = pCharPos[index];
    887         SkRSXform* rsxform = &m_rsxform[index + count];
    888         if (cp.m_bGlyphAdjust) {
    889           rsxform->fSCos = cp.m_AdjustMatrix[0];
    890           rsxform->fSSin = cp.m_AdjustMatrix[1];
    891           rsxform->fTx = cp.m_AdjustMatrix[0] * m_positions[index].fX;
    892           rsxform->fTy = cp.m_AdjustMatrix[1] * m_positions[index].fY;
    893         } else {
    894           rsxform->fSCos = 1;
    895           rsxform->fSSin = 0;
    896           rsxform->fTx = m_positions[index].fX;
    897           rsxform->fTy = m_positions[index].fY;
    898         }
    899       }
    900     }
    901     return true;
    902   }
    903 
    904   void FlushText() {
    905     Dump(__func__);
    906     SkPaint skPaint;
    907     skPaint.setAntiAlias(true);
    908     skPaint.setColor(m_fillColor);
    909     if (m_pTypeFace) {  // exclude placeholder test fonts
    910       sk_sp<SkTypeface> typeface(SkSafeRef(m_pTypeFace.Get()));
    911       skPaint.setTypeface(typeface);
    912     }
    913     skPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    914     skPaint.setHinting(SkPaint::kNo_Hinting);
    915     skPaint.setTextScaleX(m_scaleX);
    916     skPaint.setTextSize(SkTAbs(m_fontSize));
    917     skPaint.setSubpixelText(true);
    918     SkCanvas* skCanvas = m_pDriver->SkiaCanvas();
    919     skCanvas->save();
    920     SkScalar flip = m_fontSize < 0 ? -1 : 1;
    921     SkMatrix skMatrix = ToFlippedSkMatrix(m_drawMatrix, flip);
    922     skCanvas->concat(skMatrix);
    923 #ifdef _SKIA_SUPPORT_PATHS_
    924     m_pDriver->PreMultiply();
    925 #endif  // _SKIA_SUPPORT_PATHS_
    926 #if SHOW_TEXT_GLYPHS
    927     SkTDArray<SkUnichar> text;
    928     text.setCount(m_glyphs.count());
    929     skPaint.glyphsToUnichars(m_glyphs.begin(), m_glyphs.count(), text.begin());
    930     for (size_t i = 0; i < m_glyphs.count(); ++i)
    931       printf("%lc", m_glyphs[i]);
    932     printf("\n");
    933 #endif
    934     if (m_rsxform.count()) {
    935       skCanvas->drawTextRSXform(m_glyphs.begin(), m_glyphs.count() * 2,
    936                                 m_rsxform.begin(), nullptr, skPaint);
    937     } else {
    938       skCanvas->drawPosText(m_glyphs.begin(), m_glyphs.count() * 2,
    939                             m_positions.begin(), skPaint);
    940     }
    941     skCanvas->restore();
    942     m_drawIndex = INT_MAX;
    943     m_type = Accumulator::kNone;
    944   }
    945 
    946   bool IsEmpty() { return !m_commands.count(); }
    947 
    948   bool SetClipFill(const CFX_PathData* pPathData,
    949                    const CFX_Matrix* pMatrix,
    950                    int fill_mode) {
    951     if (m_debugDisable)
    952       return false;
    953     Dump(__func__);
    954     SkPath skClipPath;
    955     if (pPathData->GetPoints().size() == 5 ||
    956         pPathData->GetPoints().size() == 4) {
    957       CFX_FloatRect rectf;
    958       if (pPathData->IsRect(pMatrix, &rectf)) {
    959         rectf.Intersect(CFX_FloatRect(
    960             0, 0,
    961             static_cast<float>(m_pDriver->GetDeviceCaps(FXDC_PIXEL_WIDTH)),
    962             static_cast<float>(m_pDriver->GetDeviceCaps(FXDC_PIXEL_HEIGHT))));
    963         FX_RECT outer = rectf.GetOuterRect();
    964         // note that PDF's y-axis goes up; Skia's y-axis goes down
    965         skClipPath.addRect({(float)outer.left, (float)outer.bottom,
    966                             (float)outer.right, (float)outer.top});
    967       }
    968     }
    969     if (skClipPath.isEmpty()) {
    970       skClipPath = BuildPath(pPathData);
    971       skClipPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE
    972                                  ? SkPath::kEvenOdd_FillType
    973                                  : SkPath::kWinding_FillType);
    974       SkMatrix skMatrix = ToSkMatrix(*pMatrix);
    975       skClipPath.transform(skMatrix);
    976     }
    977     return SetClip(skClipPath);
    978   }
    979 
    980   bool SetClip(const SkPath& skClipPath) {
    981     // if a pending draw depends on clip state that is cached, flush it and draw
    982     if (m_commandIndex < m_commands.count()) {
    983       if (m_commands[m_commandIndex] == Clip::kPath &&
    984           m_clips[m_commandIndex] == skClipPath) {
    985         ++m_commandIndex;
    986         return true;
    987       }
    988       Flush();
    989     }
    990     while (m_clipIndex > m_commandIndex) {
    991       do {
    992         --m_clipIndex;
    993         SkASSERT(m_clipIndex >= 0);
    994       } while (m_commands[m_clipIndex] != Clip::kSave);
    995       m_pDriver->SkiaCanvas()->restore();
    996     }
    997     if (m_commandIndex < m_commands.count()) {
    998       m_commands[m_commandIndex] = Clip::kPath;
    999       m_clips[m_commandIndex] = skClipPath;
   1000     } else {
   1001       m_commands.push(Clip::kPath);
   1002       m_clips.push_back(skClipPath);
   1003     }
   1004     ++m_commandIndex;
   1005     return true;
   1006   }
   1007 
   1008   bool SetClipStroke(const CFX_PathData* pPathData,
   1009                      const CFX_Matrix* pMatrix,
   1010                      const CFX_GraphStateData* pGraphState) {
   1011     if (m_debugDisable)
   1012       return false;
   1013     Dump(__func__);
   1014     SkPath skPath = BuildPath(pPathData);
   1015     SkMatrix skMatrix = ToSkMatrix(*pMatrix);
   1016     SkPaint skPaint;
   1017     m_pDriver->PaintStroke(&skPaint, pGraphState, skMatrix);
   1018     SkPath dst_path;
   1019     skPaint.getFillPath(skPath, &dst_path);
   1020     dst_path.transform(skMatrix);
   1021     return SetClip(dst_path);
   1022   }
   1023 
   1024   bool MatrixOffset(const CFX_Matrix* pMatrix, SkPoint* delta) {
   1025     CFX_Matrix identityMatrix;
   1026     if (!pMatrix)
   1027       pMatrix = &identityMatrix;
   1028     delta->set(pMatrix->e - m_drawMatrix.e, pMatrix->f - m_drawMatrix.f);
   1029     if (!delta->fX && !delta->fY)
   1030       return true;
   1031     SkMatrix drawMatrix = ToSkMatrix(m_drawMatrix);
   1032     if (!(drawMatrix.getType() & ~SkMatrix::kTranslate_Mask))
   1033       return true;
   1034     SkMatrix invDrawMatrix;
   1035     if (!drawMatrix.invert(&invDrawMatrix))
   1036       return false;
   1037     SkMatrix invNewMatrix;
   1038     SkMatrix newMatrix = ToSkMatrix(*pMatrix);
   1039     if (!newMatrix.invert(&invNewMatrix))
   1040       return false;
   1041     delta->set(invDrawMatrix.getTranslateX() - invNewMatrix.getTranslateX(),
   1042                invDrawMatrix.getTranslateY() - invNewMatrix.getTranslateY());
   1043     return true;
   1044   }
   1045 
   1046   // returns true if caller should apply command to skia canvas
   1047   bool ClipSave() {
   1048     if (m_debugDisable)
   1049       return false;
   1050     Dump(__func__);
   1051     int count = m_commands.count();
   1052     if (m_commandIndex < count) {
   1053       if (Clip::kSave == m_commands[m_commandIndex]) {
   1054         ++m_commandIndex;
   1055         return true;
   1056       }
   1057       Flush();
   1058       AdjustClip(m_commandIndex);
   1059       m_commands[m_commandIndex] = Clip::kSave;
   1060       m_clips[m_commandIndex] = m_skEmptyPath;
   1061     } else {
   1062       AdjustClip(m_commandIndex);
   1063       m_commands.push(Clip::kSave);
   1064       m_clips.push_back(m_skEmptyPath);
   1065     }
   1066     ++m_commandIndex;
   1067     return true;
   1068   }
   1069 
   1070   bool ClipRestore() {
   1071     if (m_debugDisable)
   1072       return false;
   1073     Dump(__func__);
   1074     while (Clip::kSave != m_commands[--m_commandIndex]) {
   1075       SkASSERT(m_commandIndex > 0);
   1076     }
   1077     return true;
   1078   }
   1079 
   1080   bool DrawChanged(const CFX_Matrix* pMatrix,
   1081                    const CFX_GraphStateData* pState,
   1082                    uint32_t fill_color,
   1083                    uint32_t stroke_color,
   1084                    int fill_mode,
   1085                    int blend_type,
   1086                    bool group_knockout) const {
   1087     return MatrixChanged(pMatrix, m_drawMatrix) ||
   1088            StateChanged(pState, m_drawState) || fill_color != m_fillColor ||
   1089            stroke_color != m_strokeColor ||
   1090            ((fill_mode & 3) == FXFILL_ALTERNATE) !=
   1091                (m_skPath.getFillType() == SkPath::kEvenOdd_FillType) ||
   1092            blend_type != m_blendType || group_knockout != m_groupKnockout;
   1093   }
   1094 
   1095   bool FontChanged(CFX_Font* pFont,
   1096                    const CFX_Matrix* pMatrix,
   1097                    float font_size,
   1098                    float scaleX,
   1099                    uint32_t color) const {
   1100     CFX_TypeFace* typeface =
   1101         pFont->GetFace() ? pFont->GetDeviceCache() : nullptr;
   1102     return typeface != m_pTypeFace || MatrixChanged(pMatrix, m_drawMatrix) ||
   1103            font_size != m_fontSize || scaleX != m_scaleX ||
   1104            color != m_fillColor;
   1105   }
   1106 
   1107   bool MatrixChanged(const CFX_Matrix* pMatrix,
   1108                      const CFX_Matrix& refMatrix) const {
   1109     CFX_Matrix identityMatrix;
   1110     if (!pMatrix)
   1111       pMatrix = &identityMatrix;
   1112     return pMatrix->a != refMatrix.a || pMatrix->b != refMatrix.b ||
   1113            pMatrix->c != refMatrix.c || pMatrix->d != refMatrix.d;
   1114   }
   1115 
   1116   bool StateChanged(const CFX_GraphStateData* pState,
   1117                     const CFX_GraphStateData& refState) const {
   1118     CFX_GraphStateData identityState;
   1119     if (!pState)
   1120       pState = &identityState;
   1121     return pState->m_LineWidth != refState.m_LineWidth ||
   1122            pState->m_LineCap != refState.m_LineCap ||
   1123            pState->m_LineJoin != refState.m_LineJoin ||
   1124            pState->m_MiterLimit != refState.m_MiterLimit ||
   1125            DashChanged(pState, refState);
   1126   }
   1127 
   1128   bool DashChanged(const CFX_GraphStateData* pState,
   1129                    const CFX_GraphStateData& refState) const {
   1130     bool dashArray = pState && pState->m_DashArray;
   1131     if (!dashArray && !refState.m_DashArray)
   1132       return false;
   1133     if (!dashArray || !refState.m_DashArray)
   1134       return true;
   1135     if (pState->m_DashPhase != refState.m_DashPhase ||
   1136         pState->m_DashCount != refState.m_DashCount) {
   1137       return true;
   1138     }
   1139     for (int index = 0; index < pState->m_DashCount; ++index) {
   1140       if (pState->m_DashArray[index] != refState.m_DashArray[index])
   1141         return true;
   1142     }
   1143     return true;
   1144   }
   1145 
   1146   void AdjustClip(int limit) {
   1147     while (m_clipIndex > limit) {
   1148       do {
   1149         --m_clipIndex;
   1150         SkASSERT(m_clipIndex >= 0);
   1151       } while (m_commands[m_clipIndex] != Clip::kSave);
   1152       m_pDriver->SkiaCanvas()->restore();
   1153     }
   1154     while (m_clipIndex < limit) {
   1155       if (Clip::kSave == m_commands[m_clipIndex]) {
   1156         m_pDriver->SkiaCanvas()->save();
   1157       } else {
   1158         SkASSERT(Clip::kPath == m_commands[m_clipIndex]);
   1159         m_pDriver->SkiaCanvas()->clipPath(m_clips[m_clipIndex],
   1160                                           SkClipOp::kIntersect, true);
   1161       }
   1162       ++m_clipIndex;
   1163     }
   1164   }
   1165 
   1166   void Flush() {
   1167     if (m_debugDisable)
   1168       return;
   1169     Dump(__func__);
   1170     if (Accumulator::kPath == m_type || Accumulator::kText == m_type) {
   1171       AdjustClip(SkTMin(m_drawIndex, m_commands.count()));
   1172       Accumulator::kPath == m_type ? FlushPath() : FlushText();
   1173     }
   1174   }
   1175 
   1176   void FlushForDraw() {
   1177     if (m_debugDisable)
   1178       return;
   1179     Flush();                     // draw any pending text or path
   1180     AdjustClip(m_commandIndex);  // set up clip stack with any pending state
   1181   }
   1182 
   1183 #if SHOW_SKIA_PATH
   1184   void DumpPrefix(int index) const {
   1185     if (index != m_commandIndex && index != m_drawIndex &&
   1186         index != m_clipIndex) {
   1187       printf("     ");
   1188       return;
   1189     }
   1190     printf("%c%c%c> ", index == m_commandIndex ? 'x' : '-',
   1191            index == m_drawIndex ? 'd' : '-', index == m_clipIndex ? 'c' : '-');
   1192   }
   1193 
   1194   void DumpEndPrefix() const {
   1195     int index = m_commands.count();
   1196     if (index != m_commandIndex && index > m_drawIndex && index != m_clipIndex)
   1197       return;
   1198     printf("%c%c%c>\n", index == m_commandIndex ? 'x' : '-',
   1199            index <= m_drawIndex ? 'd' : '-', index == m_clipIndex ? 'c' : '-');
   1200   }
   1201 #endif  // SHOW_SKIA_PATH
   1202 
   1203   void Dump(const char* where) const {
   1204 #if SHOW_SKIA_PATH
   1205     if (m_debugDisable)
   1206       return;
   1207     printf(
   1208         "\n%s\nSkia Save Count %d  Agg Save Stack/Count %d/%d"
   1209         "  Cache Save Index/Count %d/%d\n",
   1210         where, m_pDriver->m_pCanvas->getSaveCount(),
   1211         (int)m_pDriver->m_StateStack.size(), AggSaveCount(m_pDriver),
   1212         m_commandIndex, CacheSaveCount(m_commands, m_commandIndex));
   1213     printf("Cache:\n");
   1214 #if SHOW_SKIA_PATH_SHORTHAND
   1215     bool dumpedPath = false;
   1216 #endif
   1217     for (int index = 0; index < m_commands.count(); ++index) {
   1218 #if SHOW_SKIA_PATH_SHORTHAND
   1219       if (Clip::kSave == m_commands[index] && dumpedPath) {
   1220         printf("\n");
   1221         dumpedPath = false;
   1222       }
   1223 #endif
   1224       DumpPrefix(index);
   1225       switch (m_commands[index]) {
   1226         case Clip::kSave:
   1227           printf("Save %d\n", ++m_debugSaveCounter);
   1228           break;
   1229         case Clip::kPath:
   1230 #if SHOW_SKIA_PATH_SHORTHAND
   1231           printf("*");
   1232           dumpedPath = true;
   1233 #else
   1234           m_clips[index].dump();
   1235 #endif
   1236           break;
   1237         default:
   1238           printf("unknown\n");
   1239       }
   1240     }
   1241 #if SHOW_SKIA_PATH_SHORTHAND
   1242     if (dumpedPath)
   1243       printf("\n");
   1244 #endif
   1245     DumpEndPrefix();
   1246     int skCanvasSaveCount = m_pDriver->m_pCanvas->getSaveCount();
   1247     int cacheSaveCount = 1;
   1248     SkASSERT(m_clipIndex <= m_commands.count());
   1249     for (int index = 0; index < m_clipIndex; ++index)
   1250       cacheSaveCount += Clip::kSave == m_commands[index];
   1251     SkASSERT(skCanvasSaveCount == cacheSaveCount);
   1252 #endif  // SHOW_SKIA_PATH
   1253   }
   1254 
   1255 #if SHOW_SKIA_PATH
   1256   static int AggSaveCount(const UnownedPtr<CFX_SkiaDeviceDriver> driver) {
   1257     FX_RECT last;
   1258     int aggSaveCount = 0;
   1259     bool foundLast = false;
   1260     for (int index = 0; index < (int)driver->m_StateStack.size(); ++index) {
   1261       if (!driver->m_StateStack[index]) {
   1262         continue;
   1263       }
   1264       if (driver->m_StateStack[index]->GetType() != CFX_ClipRgn::RectI) {
   1265         aggSaveCount += 1;
   1266         foundLast = false;
   1267         continue;
   1268       }
   1269       if (!foundLast || memcmp(&last, &driver->m_StateStack[index]->GetBox(),
   1270                                sizeof(FX_RECT))) {
   1271         aggSaveCount += 1;
   1272         foundLast = true;
   1273         last = driver->m_StateStack[index]->GetBox();
   1274       }
   1275     }
   1276     if (driver->m_pClipRgn) {
   1277       CFX_ClipRgn::ClipType clipType = driver->m_pClipRgn->GetType();
   1278       if (clipType != CFX_ClipRgn::RectI || !foundLast ||
   1279           memcmp(&last, &driver->m_pClipRgn->GetBox(), sizeof(FX_RECT))) {
   1280         aggSaveCount += 1;
   1281       }
   1282     }
   1283     return aggSaveCount;
   1284   }
   1285 
   1286   static int CacheSaveCount(const SkTDArray<SkiaState::Clip>& commands,
   1287                             int commandIndex) {
   1288     int cacheSaveCount = 0;
   1289     bool newPath = false;
   1290     for (int index = 0; index < commandIndex; ++index) {
   1291       if (Clip::kSave == commands[index]) {
   1292         newPath = true;
   1293       } else if (newPath) {
   1294         ++cacheSaveCount;
   1295         newPath = false;
   1296       }
   1297     }
   1298     return cacheSaveCount;
   1299   }
   1300 #endif
   1301 
   1302   void DebugCheckClip() {
   1303 #if SHOW_SKIA_PATH
   1304     if (m_debugDisable)
   1305       return;
   1306     int aggSaveCount = AggSaveCount(m_pDriver);
   1307     int cacheSaveCount = CacheSaveCount(m_commands, m_commandIndex);
   1308     SkASSERT(m_clipIndex <= m_commands.count());
   1309     if (aggSaveCount != cacheSaveCount) {
   1310       // may not signify a bug if counts don't match
   1311       printf("aggSaveCount %d != cacheSaveCount %d\n", aggSaveCount,
   1312              cacheSaveCount);
   1313       DumpClipStacks();
   1314     }
   1315     for (int aggIndex = 0; aggIndex < (int)m_pDriver->m_StateStack.size();
   1316          ++aggIndex) {
   1317       if (!m_pDriver->m_StateStack[aggIndex])
   1318         continue;
   1319       if (m_pDriver->m_StateStack[aggIndex]->GetType() != CFX_ClipRgn::RectI)
   1320         continue;
   1321       const FX_RECT& aggRect = m_pDriver->m_StateStack[aggIndex]->GetBox();
   1322       SkRect skRect = SkRect::MakeLTRB(aggRect.left, aggRect.top, aggRect.right,
   1323                                        aggRect.bottom);
   1324       bool foundMatch = false;
   1325       for (int skIndex = 0; skIndex < m_commandIndex; ++skIndex) {
   1326         if (Clip::kPath != m_commands[skIndex])
   1327           continue;
   1328         const SkPath& clip = m_clips[skIndex];
   1329         SkRect bounds;
   1330         if (!clip.isRect(&bounds))
   1331           continue;
   1332         bounds.roundOut(&bounds);
   1333         if (skRect == bounds) {
   1334           foundMatch = true;
   1335           break;
   1336         }
   1337       }
   1338       if (!foundMatch) {
   1339         DumpClipStacks();
   1340         SkASSERT(0);
   1341       }
   1342     }
   1343 #endif  // SHOW_SKIA_PATH
   1344   }
   1345 
   1346 #if SHOW_SKIA_PATH
   1347   void DumpClipStacks() const {
   1348     if (m_debugDisable)
   1349       return;
   1350     printf("\ncache\n");
   1351     for (int index = 0; index < m_commandIndex; ++index) {
   1352       DumpPrefix(index);
   1353       switch (m_commands[index]) {
   1354         case Clip::kSave:
   1355           printf("Save\n");
   1356           break;
   1357         case Clip::kPath:
   1358           m_clips[index].dump();
   1359           break;
   1360         default:
   1361           printf("unknown\n");
   1362       }
   1363     }
   1364     printf("\nagg\n");
   1365     for (int index = 0; index < (int)m_pDriver->m_StateStack.size(); ++index) {
   1366       if (!m_pDriver->m_StateStack[index]) {
   1367         printf("null\n");
   1368         continue;
   1369       }
   1370       CFX_ClipRgn::ClipType clipType =
   1371           m_pDriver->m_StateStack[index]->GetType();
   1372       const FX_RECT& box = m_pDriver->m_StateStack[index]->GetBox();
   1373       printf("stack rect: %d,%d,%d,%d mask=%s\n", box.left, box.top, box.right,
   1374              box.bottom,
   1375              CFX_ClipRgn::MaskF == clipType
   1376                  ? "1"
   1377                  : CFX_ClipRgn::RectI == clipType ? "0" : "?");
   1378     }
   1379     if (m_pDriver->m_pClipRgn) {
   1380       const FX_RECT& box = m_pDriver->m_pClipRgn->GetBox();
   1381       CFX_ClipRgn::ClipType clipType = m_pDriver->m_pClipRgn->GetType();
   1382       printf("clip rect: %d,%d,%d,%d mask=%s\n", box.left, box.top, box.right,
   1383              box.bottom,
   1384              CFX_ClipRgn::MaskF == clipType
   1385                  ? "1"
   1386                  : CFX_ClipRgn::RectI == clipType ? "0" : "?");
   1387     }
   1388   }
   1389 #endif  // SHOW_SKIA_PATH
   1390 
   1391  private:
   1392   SkTArray<SkPath> m_clips;        // stack of clips that may be reused
   1393   SkTDArray<Clip> m_commands;      // stack of clip-related commands
   1394   SkTDArray<SkPoint> m_positions;  // accumulator for text positions
   1395   SkTDArray<SkRSXform> m_rsxform;  // accumulator for txt rotate/scale/translate
   1396   SkTDArray<uint16_t> m_glyphs;    // accumulator for text glyphs
   1397   SkPath m_skPath;                 // accumulator for path contours
   1398   SkPath m_skEmptyPath;            // used as placehold in the clips array
   1399   CFX_Matrix m_drawMatrix;
   1400   CFX_GraphStateData m_clipState;
   1401   CFX_GraphStateData m_drawState;
   1402   CFX_Matrix m_clipMatrix;
   1403   UnownedPtr<CFX_SkiaDeviceDriver> m_pDriver;
   1404   UnownedPtr<CFX_TypeFace> m_pTypeFace;
   1405   float m_fontSize;
   1406   float m_scaleX;
   1407   uint32_t m_fillColor;
   1408   uint32_t m_strokeColor;
   1409   int m_blendType;
   1410   int m_commandIndex;  // active position in clip command stack
   1411   int m_drawIndex;     // position of the pending path or text draw
   1412   int m_clipIndex;     // position reflecting depth of canvas clip stacck
   1413   Accumulator m_type;  // type of pending draw
   1414   bool m_fillFullCover;
   1415   bool m_fillPath;
   1416   bool m_groupKnockout;
   1417   bool m_debugDisable;  // turn off cache for debugging
   1418 #if SHOW_SKIA_PATH
   1419  public:
   1420   mutable int m_debugSaveCounter;
   1421   static int m_debugInitCounter;
   1422 #endif
   1423 };
   1424 
   1425 #if SHOW_SKIA_PATH
   1426 int SkiaState::m_debugInitCounter;
   1427 #endif
   1428 
   1429 // convert a stroking path to scanlines
   1430 void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint,
   1431                                        const CFX_GraphStateData* pGraphState,
   1432                                        const SkMatrix& matrix) {
   1433   SkPaint::Cap cap;
   1434   switch (pGraphState->m_LineCap) {
   1435     case CFX_GraphStateData::LineCapRound:
   1436       cap = SkPaint::kRound_Cap;
   1437       break;
   1438     case CFX_GraphStateData::LineCapSquare:
   1439       cap = SkPaint::kSquare_Cap;
   1440       break;
   1441     default:
   1442       cap = SkPaint::kButt_Cap;
   1443       break;
   1444   }
   1445   SkPaint::Join join;
   1446   switch (pGraphState->m_LineJoin) {
   1447     case CFX_GraphStateData::LineJoinRound:
   1448       join = SkPaint::kRound_Join;
   1449       break;
   1450     case CFX_GraphStateData::LineJoinBevel:
   1451       join = SkPaint::kBevel_Join;
   1452       break;
   1453     default:
   1454       join = SkPaint::kMiter_Join;
   1455       break;
   1456   }
   1457   SkMatrix inverse;
   1458   if (!matrix.invert(&inverse))
   1459     return;  // give up if the matrix is degenerate, and not invertable
   1460   inverse.set(SkMatrix::kMTransX, 0);
   1461   inverse.set(SkMatrix::kMTransY, 0);
   1462   SkVector deviceUnits[2] = {{0, 1}, {1, 0}};
   1463   inverse.mapPoints(deviceUnits, SK_ARRAY_COUNT(deviceUnits));
   1464   float width =
   1465       SkTMax(pGraphState->m_LineWidth,
   1466              SkTMin(deviceUnits[0].length(), deviceUnits[1].length()));
   1467   if (pGraphState->m_DashArray) {
   1468     int count = (pGraphState->m_DashCount + 1) / 2;
   1469     std::unique_ptr<SkScalar, FxFreeDeleter> intervals(
   1470         FX_Alloc2D(SkScalar, count, sizeof(SkScalar)));
   1471     // Set dash pattern
   1472     for (int i = 0; i < count; i++) {
   1473       float on = pGraphState->m_DashArray[i * 2];
   1474       if (on <= 0.000001f)
   1475         on = 1.f / 10;
   1476       float off = i * 2 + 1 == pGraphState->m_DashCount
   1477                       ? on
   1478                       : pGraphState->m_DashArray[i * 2 + 1];
   1479       if (off < 0)
   1480         off = 0;
   1481       intervals.get()[i * 2] = on;
   1482       intervals.get()[i * 2 + 1] = off;
   1483     }
   1484     spaint->setPathEffect(SkDashPathEffect::Make(intervals.get(), count * 2,
   1485                                                  pGraphState->m_DashPhase));
   1486   }
   1487   spaint->setStyle(SkPaint::kStroke_Style);
   1488   spaint->setAntiAlias(true);
   1489   spaint->setStrokeWidth(width);
   1490   spaint->setStrokeMiter(pGraphState->m_MiterLimit);
   1491   spaint->setStrokeCap(cap);
   1492   spaint->setStrokeJoin(join);
   1493 }
   1494 
   1495 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(
   1496     const RetainPtr<CFX_DIBitmap>& pBitmap,
   1497     bool bRgbByteOrder,
   1498     const RetainPtr<CFX_DIBitmap>& pOriDevice,
   1499     bool bGroupKnockout)
   1500     : m_pBitmap(pBitmap),
   1501       m_pOriDevice(pOriDevice),
   1502       m_pRecorder(nullptr),
   1503       m_pCache(new SkiaState(this)),
   1504 #ifdef _SKIA_SUPPORT_PATHS_
   1505       m_pClipRgn(nullptr),
   1506       m_FillFlags(0),
   1507       m_bRgbByteOrder(bRgbByteOrder),
   1508 #endif  // _SKIA_SUPPORT_PATHS_
   1509       m_bGroupKnockout(bGroupKnockout) {
   1510   SkBitmap skBitmap;
   1511   SkASSERT(pBitmap->GetBPP() == 8 || pBitmap->GetBPP() == 32);
   1512   SkImageInfo imageInfo = SkImageInfo::Make(
   1513       pBitmap->GetWidth(), pBitmap->GetHeight(),
   1514       pBitmap->GetBPP() == 8 ? kAlpha_8_SkColorType : kN32_SkColorType,
   1515       kOpaque_SkAlphaType);
   1516   skBitmap.installPixels(imageInfo, pBitmap->GetBuffer(), pBitmap->GetPitch());
   1517   m_pCanvas = new SkCanvas(skBitmap);
   1518 }
   1519 
   1520 #ifdef _SKIA_SUPPORT_
   1521 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(int size_x, int size_y)
   1522     : m_pBitmap(nullptr),
   1523       m_pOriDevice(nullptr),
   1524       m_pRecorder(new SkPictureRecorder),
   1525       m_pCache(new SkiaState(this)),
   1526       m_bGroupKnockout(false) {
   1527   m_pRecorder->beginRecording(SkIntToScalar(size_x), SkIntToScalar(size_y));
   1528   m_pCanvas = m_pRecorder->getRecordingCanvas();
   1529 }
   1530 
   1531 CFX_SkiaDeviceDriver::CFX_SkiaDeviceDriver(SkPictureRecorder* recorder)
   1532     : m_pBitmap(nullptr),
   1533       m_pOriDevice(nullptr),
   1534       m_pRecorder(recorder),
   1535       m_pCache(new SkiaState(this)),
   1536       m_bGroupKnockout(false) {
   1537   m_pCanvas = m_pRecorder->getRecordingCanvas();
   1538 }
   1539 #endif  // _SKIA_SUPPORT_
   1540 
   1541 CFX_SkiaDeviceDriver::~CFX_SkiaDeviceDriver() {
   1542   Flush();
   1543   if (!m_pRecorder)
   1544     delete m_pCanvas;
   1545 }
   1546 
   1547 void CFX_SkiaDeviceDriver::Flush() {
   1548   m_pCache->Flush();
   1549 }
   1550 
   1551 void CFX_SkiaDeviceDriver::PreMultiply() {
   1552   m_pBitmap->PreMultiply();
   1553 }
   1554 
   1555 bool CFX_SkiaDeviceDriver::DrawDeviceText(int nChars,
   1556                                           const FXTEXT_CHARPOS* pCharPos,
   1557                                           CFX_Font* pFont,
   1558                                           const CFX_Matrix* pObject2Device,
   1559                                           float font_size,
   1560                                           uint32_t color) {
   1561   if (m_pCache->DrawText(nChars, pCharPos, pFont, pObject2Device, font_size,
   1562                          color)) {
   1563     return true;
   1564   }
   1565   sk_sp<SkTypeface> typeface(SkSafeRef(pFont->GetDeviceCache()));
   1566   SkPaint paint;
   1567   paint.setAntiAlias(true);
   1568   paint.setColor(color);
   1569   paint.setTypeface(typeface);
   1570   paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
   1571   paint.setHinting(SkPaint::kNo_Hinting);
   1572   paint.setTextSize(SkTAbs(font_size));
   1573   paint.setSubpixelText(true);
   1574   m_pCanvas->save();
   1575   SkScalar flip = font_size < 0 ? -1 : 1;
   1576   SkScalar vFlip = flip;
   1577   if (pFont->IsVertical())
   1578     vFlip *= -1;
   1579   SkMatrix skMatrix = ToFlippedSkMatrix(*pObject2Device, flip);
   1580   m_pCanvas->concat(skMatrix);
   1581   SkTDArray<SkPoint> positions;
   1582   positions.setCount(nChars);
   1583   SkTDArray<uint16_t> glyphs;
   1584   glyphs.setCount(nChars);
   1585   bool useRSXform = false;
   1586   bool oneAtATime = false;
   1587   for (int index = 0; index < nChars; ++index) {
   1588     const FXTEXT_CHARPOS& cp = pCharPos[index];
   1589     positions[index] = {cp.m_Origin.x * flip, cp.m_Origin.y * vFlip};
   1590     if (cp.m_bGlyphAdjust) {
   1591       useRSXform = true;
   1592       if (cp.m_AdjustMatrix[0] != cp.m_AdjustMatrix[3] ||
   1593           cp.m_AdjustMatrix[1] != -cp.m_AdjustMatrix[2]) {
   1594         oneAtATime = true;
   1595       }
   1596     }
   1597     glyphs[index] = static_cast<uint16_t>(cp.m_GlyphIndex);
   1598 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
   1599     if (cp.m_ExtGID)
   1600       glyphs[index] = static_cast<uint16_t>(cp.m_ExtGID);
   1601 #endif
   1602   }
   1603   if (oneAtATime)
   1604     useRSXform = false;
   1605 #if SHOW_TEXT_GLYPHS
   1606   SkTDArray<SkUnichar> text;
   1607   text.setCount(glyphs.count());
   1608   paint.glyphsToUnichars(glyphs.begin(), glyphs.count(), text.begin());
   1609   for (size_t i = 0; i < glyphs.count(); ++i)
   1610     printf("%lc", text[i]);
   1611   printf("\n");
   1612 #endif
   1613 #ifdef _SKIA_SUPPORT_PATHS_
   1614   m_pBitmap->PreMultiply();
   1615 #endif  // _SKIA_SUPPORT_PATHS_
   1616   if (useRSXform) {
   1617     SkTDArray<SkRSXform> xforms;
   1618     xforms.setCount(nChars);
   1619     for (int index = 0; index < nChars; ++index) {
   1620       const FXTEXT_CHARPOS& cp = pCharPos[index];
   1621       SkRSXform* rsxform = &xforms[index];
   1622       if (cp.m_bGlyphAdjust) {
   1623         rsxform->fSCos = cp.m_AdjustMatrix[0];
   1624         rsxform->fSSin = cp.m_AdjustMatrix[1];
   1625         rsxform->fTx = cp.m_AdjustMatrix[0] * positions[index].fX;
   1626         rsxform->fTy = cp.m_AdjustMatrix[1] * positions[index].fY;
   1627       } else {
   1628         rsxform->fSCos = 1;
   1629         rsxform->fSSin = 0;
   1630         rsxform->fTx = positions[index].fX;
   1631         rsxform->fTy = positions[index].fY;
   1632       }
   1633     }
   1634     m_pCanvas->drawTextRSXform(glyphs.begin(), nChars * 2, xforms.begin(),
   1635                                nullptr, paint);
   1636   } else if (oneAtATime) {
   1637     for (int index = 0; index < nChars; ++index) {
   1638       const FXTEXT_CHARPOS& cp = pCharPos[index];
   1639       if (cp.m_bGlyphAdjust) {
   1640         if (0 == cp.m_AdjustMatrix[1] && 0 == cp.m_AdjustMatrix[2] &&
   1641             1 == cp.m_AdjustMatrix[3]) {
   1642           paint.setTextScaleX(cp.m_AdjustMatrix[0]);
   1643           m_pCanvas->drawText(&glyphs[index], 1, positions[index].fX,
   1644                               positions[index].fY, paint);
   1645           paint.setTextScaleX(1);
   1646         } else {
   1647           m_pCanvas->save();
   1648           SkMatrix adjust;
   1649           adjust.reset();
   1650           adjust.setScaleX(cp.m_AdjustMatrix[0]);
   1651           adjust.setSkewX(cp.m_AdjustMatrix[1]);
   1652           adjust.setSkewY(cp.m_AdjustMatrix[2]);
   1653           adjust.setScaleY(cp.m_AdjustMatrix[3]);
   1654           adjust.preTranslate(positions[index].fX, positions[index].fY);
   1655           m_pCanvas->concat(adjust);
   1656           m_pCanvas->drawText(&glyphs[index], 1, 0, 0, paint);
   1657           m_pCanvas->restore();
   1658         }
   1659       } else {
   1660         m_pCanvas->drawText(&glyphs[index], 1, positions[index].fX,
   1661                             positions[index].fY, paint);
   1662       }
   1663     }
   1664   } else {
   1665     m_pCanvas->drawPosText(glyphs.begin(), nChars * 2, positions.begin(),
   1666                            paint);
   1667   }
   1668   m_pCanvas->restore();
   1669 
   1670   return true;
   1671 }
   1672 
   1673 int CFX_SkiaDeviceDriver::GetDeviceCaps(int caps_id) const {
   1674   switch (caps_id) {
   1675     case FXDC_DEVICE_CLASS:
   1676       return FXDC_DISPLAY;
   1677 #ifdef _SKIA_SUPPORT_
   1678     case FXDC_PIXEL_WIDTH:
   1679       return m_pCanvas->imageInfo().width();
   1680     case FXDC_PIXEL_HEIGHT:
   1681       return m_pCanvas->imageInfo().height();
   1682     case FXDC_BITS_PIXEL:
   1683       return 32;
   1684     case FXDC_HORZ_SIZE:
   1685     case FXDC_VERT_SIZE:
   1686       return 0;
   1687     case FXDC_RENDER_CAPS:
   1688       return FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
   1689              FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_ALPHA_OUTPUT |
   1690              FXRC_FILLSTROKE_PATH | FXRC_SHADING;
   1691 #endif  // _SKIA_SUPPORT_
   1692 
   1693 #ifdef _SKIA_SUPPORT_PATHS_
   1694     case FXDC_PIXEL_WIDTH:
   1695       return m_pBitmap->GetWidth();
   1696     case FXDC_PIXEL_HEIGHT:
   1697       return m_pBitmap->GetHeight();
   1698     case FXDC_BITS_PIXEL:
   1699       return m_pBitmap->GetBPP();
   1700     case FXDC_HORZ_SIZE:
   1701     case FXDC_VERT_SIZE:
   1702       return 0;
   1703     case FXDC_RENDER_CAPS: {
   1704       int flags = FXRC_GET_BITS | FXRC_ALPHA_PATH | FXRC_ALPHA_IMAGE |
   1705                   FXRC_BLEND_MODE | FXRC_SOFT_CLIP | FXRC_SHADING;
   1706       if (m_pBitmap->HasAlpha()) {
   1707         flags |= FXRC_ALPHA_OUTPUT;
   1708       } else if (m_pBitmap->IsAlphaMask()) {
   1709         if (m_pBitmap->GetBPP() == 1) {
   1710           flags |= FXRC_BITMASK_OUTPUT;
   1711         } else {
   1712           flags |= FXRC_BYTEMASK_OUTPUT;
   1713         }
   1714       }
   1715       if (m_pBitmap->IsCmykImage()) {
   1716         flags |= FXRC_CMYK_OUTPUT;
   1717       }
   1718       return flags;
   1719     }
   1720 #endif  // _SKIA_SUPPORT_PATHS_
   1721   }
   1722   return 0;
   1723 }
   1724 
   1725 void CFX_SkiaDeviceDriver::SaveState() {
   1726   m_pCache->DebugCheckClip();
   1727   if (!m_pCache->ClipSave())
   1728     m_pCanvas->save();
   1729 
   1730 #ifdef _SKIA_SUPPORT_PATHS_
   1731 #if SHOW_SKIA_PATH
   1732   printf("SaveState %zd\n", m_StateStack.size());
   1733 #endif
   1734   std::unique_ptr<CFX_ClipRgn> pClip;
   1735   if (m_pClipRgn)
   1736     pClip = pdfium::MakeUnique<CFX_ClipRgn>(*m_pClipRgn);
   1737   m_StateStack.push_back(std::move(pClip));
   1738 #endif  // _SKIA_SUPPORT_PATHS_
   1739 }
   1740 
   1741 void CFX_SkiaDeviceDriver::RestoreState(bool bKeepSaved) {
   1742 #ifdef _SKIA_SUPPORT_PATHS_
   1743   m_pClipRgn.reset();
   1744 
   1745   if (m_StateStack.empty())
   1746     return;
   1747 #else
   1748   if (m_pCache->IsEmpty())
   1749     return;
   1750 #endif
   1751   if (!m_pCache->ClipRestore())
   1752     m_pCanvas->restore();
   1753   if (bKeepSaved && !m_pCache->ClipSave())
   1754     m_pCanvas->save();
   1755 #ifdef _SKIA_SUPPORT_PATHS_
   1756 #if SHOW_SKIA_PATH
   1757   printf("RestoreState %zd %s\n", m_StateStack.size(),
   1758          bKeepSaved ? "bKeepSaved" : "");
   1759 #endif
   1760   if (bKeepSaved) {
   1761     if (m_StateStack.back())
   1762       m_pClipRgn = pdfium::MakeUnique<CFX_ClipRgn>(*m_StateStack.back());
   1763   } else {
   1764     m_pClipRgn = std::move(m_StateStack.back());
   1765     m_StateStack.pop_back();
   1766   }
   1767   m_pCache->DebugCheckClip();
   1768 #endif  // _SKIA_SUPPORT_PATHS_
   1769 }
   1770 
   1771 #ifdef _SKIA_SUPPORT_PATHS_
   1772 void CFX_SkiaDeviceDriver::SetClipMask(const FX_RECT& clipBox,
   1773                                        const SkPath& path) {
   1774   FX_RECT path_rect(clipBox.left, clipBox.top, clipBox.right + 1,
   1775                     clipBox.bottom + 1);
   1776   path_rect.Intersect(m_pClipRgn->GetBox());
   1777   auto pThisLayer = pdfium::MakeRetain<CFX_DIBitmap>();
   1778   pThisLayer->Create(path_rect.Width(), path_rect.Height(), FXDIB_8bppMask);
   1779   pThisLayer->Clear(0);
   1780 
   1781   SkImageInfo imageInfo =
   1782       SkImageInfo::Make(pThisLayer->GetWidth(), pThisLayer->GetHeight(),
   1783                         SkColorType::kAlpha_8_SkColorType, kOpaque_SkAlphaType);
   1784   SkBitmap bitmap;
   1785   bitmap.installPixels(imageInfo, pThisLayer->GetBuffer(),
   1786                        pThisLayer->GetPitch());
   1787   auto canvas = pdfium::MakeUnique<SkCanvas>(bitmap);
   1788   canvas->translate(
   1789       -path_rect.left,
   1790       -path_rect.top);  // FIXME(caryclark) wrong sign(s)? upside down?
   1791   SkPaint paint;
   1792   paint.setAntiAlias((m_FillFlags & FXFILL_NOPATHSMOOTH) == 0);
   1793   canvas->drawPath(path, paint);
   1794   m_pClipRgn->IntersectMaskF(path_rect.left, path_rect.top, pThisLayer);
   1795 }
   1796 #endif  // _SKIA_SUPPORT_PATHS_
   1797 
   1798 bool CFX_SkiaDeviceDriver::SetClip_PathFill(
   1799     const CFX_PathData* pPathData,     // path info
   1800     const CFX_Matrix* pObject2Device,  // flips object's y-axis
   1801     int fill_mode                      // fill mode, WINDING or ALTERNATE
   1802     ) {
   1803   CFX_Matrix identity;
   1804   const CFX_Matrix* deviceMatrix = pObject2Device ? pObject2Device : &identity;
   1805   bool cached = m_pCache->SetClipFill(pPathData, deviceMatrix, fill_mode);
   1806 
   1807 #ifdef _SKIA_SUPPORT_PATHS_
   1808   m_FillFlags = fill_mode;
   1809   if (!m_pClipRgn) {
   1810     m_pClipRgn = pdfium::MakeUnique<CFX_ClipRgn>(
   1811         GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
   1812   }
   1813 #endif  // _SKIA_SUPPORT_PATHS_
   1814   if (pPathData->GetPoints().size() == 5 ||
   1815       pPathData->GetPoints().size() == 4) {
   1816     CFX_FloatRect rectf;
   1817     if (pPathData->IsRect(deviceMatrix, &rectf)) {
   1818       rectf.Intersect(CFX_FloatRect(0, 0,
   1819                                     (float)GetDeviceCaps(FXDC_PIXEL_WIDTH),
   1820                                     (float)GetDeviceCaps(FXDC_PIXEL_HEIGHT)));
   1821       // note that PDF's y-axis goes up; Skia's y-axis goes down
   1822       if (!cached) {
   1823         SkRect skClipRect =
   1824             SkRect::MakeLTRB(rectf.left, rectf.bottom, rectf.right, rectf.top);
   1825         DebugDrawSkiaClipRect(m_pCanvas, skClipRect);
   1826         m_pCanvas->clipRect(skClipRect, SkClipOp::kIntersect, true);
   1827       }
   1828 
   1829 #ifdef _SKIA_SUPPORT_PATHS_
   1830       FX_RECT rect = rectf.GetOuterRect();
   1831       m_pClipRgn->IntersectRect(rect);
   1832 #endif  // _SKIA_SUPPORT_PATHS_
   1833       DebugShowCanvasClip(this, m_pCanvas);
   1834       return true;
   1835     }
   1836   }
   1837   SkPath skClipPath = BuildPath(pPathData);
   1838   skClipPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE
   1839                              ? SkPath::kEvenOdd_FillType
   1840                              : SkPath::kWinding_FillType);
   1841   SkMatrix skMatrix = ToSkMatrix(*deviceMatrix);
   1842   skClipPath.transform(skMatrix);
   1843   DebugShowSkiaPath(skClipPath);
   1844   if (!cached) {
   1845     DebugDrawSkiaClipPath(m_pCanvas, skClipPath);
   1846     m_pCanvas->clipPath(skClipPath, SkClipOp::kIntersect, true);
   1847   }
   1848 #ifdef _SKIA_SUPPORT_PATHS_
   1849   FX_RECT clipBox(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH),
   1850                   GetDeviceCaps(FXDC_PIXEL_HEIGHT));
   1851   SetClipMask(clipBox, skClipPath);
   1852 #endif  // _SKIA_SUPPORT_PATHS_
   1853   DebugShowCanvasClip(this, m_pCanvas);
   1854   return true;
   1855 }
   1856 
   1857 bool CFX_SkiaDeviceDriver::SetClip_PathStroke(
   1858     const CFX_PathData* pPathData,         // path info
   1859     const CFX_Matrix* pObject2Device,      // optional transformation
   1860     const CFX_GraphStateData* pGraphState  // graphic state, for pen attributes
   1861     ) {
   1862   bool cached = m_pCache->SetClipStroke(pPathData, pObject2Device, pGraphState);
   1863 
   1864 #ifdef _SKIA_SUPPORT_PATHS_
   1865   if (!m_pClipRgn) {
   1866     m_pClipRgn = pdfium::MakeUnique<CFX_ClipRgn>(
   1867         GetDeviceCaps(FXDC_PIXEL_WIDTH), GetDeviceCaps(FXDC_PIXEL_HEIGHT));
   1868   }
   1869 #endif  // _SKIA_SUPPORT_PATHS_
   1870   // build path data
   1871   SkPath skPath = BuildPath(pPathData);
   1872   SkMatrix skMatrix = ToSkMatrix(*pObject2Device);
   1873   SkPaint skPaint;
   1874   PaintStroke(&skPaint, pGraphState, skMatrix);
   1875   SkPath dst_path;
   1876   skPaint.getFillPath(skPath, &dst_path);
   1877   dst_path.transform(skMatrix);
   1878   if (!cached) {
   1879     DebugDrawSkiaClipPath(m_pCanvas, dst_path);
   1880     m_pCanvas->clipPath(dst_path, SkClipOp::kIntersect, true);
   1881   }
   1882 #ifdef _SKIA_SUPPORT_PATHS_
   1883   FX_RECT clipBox(0, 0, GetDeviceCaps(FXDC_PIXEL_WIDTH),
   1884                   GetDeviceCaps(FXDC_PIXEL_HEIGHT));
   1885   SetClipMask(clipBox, dst_path);
   1886 #endif  // _SKIA_SUPPORT_PATHS_
   1887   DebugShowCanvasClip(this, m_pCanvas);
   1888   return true;
   1889 }
   1890 
   1891 bool CFX_SkiaDeviceDriver::DrawPath(
   1892     const CFX_PathData* pPathData,          // path info
   1893     const CFX_Matrix* pObject2Device,       // optional transformation
   1894     const CFX_GraphStateData* pGraphState,  // graphic state, for pen attributes
   1895     uint32_t fill_color,                    // fill color
   1896     uint32_t stroke_color,                  // stroke color
   1897     int fill_mode,  // fill mode, WINDING or ALTERNATE. 0 for not filled
   1898     int blend_type) {
   1899   if (fill_mode & FX_ZEROAREA_FILL)
   1900     return true;
   1901   if (m_pCache->DrawPath(pPathData, pObject2Device, pGraphState, fill_color,
   1902                          stroke_color, fill_mode, blend_type)) {
   1903     return true;
   1904   }
   1905   SkMatrix skMatrix;
   1906   if (pObject2Device)
   1907     skMatrix = ToSkMatrix(*pObject2Device);
   1908   else
   1909     skMatrix.setIdentity();
   1910   SkPaint skPaint;
   1911   skPaint.setAntiAlias(true);
   1912   if (fill_mode & FXFILL_FULLCOVER)
   1913     skPaint.setBlendMode(SkBlendMode::kPlus);
   1914   int stroke_alpha = FXARGB_A(stroke_color);
   1915   if (pGraphState && stroke_alpha)
   1916     PaintStroke(&skPaint, pGraphState, skMatrix);
   1917   SkPath skPath = BuildPath(pPathData);
   1918   m_pCanvas->save();
   1919   m_pCanvas->concat(skMatrix);
   1920   if ((fill_mode & 3) && fill_color) {
   1921     skPath.setFillType((fill_mode & 3) == FXFILL_ALTERNATE
   1922                            ? SkPath::kEvenOdd_FillType
   1923                            : SkPath::kWinding_FillType);
   1924     SkPath strokePath;
   1925     const SkPath* fillPath = &skPath;
   1926     if (pGraphState && stroke_alpha) {
   1927       if (m_bGroupKnockout) {
   1928         skPaint.getFillPath(skPath, &strokePath);
   1929         if (Op(skPath, strokePath, SkPathOp::kDifference_SkPathOp,
   1930                &strokePath)) {
   1931           fillPath = &strokePath;
   1932         }
   1933       }
   1934     }
   1935     skPaint.setStyle(SkPaint::kFill_Style);
   1936     skPaint.setColor(fill_color);
   1937 #ifdef _SKIA_SUPPORT_PATHS_
   1938     m_pBitmap->PreMultiply();
   1939 #endif  // _SKIA_SUPPORT_PATHS_
   1940     DebugShowSkiaDrawPath(this, m_pCanvas, skPaint, *fillPath);
   1941     m_pCanvas->drawPath(*fillPath, skPaint);
   1942   }
   1943   if (pGraphState && stroke_alpha) {
   1944     skPaint.setStyle(SkPaint::kStroke_Style);
   1945     skPaint.setColor(stroke_color);
   1946 #ifdef _SKIA_SUPPORT_PATHS_
   1947     m_pBitmap->PreMultiply();
   1948 #endif  // _SKIA_SUPPORT_PATHS_
   1949     DebugShowSkiaDrawPath(this, m_pCanvas, skPaint, skPath);
   1950     m_pCanvas->drawPath(skPath, skPaint);
   1951   }
   1952   m_pCanvas->restore();
   1953   return true;
   1954 }
   1955 
   1956 bool CFX_SkiaDeviceDriver::DrawCosmeticLine(const CFX_PointF& ptMoveTo,
   1957                                             const CFX_PointF& ptLineTo,
   1958                                             uint32_t color,
   1959                                             int blend_type) {
   1960   return false;
   1961 }
   1962 
   1963 bool CFX_SkiaDeviceDriver::FillRectWithBlend(const FX_RECT* pRect,
   1964                                              uint32_t fill_color,
   1965                                              int blend_type) {
   1966   m_pCache->FlushForDraw();
   1967   SkPaint spaint;
   1968   spaint.setAntiAlias(true);
   1969   spaint.setColor(fill_color);
   1970   spaint.setBlendMode(GetSkiaBlendMode(blend_type));
   1971   SkRect rect =
   1972       SkRect::MakeLTRB(pRect->left, SkTMin(pRect->top, pRect->bottom),
   1973                        pRect->right, SkTMax(pRect->bottom, pRect->top));
   1974   DebugShowSkiaDrawRect(this, m_pCanvas, spaint, rect);
   1975   m_pCanvas->drawRect(rect, spaint);
   1976   return true;
   1977 }
   1978 
   1979 bool CFX_SkiaDeviceDriver::DrawShading(const CPDF_ShadingPattern* pPattern,
   1980                                        const CFX_Matrix* pMatrix,
   1981                                        const FX_RECT& clip_rect,
   1982                                        int alpha,
   1983                                        bool bAlphaMode) {
   1984   m_pCache->FlushForDraw();
   1985   ShadingType shadingType = pPattern->GetShadingType();
   1986   if (kAxialShading != shadingType && kRadialShading != shadingType &&
   1987       kCoonsPatchMeshShading != shadingType) {
   1988     // TODO(caryclark) more types
   1989     return false;
   1990   }
   1991   int csFamily = pPattern->GetCS()->GetFamily();
   1992   if (PDFCS_DEVICERGB != csFamily && PDFCS_DEVICEGRAY != csFamily)
   1993     return false;
   1994   const std::vector<std::unique_ptr<CPDF_Function>>& pFuncs =
   1995       pPattern->GetFuncs();
   1996   int nFuncs = pFuncs.size();
   1997   if (nFuncs > 1)  // TODO(caryclark) remove this restriction
   1998     return false;
   1999   CPDF_Dictionary* pDict = pPattern->GetShadingObject()->GetDict();
   2000   CPDF_Array* pCoords = pDict->GetArrayFor("Coords");
   2001   if (!pCoords && kCoonsPatchMeshShading != shadingType)
   2002     return false;
   2003   // TODO(caryclark) Respect Domain[0], Domain[1]. (Don't know what they do
   2004   // yet.)
   2005   SkTDArray<SkColor> skColors;
   2006   SkTDArray<SkScalar> skPos;
   2007   for (int j = 0; j < nFuncs; j++) {
   2008     if (!pFuncs[j])
   2009       continue;
   2010 
   2011     if (const CPDF_SampledFunc* pSampledFunc = pFuncs[j]->ToSampledFunc()) {
   2012       /* TODO(caryclark)
   2013          Type 0 Sampled Functions in PostScript can also have an Order integer
   2014          in the dictionary. PDFium doesn't appear to check for this anywhere.
   2015        */
   2016       if (!AddSamples(pSampledFunc, &skColors, &skPos))
   2017         return false;
   2018     } else if (const CPDF_ExpIntFunc* pExpIntFuc = pFuncs[j]->ToExpIntFunc()) {
   2019       if (!AddColors(pExpIntFuc, &skColors))
   2020         return false;
   2021       skPos.push(0);
   2022       skPos.push(1);
   2023     } else if (const CPDF_StitchFunc* pStitchFunc = pFuncs[j]->ToStitchFunc()) {
   2024       if (!AddStitching(pStitchFunc, &skColors, &skPos))
   2025         return false;
   2026     } else {
   2027       return false;
   2028     }
   2029   }
   2030   CPDF_Array* pArray = pDict->GetArrayFor("Extend");
   2031   bool clipStart = !pArray || !pArray->GetIntegerAt(0);
   2032   bool clipEnd = !pArray || !pArray->GetIntegerAt(1);
   2033   SkPaint paint;
   2034   paint.setAntiAlias(true);
   2035   paint.setAlpha(alpha);
   2036   SkMatrix skMatrix = ToSkMatrix(*pMatrix);
   2037   SkRect skRect = SkRect::MakeLTRB(clip_rect.left, clip_rect.top,
   2038                                    clip_rect.right, clip_rect.bottom);
   2039   SkPath skClip;
   2040   SkPath skPath;
   2041   if (kAxialShading == shadingType) {
   2042     float start_x = pCoords->GetNumberAt(0);
   2043     float start_y = pCoords->GetNumberAt(1);
   2044     float end_x = pCoords->GetNumberAt(2);
   2045     float end_y = pCoords->GetNumberAt(3);
   2046     SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}};
   2047     skMatrix.mapPoints(pts, SK_ARRAY_COUNT(pts));
   2048     paint.setShader(SkGradientShader::MakeLinear(
   2049         pts, skColors.begin(), skPos.begin(), skColors.count(),
   2050         SkShader::kClamp_TileMode));
   2051     if (clipStart || clipEnd) {
   2052       // if the gradient is horizontal or vertical, modify the draw rectangle
   2053       if (pts[0].fX == pts[1].fX) {  // vertical
   2054         if (pts[0].fY > pts[1].fY) {
   2055           SkTSwap(pts[0].fY, pts[1].fY);
   2056           SkTSwap(clipStart, clipEnd);
   2057         }
   2058         if (clipStart)
   2059           skRect.fTop = SkTMax(skRect.fTop, pts[0].fY);
   2060         if (clipEnd)
   2061           skRect.fBottom = SkTMin(skRect.fBottom, pts[1].fY);
   2062       } else if (pts[0].fY == pts[1].fY) {  // horizontal
   2063         if (pts[0].fX > pts[1].fX) {
   2064           SkTSwap(pts[0].fX, pts[1].fX);
   2065           SkTSwap(clipStart, clipEnd);
   2066         }
   2067         if (clipStart)
   2068           skRect.fLeft = SkTMax(skRect.fLeft, pts[0].fX);
   2069         if (clipEnd)
   2070           skRect.fRight = SkTMin(skRect.fRight, pts[1].fX);
   2071       } else {  // if the gradient is angled and contained by the rect, clip
   2072         SkPoint rectPts[4] = {{skRect.fLeft, skRect.fTop},
   2073                               {skRect.fRight, skRect.fTop},
   2074                               {skRect.fRight, skRect.fBottom},
   2075                               {skRect.fLeft, skRect.fBottom}};
   2076         ClipAngledGradient(pts, rectPts, clipStart, clipEnd, &skClip);
   2077       }
   2078     }
   2079     skPath.addRect(skRect);
   2080     skMatrix.setIdentity();
   2081   } else if (kRadialShading == shadingType) {
   2082     float start_x = pCoords->GetNumberAt(0);
   2083     float start_y = pCoords->GetNumberAt(1);
   2084     float start_r = pCoords->GetNumberAt(2);
   2085     float end_x = pCoords->GetNumberAt(3);
   2086     float end_y = pCoords->GetNumberAt(4);
   2087     float end_r = pCoords->GetNumberAt(5);
   2088     SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}};
   2089 
   2090     paint.setShader(SkGradientShader::MakeTwoPointConical(
   2091         pts[0], start_r, pts[1], end_r, skColors.begin(), skPos.begin(),
   2092         skColors.count(), SkShader::kClamp_TileMode));
   2093     if (clipStart || clipEnd) {
   2094       if (clipStart && start_r)
   2095         skClip.addCircle(pts[0].fX, pts[0].fY, start_r);
   2096       if (clipEnd)
   2097         skClip.addCircle(pts[1].fX, pts[1].fY, end_r, SkPath::kCCW_Direction);
   2098       else
   2099         skClip.setFillType(SkPath::kInverseWinding_FillType);
   2100       skClip.transform(skMatrix);
   2101     }
   2102     SkMatrix inverse;
   2103     if (!skMatrix.invert(&inverse))
   2104       return false;
   2105     skPath.addRect(skRect);
   2106     skPath.transform(inverse);
   2107   } else {
   2108     ASSERT(kCoonsPatchMeshShading == shadingType);
   2109     CPDF_Stream* pStream = ToStream(pPattern->GetShadingObject());
   2110     if (!pStream)
   2111       return false;
   2112     CPDF_MeshStream stream(shadingType, pPattern->GetFuncs(), pStream,
   2113                            pPattern->GetCS());
   2114     if (!stream.Load())
   2115       return false;
   2116     SkPoint cubics[12];
   2117     SkColor colors[4];
   2118     m_pCanvas->save();
   2119     if (!skClip.isEmpty())
   2120       m_pCanvas->clipPath(skClip, SkClipOp::kIntersect, true);
   2121     m_pCanvas->concat(skMatrix);
   2122     while (!stream.BitStream()->IsEOF()) {
   2123       uint32_t flag = stream.ReadFlag();
   2124       int iStartPoint = flag ? 4 : 0;
   2125       int iStartColor = flag ? 2 : 0;
   2126       if (flag) {
   2127         SkPoint tempCubics[4];
   2128         for (int i = 0; i < (int)SK_ARRAY_COUNT(tempCubics); i++)
   2129           tempCubics[i] = cubics[(flag * 3 + i) % 12];
   2130         memcpy(cubics, tempCubics, sizeof(tempCubics));
   2131         SkColor tempColors[2];
   2132         tempColors[0] = colors[flag];
   2133         tempColors[1] = colors[(flag + 1) % 4];
   2134         memcpy(colors, tempColors, sizeof(tempColors));
   2135       }
   2136       for (int i = iStartPoint; i < (int)SK_ARRAY_COUNT(cubics); i++) {
   2137         CFX_PointF point = stream.ReadCoords();
   2138         cubics[i].fX = point.x;
   2139         cubics[i].fY = point.y;
   2140       }
   2141       for (int i = iStartColor; i < (int)SK_ARRAY_COUNT(colors); i++) {
   2142         float r;
   2143         float g;
   2144         float b;
   2145         std::tie(r, g, b) = stream.ReadColor();
   2146         colors[i] = SkColorSetARGBInline(0xFF, (U8CPU)(r * 255),
   2147                                          (U8CPU)(g * 255), (U8CPU)(b * 255));
   2148       }
   2149       m_pCanvas->drawPatch(cubics, colors, nullptr, paint);
   2150     }
   2151     m_pCanvas->restore();
   2152     return true;
   2153   }
   2154   m_pCanvas->save();
   2155   if (!skClip.isEmpty())
   2156     m_pCanvas->clipPath(skClip, SkClipOp::kIntersect, true);
   2157   m_pCanvas->concat(skMatrix);
   2158   m_pCanvas->drawPath(skPath, paint);
   2159   m_pCanvas->restore();
   2160   return true;
   2161 }
   2162 
   2163 uint8_t* CFX_SkiaDeviceDriver::GetBuffer() const {
   2164   return m_pBitmap->GetBuffer();
   2165 }
   2166 
   2167 bool CFX_SkiaDeviceDriver::GetClipBox(FX_RECT* pRect) {
   2168 #ifdef _SKIA_SUPPORT_PATHS_
   2169   if (!m_pClipRgn) {
   2170     pRect->left = pRect->top = 0;
   2171     pRect->right = GetDeviceCaps(FXDC_PIXEL_WIDTH);
   2172     pRect->bottom = GetDeviceCaps(FXDC_PIXEL_HEIGHT);
   2173     return true;
   2174   }
   2175   *pRect = m_pClipRgn->GetBox();
   2176 #else
   2177   // TODO(caryclark) call m_canvas->getClipDeviceBounds() instead
   2178   pRect->left = 0;
   2179   pRect->top = 0;
   2180   const SkImageInfo& canvasSize = m_pCanvas->imageInfo();
   2181   pRect->right = canvasSize.width();
   2182   pRect->bottom = canvasSize.height();
   2183 #endif
   2184   return true;
   2185 }
   2186 
   2187 bool CFX_SkiaDeviceDriver::GetDIBits(const RetainPtr<CFX_DIBitmap>& pBitmap,
   2188                                      int left,
   2189                                      int top) {
   2190   if (!m_pBitmap)
   2191     return true;
   2192   uint8_t* srcBuffer = m_pBitmap->GetBuffer();
   2193   if (!srcBuffer)
   2194     return true;
   2195 #ifdef _SKIA_SUPPORT_
   2196   m_pCache->FlushForDraw();
   2197   int srcWidth = m_pBitmap->GetWidth();
   2198   int srcHeight = m_pBitmap->GetHeight();
   2199   int srcRowBytes = srcWidth * sizeof(uint32_t);
   2200   SkImageInfo srcImageInfo = SkImageInfo::Make(
   2201       srcWidth, srcHeight, SkColorType::kN32_SkColorType, kPremul_SkAlphaType);
   2202   SkBitmap skSrcBitmap;
   2203   skSrcBitmap.installPixels(srcImageInfo, srcBuffer, srcRowBytes);
   2204   SkASSERT(pBitmap);
   2205   uint8_t* dstBuffer = pBitmap->GetBuffer();
   2206   SkASSERT(dstBuffer);
   2207   int dstWidth = pBitmap->GetWidth();
   2208   int dstHeight = pBitmap->GetHeight();
   2209   int dstRowBytes = dstWidth * sizeof(uint32_t);
   2210   SkImageInfo dstImageInfo = SkImageInfo::Make(
   2211       dstWidth, dstHeight, SkColorType::kN32_SkColorType, kPremul_SkAlphaType);
   2212   SkBitmap skDstBitmap;
   2213   skDstBitmap.installPixels(dstImageInfo, dstBuffer, dstRowBytes);
   2214   SkCanvas canvas(skDstBitmap);
   2215   canvas.drawBitmap(skSrcBitmap, left, top, nullptr);
   2216   return true;
   2217 #endif  // _SKIA_SUPPORT_
   2218 
   2219 #ifdef _SKIA_SUPPORT_PATHS_
   2220   Flush();
   2221   m_pBitmap->UnPreMultiply();
   2222   FX_RECT rect(left, top, left + pBitmap->GetWidth(),
   2223                top + pBitmap->GetHeight());
   2224   RetainPtr<CFX_DIBitmap> pBack;
   2225   if (m_pOriDevice) {
   2226     pBack = m_pOriDevice->Clone(&rect);
   2227     if (!pBack)
   2228       return true;
   2229 
   2230     pBack->CompositeBitmap(0, 0, pBack->GetWidth(), pBack->GetHeight(),
   2231                            m_pBitmap, 0, 0);
   2232   } else {
   2233     pBack = m_pBitmap->Clone(&rect);
   2234     if (!pBack)
   2235       return true;
   2236   }
   2237 
   2238   bool bRet = true;
   2239   left = std::min(left, 0);
   2240   top = std::min(top, 0);
   2241   if (m_bRgbByteOrder) {
   2242     RgbByteOrderTransferBitmap(pBitmap, 0, 0, rect.Width(), rect.Height(),
   2243                                pBack, left, top);
   2244   } else {
   2245     bRet = pBitmap->TransferBitmap(0, 0, rect.Width(), rect.Height(), pBack,
   2246                                    left, top);
   2247   }
   2248   return bRet;
   2249 #endif  // _SKIA_SUPPORT_PATHS_
   2250 }
   2251 
   2252 RetainPtr<CFX_DIBitmap> CFX_SkiaDeviceDriver::GetBackDrop() {
   2253   return m_pOriDevice;
   2254 }
   2255 
   2256 bool CFX_SkiaDeviceDriver::SetDIBits(const RetainPtr<CFX_DIBSource>& pBitmap,
   2257                                      uint32_t argb,
   2258                                      const FX_RECT* pSrcRect,
   2259                                      int left,
   2260                                      int top,
   2261                                      int blend_type) {
   2262   if (!m_pBitmap || !m_pBitmap->GetBuffer())
   2263     return true;
   2264 
   2265 #ifdef _SKIA_SUPPORT_
   2266   CFX_Matrix m(pBitmap->GetWidth(), 0, 0, -pBitmap->GetHeight(), left,
   2267                top + pBitmap->GetHeight());
   2268   std::unique_ptr<CFX_ImageRenderer> dummy;
   2269   return StartDIBits(pBitmap, 0xFF, argb, &m, 0, &dummy, blend_type);
   2270 #endif  // _SKIA_SUPPORT_
   2271 
   2272 #ifdef _SKIA_SUPPORT_PATHS_
   2273   Flush();
   2274   if (pBitmap->IsAlphaMask()) {
   2275     return m_pBitmap->CompositeMask(left, top, pSrcRect->Width(),
   2276                                     pSrcRect->Height(), pBitmap, argb,
   2277                                     pSrcRect->left, pSrcRect->top, blend_type,
   2278                                     m_pClipRgn.get(), m_bRgbByteOrder, 0);
   2279   }
   2280   return m_pBitmap->CompositeBitmap(
   2281       left, top, pSrcRect->Width(), pSrcRect->Height(), pBitmap, pSrcRect->left,
   2282       pSrcRect->top, blend_type, m_pClipRgn.get(), m_bRgbByteOrder);
   2283 #endif  // _SKIA_SUPPORT_PATHS_
   2284 }
   2285 
   2286 bool CFX_SkiaDeviceDriver::StretchDIBits(
   2287     const RetainPtr<CFX_DIBSource>& pSource,
   2288     uint32_t argb,
   2289     int dest_left,
   2290     int dest_top,
   2291     int dest_width,
   2292     int dest_height,
   2293     const FX_RECT* pClipRect,
   2294     uint32_t flags,
   2295     int blend_type) {
   2296 #ifdef _SKIA_SUPPORT_
   2297   m_pCache->FlushForDraw();
   2298   if (!m_pBitmap->GetBuffer())
   2299     return true;
   2300   CFX_Matrix m(dest_width, 0, 0, -dest_height, dest_left,
   2301                dest_top + dest_height);
   2302 
   2303   m_pCanvas->save();
   2304   SkRect skClipRect = SkRect::MakeLTRB(pClipRect->left, pClipRect->bottom,
   2305                                        pClipRect->right, pClipRect->top);
   2306   m_pCanvas->clipRect(skClipRect, SkClipOp::kIntersect, true);
   2307   std::unique_ptr<CFX_ImageRenderer> dummy;
   2308   bool result = StartDIBits(pSource, 0xFF, argb, &m, 0, &dummy, blend_type);
   2309   m_pCanvas->restore();
   2310 
   2311   return result;
   2312 #endif  // _SKIA_SUPPORT_
   2313 
   2314 #ifdef _SKIA_SUPPORT_PATHS_
   2315   if (dest_width == pSource->GetWidth() &&
   2316       dest_height == pSource->GetHeight()) {
   2317     FX_RECT rect(0, 0, dest_width, dest_height);
   2318     return SetDIBits(pSource, argb, &rect, dest_left, dest_top, blend_type);
   2319   }
   2320   Flush();
   2321   FX_RECT dest_rect(dest_left, dest_top, dest_left + dest_width,
   2322                     dest_top + dest_height);
   2323   dest_rect.Normalize();
   2324   FX_RECT dest_clip = dest_rect;
   2325   dest_clip.Intersect(*pClipRect);
   2326   CFX_BitmapComposer composer;
   2327   composer.Compose(m_pBitmap, m_pClipRgn.get(), 255, argb, dest_clip, false,
   2328                    false, false, m_bRgbByteOrder, 0, blend_type);
   2329   dest_clip.Offset(-dest_rect.left, -dest_rect.top);
   2330   CFX_ImageStretcher stretcher(&composer, pSource, dest_width, dest_height,
   2331                                dest_clip, flags);
   2332   if (stretcher.Start())
   2333     stretcher.Continue(nullptr);
   2334   return true;
   2335 #endif  // _SKIA_SUPPORT_PATHS_
   2336 }
   2337 
   2338 bool CFX_SkiaDeviceDriver::StartDIBits(
   2339     const RetainPtr<CFX_DIBSource>& pSource,
   2340     int bitmap_alpha,
   2341     uint32_t argb,
   2342     const CFX_Matrix* pMatrix,
   2343     uint32_t render_flags,
   2344     std::unique_ptr<CFX_ImageRenderer>* handle,
   2345     int blend_type) {
   2346 #ifdef _SKIA_SUPPORT_
   2347   m_pCache->FlushForDraw();
   2348   DebugValidate(m_pBitmap, m_pOriDevice);
   2349   std::unique_ptr<uint8_t, FxFreeDeleter> dst8Storage;
   2350   std::unique_ptr<uint32_t, FxFreeDeleter> dst32Storage;
   2351   SkBitmap skBitmap;
   2352   int width, height;
   2353   if (!Upsample(pSource, dst8Storage, dst32Storage, &skBitmap, &width, &height,
   2354                 false)) {
   2355     return false;
   2356   }
   2357   m_pCanvas->save();
   2358   SkMatrix skMatrix;
   2359   SetBitmapMatrix(pMatrix, width, height, &skMatrix);
   2360   m_pCanvas->concat(skMatrix);
   2361   SkPaint paint;
   2362   SetBitmapPaint(pSource->IsAlphaMask(), argb, bitmap_alpha, blend_type,
   2363                  &paint);
   2364   // TODO(caryclark) Once Skia supports 8 bit src to 8 bit dst remove this
   2365   if (m_pBitmap && m_pBitmap->GetBPP() == 8 && pSource->GetBPP() == 8) {
   2366     SkMatrix inv;
   2367     SkAssertResult(skMatrix.invert(&inv));
   2368     for (int y = 0; y < m_pBitmap->GetHeight(); ++y) {
   2369       for (int x = 0; x < m_pBitmap->GetWidth(); ++x) {
   2370         SkPoint src = {x + 0.5f, y + 0.5f};
   2371         inv.mapPoints(&src, 1);
   2372         // TODO(caryclark) Why does the matrix map require clamping?
   2373         src.fX = SkTMax(0.5f, SkTMin(src.fX, width - 0.5f));
   2374         src.fY = SkTMax(0.5f, SkTMin(src.fY, height - 0.5f));
   2375         m_pBitmap->SetPixel(x, y, skBitmap.getColor(src.fX, src.fY));
   2376       }
   2377     }
   2378   } else {
   2379     m_pCanvas->drawBitmap(skBitmap, 0, 0, &paint);
   2380   }
   2381   m_pCanvas->restore();
   2382   DebugValidate(m_pBitmap, m_pOriDevice);
   2383 #endif  // _SKIA_SUPPORT_
   2384 
   2385 #ifdef _SKIA_SUPPORT_PATHS_
   2386   Flush();
   2387   if (!m_pBitmap->GetBuffer())
   2388     return true;
   2389   m_pBitmap->UnPreMultiply();
   2390   *handle = pdfium::MakeUnique<CFX_ImageRenderer>(
   2391       m_pBitmap, m_pClipRgn.get(), pSource, bitmap_alpha, argb, pMatrix,
   2392       render_flags, m_bRgbByteOrder);
   2393 #endif  // _SKIA_SUPPORT_PATHS_
   2394   return true;
   2395 }
   2396 
   2397 bool CFX_SkiaDeviceDriver::ContinueDIBits(CFX_ImageRenderer* handle,
   2398                                           IFX_PauseIndicator* pPause) {
   2399 #ifdef _SKIA_SUPPORT_
   2400   m_pCache->FlushForDraw();
   2401   return false;
   2402 #endif  // _SKIA_SUPPORT_
   2403 
   2404 #ifdef _SKIA_SUPPORT_PATHS_
   2405   Flush();
   2406   if (!m_pBitmap->GetBuffer()) {
   2407     return true;
   2408   }
   2409   return handle->Continue(pPause);
   2410 #endif  // _SKIA_SUPPORT_PATHS_
   2411 }
   2412 
   2413 #if defined _SKIA_SUPPORT_
   2414 void CFX_SkiaDeviceDriver::PreMultiply(
   2415     const RetainPtr<CFX_DIBitmap>& pDIBitmap) {
   2416   pDIBitmap->PreMultiply();
   2417 }
   2418 #endif  // _SKIA_SUPPORT_
   2419 
   2420 void CFX_DIBitmap::PreMultiply() {
   2421   if (this->GetBPP() != 32)
   2422     return;
   2423   void* buffer = this->GetBuffer();
   2424   if (!buffer)
   2425     return;
   2426 #if defined _SKIA_SUPPORT_PATHS_
   2427   Format priorFormat = m_nFormat;
   2428   m_nFormat = Format::kPreMultiplied;
   2429   if (priorFormat != Format::kUnPreMultiplied)
   2430     return;
   2431 #endif
   2432   int height = this->GetHeight();
   2433   int width = this->GetWidth();
   2434   int rowBytes = this->GetPitch();
   2435   SkImageInfo unpremultipliedInfo =
   2436       SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType);
   2437   SkPixmap unpremultiplied(unpremultipliedInfo, buffer, rowBytes);
   2438   SkImageInfo premultipliedInfo =
   2439       SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
   2440   SkPixmap premultiplied(premultipliedInfo, buffer, rowBytes);
   2441   unpremultiplied.readPixels(premultiplied);
   2442   this->DebugVerifyBitmapIsPreMultiplied(nullptr);
   2443 }
   2444 
   2445 #ifdef _SKIA_SUPPORT_PATHS_
   2446 void CFX_DIBitmap::UnPreMultiply() {
   2447   if (this->GetBPP() != 32)
   2448     return;
   2449   void* buffer = this->GetBuffer();
   2450   if (!buffer)
   2451     return;
   2452   Format priorFormat = m_nFormat;
   2453   m_nFormat = Format::kUnPreMultiplied;
   2454   if (priorFormat != Format::kPreMultiplied)
   2455     return;
   2456   this->DebugVerifyBitmapIsPreMultiplied(nullptr);
   2457   int height = this->GetHeight();
   2458   int width = this->GetWidth();
   2459   int rowBytes = this->GetPitch();
   2460   SkImageInfo premultipliedInfo =
   2461       SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType);
   2462   SkPixmap premultiplied(premultipliedInfo, buffer, rowBytes);
   2463   SkImageInfo unpremultipliedInfo =
   2464       SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType);
   2465   SkPixmap unpremultiplied(unpremultipliedInfo, buffer, rowBytes);
   2466   premultiplied.readPixels(unpremultiplied);
   2467 }
   2468 #endif  // _SKIA_SUPPORT_PATHS_
   2469 
   2470 #ifdef _SKIA_SUPPORT_
   2471 bool CFX_SkiaDeviceDriver::DrawBitsWithMask(
   2472     const RetainPtr<CFX_DIBSource>& pSource,
   2473     const RetainPtr<CFX_DIBSource>& pMask,
   2474     int bitmap_alpha,
   2475     const CFX_Matrix* pMatrix,
   2476     int blend_type) {
   2477   DebugValidate(m_pBitmap, m_pOriDevice);
   2478   std::unique_ptr<uint8_t, FxFreeDeleter> src8Storage, mask8Storage;
   2479   std::unique_ptr<uint32_t, FxFreeDeleter> src32Storage, mask32Storage;
   2480   SkBitmap skBitmap, skMask;
   2481   int srcWidth, srcHeight, maskWidth, maskHeight;
   2482   if (!Upsample(pSource, src8Storage, src32Storage, &skBitmap, &srcWidth,
   2483                 &srcHeight, false)) {
   2484     return false;
   2485   }
   2486   if (!Upsample(pMask, mask8Storage, mask32Storage, &skMask, &maskWidth,
   2487                 &maskHeight, true)) {
   2488     return false;
   2489   }
   2490   m_pCanvas->save();
   2491   SkMatrix skMatrix;
   2492   SetBitmapMatrix(pMatrix, srcWidth, srcHeight, &skMatrix);
   2493   m_pCanvas->concat(skMatrix);
   2494   SkPaint paint;
   2495   SetBitmapPaint(pSource->IsAlphaMask(), 0xFFFFFFFF, bitmap_alpha, blend_type,
   2496                  &paint);
   2497   sk_sp<SkImage> skSrc = SkImage::MakeFromBitmap(skBitmap);
   2498   sk_sp<SkShader> skSrcShader =
   2499       skSrc->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
   2500   sk_sp<SkImage> skMaskImage = SkImage::MakeFromBitmap(skMask);
   2501   sk_sp<SkShader> skMaskShader = skMaskImage->makeShader(
   2502       SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
   2503   paint.setShader(SkShader::MakeComposeShader(skMaskShader, skSrcShader,
   2504                                               SkBlendMode::kSrcIn));
   2505   SkRect r = {0, 0, SkIntToScalar(srcWidth), SkIntToScalar(srcHeight)};
   2506   m_pCanvas->drawRect(r, paint);
   2507   m_pCanvas->restore();
   2508   DebugValidate(m_pBitmap, m_pOriDevice);
   2509   return true;
   2510 }
   2511 
   2512 bool CFX_SkiaDeviceDriver::SetBitsWithMask(
   2513     const RetainPtr<CFX_DIBSource>& pBitmap,
   2514     const RetainPtr<CFX_DIBSource>& pMask,
   2515     int dest_left,
   2516     int dest_top,
   2517     int bitmap_alpha,
   2518     int blend_type) {
   2519   if (!m_pBitmap || !m_pBitmap->GetBuffer())
   2520     return true;
   2521   CFX_Matrix m(pBitmap->GetWidth(), 0, 0, -pBitmap->GetHeight(), dest_left,
   2522                dest_top + pBitmap->GetHeight());
   2523   return DrawBitsWithMask(pBitmap, pMask, bitmap_alpha, &m, blend_type);
   2524 }
   2525 
   2526 void CFX_SkiaDeviceDriver::Clear(uint32_t color) {
   2527   m_pCanvas->clear(color);
   2528 }
   2529 #endif  // _SKIA_SUPPORT_
   2530 
   2531 void CFX_SkiaDeviceDriver::Dump() const {
   2532 #if SHOW_SKIA_PATH && defined _SKIA_SUPPORT_
   2533   if (m_pCache)
   2534     m_pCache->Dump(this);
   2535 #endif  // SHOW_SKIA_PATH && defined _SKIA_SUPPORT_
   2536 }
   2537 
   2538 #ifdef _SKIA_SUPPORT_
   2539 void CFX_SkiaDeviceDriver::DebugVerifyBitmapIsPreMultiplied() const {
   2540   if (m_pOriDevice)
   2541     m_pOriDevice->DebugVerifyBitmapIsPreMultiplied(nullptr);
   2542 }
   2543 #endif  // _SKIA_SUPPORT_
   2544 
   2545 CFX_DefaultRenderDevice::CFX_DefaultRenderDevice() {}
   2546 
   2547 #ifdef _SKIA_SUPPORT_
   2548 void CFX_DefaultRenderDevice::Clear(uint32_t color) {
   2549   CFX_SkiaDeviceDriver* skDriver =
   2550       static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver());
   2551   skDriver->Clear(color);
   2552 }
   2553 
   2554 SkPictureRecorder* CFX_DefaultRenderDevice::CreateRecorder(int size_x,
   2555                                                            int size_y) {
   2556   CFX_SkiaDeviceDriver* skDriver = new CFX_SkiaDeviceDriver(size_x, size_y);
   2557   SetDeviceDriver(pdfium::WrapUnique(skDriver));
   2558   return skDriver->GetRecorder();
   2559 }
   2560 #endif  // _SKIA_SUPPORT_
   2561 
   2562 bool CFX_DefaultRenderDevice::Attach(const RetainPtr<CFX_DIBitmap>& pBitmap,
   2563                                      bool bRgbByteOrder,
   2564                                      const RetainPtr<CFX_DIBitmap>& pOriDevice,
   2565                                      bool bGroupKnockout) {
   2566   if (!pBitmap)
   2567     return false;
   2568   SetBitmap(pBitmap);
   2569   SetDeviceDriver(pdfium::MakeUnique<CFX_SkiaDeviceDriver>(
   2570       pBitmap, bRgbByteOrder, pOriDevice, bGroupKnockout));
   2571   return true;
   2572 }
   2573 
   2574 #ifdef _SKIA_SUPPORT_
   2575 bool CFX_DefaultRenderDevice::AttachRecorder(SkPictureRecorder* recorder) {
   2576   if (!recorder)
   2577     return false;
   2578   SetDeviceDriver(pdfium::MakeUnique<CFX_SkiaDeviceDriver>(recorder));
   2579   return true;
   2580 }
   2581 #endif  // _SKIA_SUPPORT_
   2582 
   2583 bool CFX_DefaultRenderDevice::Create(
   2584     int width,
   2585     int height,
   2586     FXDIB_Format format,
   2587     const RetainPtr<CFX_DIBitmap>& pOriDevice) {
   2588   auto pBitmap = pdfium::MakeRetain<CFX_DIBitmap>();
   2589   if (!pBitmap->Create(width, height, format)) {
   2590     return false;
   2591   }
   2592   SetBitmap(pBitmap);
   2593   SetDeviceDriver(pdfium::MakeUnique<CFX_SkiaDeviceDriver>(pBitmap, false,
   2594                                                            pOriDevice, false));
   2595   return true;
   2596 }
   2597 
   2598 CFX_DefaultRenderDevice::~CFX_DefaultRenderDevice() {
   2599   Flush(true);
   2600 }
   2601 
   2602 #ifdef _SKIA_SUPPORT_
   2603 void CFX_DefaultRenderDevice::DebugVerifyBitmapIsPreMultiplied() const {
   2604 #ifdef SK_DEBUG
   2605   CFX_SkiaDeviceDriver* skDriver =
   2606       static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver());
   2607   if (skDriver)
   2608     skDriver->DebugVerifyBitmapIsPreMultiplied();
   2609 #endif  // SK_DEBUG
   2610 }
   2611 
   2612 bool CFX_DefaultRenderDevice::SetBitsWithMask(
   2613     const RetainPtr<CFX_DIBSource>& pBitmap,
   2614     const RetainPtr<CFX_DIBSource>& pMask,
   2615     int left,
   2616     int top,
   2617     int bitmap_alpha,
   2618     int blend_type) {
   2619   CFX_SkiaDeviceDriver* skDriver =
   2620       static_cast<CFX_SkiaDeviceDriver*>(GetDeviceDriver());
   2621   if (skDriver)
   2622     return skDriver->SetBitsWithMask(pBitmap, pMask, left, top, bitmap_alpha,
   2623                                      blend_type);
   2624   return false;
   2625 }
   2626 #endif  // _SKIA_SUPPORT_
   2627 
   2628 void CFX_DIBSource::DebugVerifyBitmapIsPreMultiplied(void* opt) const {
   2629 #ifdef SK_DEBUG
   2630   SkASSERT(32 == GetBPP());
   2631   const uint32_t* buffer = (const uint32_t*)(opt ? opt : GetBuffer());
   2632   int width = GetWidth();
   2633   int height = GetHeight();
   2634   // verify that input is really premultiplied
   2635   for (int y = 0; y < height; ++y) {
   2636     const uint32_t* srcRow = buffer + y * width;
   2637     for (int x = 0; x < width; ++x) {
   2638       uint8_t a = SkGetPackedA32(srcRow[x]);
   2639       uint8_t r = SkGetPackedR32(srcRow[x]);
   2640       uint8_t g = SkGetPackedG32(srcRow[x]);
   2641       uint8_t b = SkGetPackedB32(srcRow[x]);
   2642       SkA32Assert(a);
   2643       SkASSERT(r <= a);
   2644       SkASSERT(g <= a);
   2645       SkASSERT(b <= a);
   2646     }
   2647   }
   2648 #endif  // SK_DEBUG
   2649 }
   2650