Home | History | Annotate | Download | only in pdf
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkPDFDevice.h"
      9 
     10 #include "SkAdvancedTypefaceMetrics.h"
     11 #include "SkAnnotationKeys.h"
     12 #include "SkBitmapDevice.h"
     13 #include "SkBitmapKey.h"
     14 #include "SkCanvas.h"
     15 #include "SkClipOpPriv.h"
     16 #include "SkColor.h"
     17 #include "SkColorFilter.h"
     18 #include "SkDraw.h"
     19 #include "SkDrawFilter.h"
     20 #include "SkGlyphCache.h"
     21 #include "SkImageFilterCache.h"
     22 #include "SkJpegEncoder.h"
     23 #include "SkMakeUnique.h"
     24 #include "SkMaskFilterBase.h"
     25 #include "SkPDFBitmap.h"
     26 #include "SkPDFCanon.h"
     27 #include "SkPDFDocument.h"
     28 #include "SkPDFFont.h"
     29 #include "SkPDFFormXObject.h"
     30 #include "SkPDFGraphicState.h"
     31 #include "SkPDFResourceDict.h"
     32 #include "SkPDFShader.h"
     33 #include "SkPDFTypes.h"
     34 #include "SkPDFUtils.h"
     35 #include "SkPath.h"
     36 #include "SkPathEffect.h"
     37 #include "SkPathOps.h"
     38 #include "SkPixelRef.h"
     39 #include "SkRRect.h"
     40 #include "SkRasterClip.h"
     41 #include "SkScopeExit.h"
     42 #include "SkString.h"
     43 #include "SkSurface.h"
     44 #include "SkTemplates.h"
     45 #include "SkTextBlobRunIterator.h"
     46 #include "SkTextFormatParams.h"
     47 #include "SkUtils.h"
     48 #include "SkXfermodeInterpretation.h"
     49 
     50 #ifndef SK_PDF_MASK_QUALITY
     51     // If MASK_QUALITY is in [0,100], will be used for JpegEncoder.
     52     // Otherwise, just encode masks losslessly.
     53     #define SK_PDF_MASK_QUALITY 50
     54     // Since these masks are used for blurry shadows, we shouldn't need
     55     // high quality.  Raise this value if your shadows have visible JPEG
     56     // artifacts.
     57     // If SkJpegEncoder::Encode fails, we will fall back to the lossless
     58     // encoding.
     59 #endif
     60 
     61 // Utility functions
     62 
     63 // This function destroys the mask and either frees or takes the pixels.
     64 sk_sp<SkImage> mask_to_greyscale_image(SkMask* mask) {
     65     sk_sp<SkImage> img;
     66     SkPixmap pm(SkImageInfo::Make(mask->fBounds.width(), mask->fBounds.height(),
     67                                   kGray_8_SkColorType, kOpaque_SkAlphaType),
     68                 mask->fImage, mask->fRowBytes);
     69     const int imgQuality = SK_PDF_MASK_QUALITY;
     70     if (imgQuality <= 100 && imgQuality >= 0) {
     71         SkDynamicMemoryWStream buffer;
     72         SkJpegEncoder::Options jpegOptions;
     73         jpegOptions.fQuality = imgQuality;
     74         if (SkJpegEncoder::Encode(&buffer, pm, jpegOptions)) {
     75             img = SkImage::MakeFromEncoded(buffer.detachAsData());
     76             SkASSERT(img);
     77             if (img) {
     78                 SkMask::FreeImage(mask->fImage);
     79             }
     80         }
     81     }
     82     if (!img) {
     83         img = SkImage::MakeFromRaster(pm, [](const void* p, void*) { SkMask::FreeImage((void*)p); },
     84                                       nullptr);
     85     }
     86     *mask = SkMask();  // destructive;
     87     return img;
     88 }
     89 
     90 sk_sp<SkImage> alpha_image_to_greyscale_image(const SkImage* mask) {
     91     int w = mask->width(), h = mask->height();
     92     SkBitmap greyBitmap;
     93     greyBitmap.allocPixels(SkImageInfo::Make(w, h, kGray_8_SkColorType, kOpaque_SkAlphaType));
     94     if (!mask->readPixels(SkImageInfo::MakeA8(w, h),
     95                           greyBitmap.getPixels(), greyBitmap.rowBytes(), 0, 0)) {
     96         return nullptr;
     97     }
     98     return SkImage::MakeFromBitmap(greyBitmap);
     99 }
    100 
    101 static void draw_points(SkCanvas::PointMode mode,
    102                         size_t count,
    103                         const SkPoint* points,
    104                         const SkPaint& paint,
    105                         const SkIRect& bounds,
    106                         const SkMatrix& ctm,
    107                         SkBaseDevice* device) {
    108     SkRasterClip rc(bounds);
    109     SkDraw draw;
    110     draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(bounds.right(), bounds.bottom()), nullptr, 0);
    111     draw.fMatrix = &ctm;
    112     draw.fRC = &rc;
    113     draw.drawPoints(mode, count, points, paint, device);
    114 }
    115 
    116 // If the paint will definitely draw opaquely, replace kSrc with
    117 // kSrcOver.  http://crbug.com/473572
    118 static void replace_srcmode_on_opaque_paint(SkPaint* paint) {
    119     if (kSrcOver_SkXfermodeInterpretation == SkInterpretXfermode(*paint, false)) {
    120         paint->setBlendMode(SkBlendMode::kSrcOver);
    121     }
    122 }
    123 
    124 // A shader's matrix is:  CTMM x LocalMatrix x WrappingLocalMatrix.  We want to
    125 // switch to device space, where CTM = I, while keeping the original behavior.
    126 //
    127 //               I * LocalMatrix * NewWrappingMatrix = CTM * LocalMatrix
    128 //                   LocalMatrix * NewWrappingMatrix = CTM * LocalMatrix
    129 //  InvLocalMatrix * LocalMatrix * NewWrappingMatrix = InvLocalMatrix * CTM * LocalMatrix
    130 //                                 NewWrappingMatrix = InvLocalMatrix * CTM * LocalMatrix
    131 //
    132 static void transform_shader(SkPaint* paint, const SkMatrix& ctm) {
    133     SkMatrix lm = SkPDFUtils::GetShaderLocalMatrix(paint->getShader());
    134     SkMatrix lmInv;
    135     if (lm.invert(&lmInv)) {
    136         SkMatrix m = SkMatrix::Concat(SkMatrix::Concat(lmInv, ctm), lm);
    137         paint->setShader(paint->getShader()->makeWithLocalMatrix(m));
    138     }
    139 }
    140 
    141 static void emit_pdf_color(SkColor color, SkWStream* result) {
    142     SkASSERT(SkColorGetA(color) == 0xFF);  // We handle alpha elsewhere.
    143     SkPDFUtils::AppendColorComponent(SkColorGetR(color), result);
    144     result->writeText(" ");
    145     SkPDFUtils::AppendColorComponent(SkColorGetG(color), result);
    146     result->writeText(" ");
    147     SkPDFUtils::AppendColorComponent(SkColorGetB(color), result);
    148     result->writeText(" ");
    149 }
    150 
    151 static SkPaint calculate_text_paint(const SkPaint& paint) {
    152     SkPaint result = paint;
    153     if (result.isFakeBoldText()) {
    154         SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(),
    155                                                     kStdFakeBoldInterpKeys,
    156                                                     kStdFakeBoldInterpValues,
    157                                                     kStdFakeBoldInterpLength);
    158         SkScalar width = result.getTextSize() * fakeBoldScale;
    159         if (result.getStyle() == SkPaint::kFill_Style) {
    160             result.setStyle(SkPaint::kStrokeAndFill_Style);
    161         } else {
    162             width += result.getStrokeWidth();
    163         }
    164         result.setStrokeWidth(width);
    165     }
    166     return result;
    167 }
    168 
    169 
    170 // If the paint has a color filter, apply the color filter to the shader or the
    171 // paint color.  Remove the color filter.
    172 void remove_color_filter(SkPaint* paint) {
    173     if (SkColorFilter* cf = paint->getColorFilter()) {
    174         if (SkShader* shader = paint->getShader()) {
    175             paint->setShader(shader->makeWithColorFilter(paint->refColorFilter()));
    176         } else {
    177             paint->setColor(cf->filterColor(paint->getColor()));
    178         }
    179         paint->setColorFilter(nullptr);
    180     }
    181 }
    182 
    183 SkPDFDevice::GraphicStateEntry::GraphicStateEntry()
    184     : fColor(SK_ColorBLACK)
    185     , fTextScaleX(SK_Scalar1)
    186     , fTextFill(SkPaint::kFill_Style)
    187     , fShaderIndex(-1)
    188     , fGraphicStateIndex(-1) {
    189     fMatrix.reset();
    190 }
    191 
    192 bool SkPDFDevice::GraphicStateEntry::compareInitialState(
    193         const GraphicStateEntry& cur) {
    194     return fColor == cur.fColor &&
    195            fShaderIndex == cur.fShaderIndex &&
    196            fGraphicStateIndex == cur.fGraphicStateIndex &&
    197            fMatrix == cur.fMatrix &&
    198            fClipStack == cur.fClipStack &&
    199            (fTextScaleX == 0 ||
    200                (fTextScaleX == cur.fTextScaleX && fTextFill == cur.fTextFill));
    201 }
    202 
    203 class GraphicStackState {
    204 public:
    205     GraphicStackState(const SkClipStack& existingClipStack,
    206                       SkWStream* contentStream)
    207             : fStackDepth(0),
    208               fContentStream(contentStream) {
    209         fEntries[0].fClipStack = existingClipStack;
    210     }
    211 
    212     void updateClip(const SkClipStack& clipStack,
    213                     const SkPoint& translation, const SkRect& bounds);
    214     void updateMatrix(const SkMatrix& matrix);
    215     void updateDrawingState(const SkPDFDevice::GraphicStateEntry& state);
    216 
    217     void drainStack();
    218 
    219 private:
    220     void push();
    221     void pop();
    222     SkPDFDevice::GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; }
    223 
    224     // Conservative limit on save depth, see impl. notes in PDF 1.4 spec.
    225     static const int kMaxStackDepth = 12;
    226     SkPDFDevice::GraphicStateEntry fEntries[kMaxStackDepth + 1];
    227     int fStackDepth;
    228     SkWStream* fContentStream;
    229 };
    230 
    231 void GraphicStackState::drainStack() {
    232     while (fStackDepth) {
    233         pop();
    234     }
    235 }
    236 
    237 void GraphicStackState::push() {
    238     SkASSERT(fStackDepth < kMaxStackDepth);
    239     fContentStream->writeText("q\n");
    240     fStackDepth++;
    241     fEntries[fStackDepth] = fEntries[fStackDepth - 1];
    242 }
    243 
    244 void GraphicStackState::pop() {
    245     SkASSERT(fStackDepth > 0);
    246     fContentStream->writeText("Q\n");
    247     fStackDepth--;
    248 }
    249 
    250 /* Calculate an inverted path's equivalent non-inverted path, given the
    251  * canvas bounds.
    252  * outPath may alias with invPath (since this is supported by PathOps).
    253  */
    254 static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath,
    255                                    SkPath* outPath) {
    256     SkASSERT(invPath.isInverseFillType());
    257 
    258     SkPath clipPath;
    259     clipPath.addRect(bounds);
    260 
    261     return Op(clipPath, invPath, kIntersect_SkPathOp, outPath);
    262 }
    263 
    264 bool apply_clip(SkClipOp op, const SkPath& u, const SkPath& v, SkPath* r)  {
    265     switch (op) {
    266         case SkClipOp::kDifference:
    267             return Op(u, v, kDifference_SkPathOp, r);
    268         case SkClipOp::kIntersect:
    269             return Op(u, v, kIntersect_SkPathOp, r);
    270 #ifdef SK_SUPPORT_DEPRECATED_CLIPOPS
    271         case SkClipOp::kUnion_deprecated:
    272             return Op(u, v, kUnion_SkPathOp, r);
    273         case SkClipOp::kXOR_deprecated:
    274             return Op(u, v, kXOR_SkPathOp, r);
    275         case SkClipOp::kReverseDifference_deprecated:
    276             return Op(u, v, kReverseDifference_SkPathOp, r);
    277         case SkClipOp::kReplace_deprecated:
    278             *r = v;
    279             return true;
    280 #endif
    281         default:
    282             return false;
    283     }
    284 }
    285 
    286 /* Uses Path Ops to calculate a vector SkPath clip from a clip stack.
    287  * Returns true if successful, or false if not successful.
    288  * If successful, the resulting clip is stored in outClipPath.
    289  * If not successful, outClipPath is undefined, and a fallback method
    290  * should be used.
    291  */
    292 static bool get_clip_stack_path(const SkMatrix& transform,
    293                                 const SkClipStack& clipStack,
    294                                 const SkRect& bounds,
    295                                 SkPath* outClipPath) {
    296     outClipPath->reset();
    297     outClipPath->setFillType(SkPath::kInverseWinding_FillType);
    298 
    299     const SkClipStack::Element* clipEntry;
    300     SkClipStack::Iter iter;
    301     iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart);
    302     for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
    303         SkPath entryPath;
    304         if (SkClipStack::Element::DeviceSpaceType::kEmpty == clipEntry->getDeviceSpaceType()) {
    305             outClipPath->reset();
    306             outClipPath->setFillType(SkPath::kInverseWinding_FillType);
    307             continue;
    308         } else {
    309             clipEntry->asDeviceSpacePath(&entryPath);
    310         }
    311         entryPath.transform(transform);
    312         if (!apply_clip(clipEntry->getOp(), *outClipPath, entryPath, outClipPath)) {
    313             return false;
    314         }
    315     }
    316 
    317     if (outClipPath->isInverseFillType()) {
    318         // The bounds are slightly outset to ensure this is correct in the
    319         // face of floating-point accuracy and possible SkRegion bitmap
    320         // approximations.
    321         SkRect clipBounds = bounds;
    322         clipBounds.outset(SK_Scalar1, SK_Scalar1);
    323         if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) {
    324             return false;
    325         }
    326     }
    327     return true;
    328 }
    329 
    330 // TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF
    331 // graphic state stack, and the fact that we can know all the clips used
    332 // on the page to optimize this.
    333 void GraphicStackState::updateClip(const SkClipStack& clipStack,
    334                                    const SkPoint& translation,
    335                                    const SkRect& bounds) {
    336     if (clipStack == currentEntry()->fClipStack) {
    337         return;
    338     }
    339 
    340     while (fStackDepth > 0) {
    341         pop();
    342         if (clipStack == currentEntry()->fClipStack) {
    343             return;
    344         }
    345     }
    346     push();
    347 
    348     currentEntry()->fClipStack = clipStack;
    349 
    350     SkMatrix transform;
    351     transform.setTranslate(translation.fX, translation.fY);
    352 
    353     SkPath clipPath;
    354     if (get_clip_stack_path(transform, clipStack, bounds, &clipPath)) {
    355         SkPDFUtils::EmitPath(clipPath, SkPaint::kFill_Style, fContentStream);
    356         SkPath::FillType clipFill = clipPath.getFillType();
    357         NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false);
    358         NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false);
    359         if (clipFill == SkPath::kEvenOdd_FillType) {
    360             fContentStream->writeText("W* n\n");
    361         } else {
    362             fContentStream->writeText("W n\n");
    363         }
    364     }
    365     // If Op() fails (pathological case; e.g. input values are
    366     // extremely large or NaN), emit no clip at all.
    367 }
    368 
    369 void GraphicStackState::updateMatrix(const SkMatrix& matrix) {
    370     if (matrix == currentEntry()->fMatrix) {
    371         return;
    372     }
    373 
    374     if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) {
    375         SkASSERT(fStackDepth > 0);
    376         SkASSERT(fEntries[fStackDepth].fClipStack ==
    377                  fEntries[fStackDepth -1].fClipStack);
    378         pop();
    379 
    380         SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask);
    381     }
    382     if (matrix.getType() == SkMatrix::kIdentity_Mask) {
    383         return;
    384     }
    385 
    386     push();
    387     SkPDFUtils::AppendTransform(matrix, fContentStream);
    388     currentEntry()->fMatrix = matrix;
    389 }
    390 
    391 void GraphicStackState::updateDrawingState(const SkPDFDevice::GraphicStateEntry& state) {
    392     // PDF treats a shader as a color, so we only set one or the other.
    393     if (state.fShaderIndex >= 0) {
    394         if (state.fShaderIndex != currentEntry()->fShaderIndex) {
    395             SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream);
    396             currentEntry()->fShaderIndex = state.fShaderIndex;
    397         }
    398     } else {
    399         if (state.fColor != currentEntry()->fColor ||
    400                 currentEntry()->fShaderIndex >= 0) {
    401             emit_pdf_color(state.fColor, fContentStream);
    402             fContentStream->writeText("RG ");
    403             emit_pdf_color(state.fColor, fContentStream);
    404             fContentStream->writeText("rg\n");
    405             currentEntry()->fColor = state.fColor;
    406             currentEntry()->fShaderIndex = -1;
    407         }
    408     }
    409 
    410     if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) {
    411         SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream);
    412         currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex;
    413     }
    414 
    415     if (state.fTextScaleX) {
    416         if (state.fTextScaleX != currentEntry()->fTextScaleX) {
    417             SkScalar pdfScale = state.fTextScaleX * 100;
    418             SkPDFUtils::AppendScalar(pdfScale, fContentStream);
    419             fContentStream->writeText(" Tz\n");
    420             currentEntry()->fTextScaleX = state.fTextScaleX;
    421         }
    422         if (state.fTextFill != currentEntry()->fTextFill) {
    423             static_assert(SkPaint::kFill_Style == 0, "enum_must_match_value");
    424             static_assert(SkPaint::kStroke_Style == 1, "enum_must_match_value");
    425             static_assert(SkPaint::kStrokeAndFill_Style == 2, "enum_must_match_value");
    426             fContentStream->writeDecAsText(state.fTextFill);
    427             fContentStream->writeText(" Tr\n");
    428             currentEntry()->fTextFill = state.fTextFill;
    429         }
    430     }
    431 }
    432 
    433 static bool not_supported_for_layers(const SkPaint& layerPaint) {
    434     // PDF does not support image filters, so render them on CPU.
    435     // Note that this rendering is done at "screen" resolution (100dpi), not
    436     // printer resolution.
    437     // TODO: It may be possible to express some filters natively using PDF
    438     // to improve quality and file size (https://bug.skia.org/3043)
    439 
    440     // TODO: should we return true if there is a colorfilter?
    441     return layerPaint.getImageFilter() != nullptr;
    442 }
    443 
    444 SkBaseDevice* SkPDFDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint* layerPaint) {
    445     if (layerPaint && not_supported_for_layers(*layerPaint)) {
    446         // need to return a raster device, which we will detect in drawDevice()
    447         return SkBitmapDevice::Create(cinfo.fInfo, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
    448     }
    449     return new SkPDFDevice(cinfo.fInfo.dimensions(), fDocument);
    450 }
    451 
    452 SkPDFCanon* SkPDFDevice::getCanon() const { return fDocument->canon(); }
    453 
    454 // A helper class to automatically finish a ContentEntry at the end of a
    455 // drawing method and maintain the state needed between set up and finish.
    456 class ScopedContentEntry {
    457 public:
    458     ScopedContentEntry(SkPDFDevice* device,
    459                        const SkClipStack& clipStack,
    460                        const SkMatrix& matrix,
    461                        const SkPaint& paint,
    462                        bool hasText = false)
    463         : fDevice(device)
    464         , fContentEntry(nullptr)
    465         , fBlendMode(SkBlendMode::kSrcOver)
    466         , fDstFormXObject(nullptr)
    467     {
    468         if (matrix.hasPerspective()) {
    469             NOT_IMPLEMENTED(!matrix.hasPerspective(), false);
    470             return;
    471         }
    472         fBlendMode = paint.getBlendMode();
    473         fContentEntry =
    474             fDevice->setUpContentEntry(clipStack, matrix, paint, hasText, &fDstFormXObject);
    475     }
    476     ScopedContentEntry(SkPDFDevice* dev, const SkPaint& paint, bool hasText = false)
    477         : ScopedContentEntry(dev, dev->cs(), dev->ctm(), paint, hasText) {}
    478 
    479     ~ScopedContentEntry() {
    480         if (fContentEntry) {
    481             SkPath* shape = &fShape;
    482             if (shape->isEmpty()) {
    483                 shape = nullptr;
    484             }
    485             fDevice->finishContentEntry(fBlendMode, std::move(fDstFormXObject), shape);
    486         }
    487     }
    488 
    489     SkPDFDevice::ContentEntry* entry() { return fContentEntry; }
    490     SkDynamicMemoryWStream* stream() { return &fContentEntry->fContent; }
    491 
    492     /* Returns true when we explicitly need the shape of the drawing. */
    493     bool needShape() {
    494         switch (fBlendMode) {
    495             case SkBlendMode::kClear:
    496             case SkBlendMode::kSrc:
    497             case SkBlendMode::kSrcIn:
    498             case SkBlendMode::kSrcOut:
    499             case SkBlendMode::kDstIn:
    500             case SkBlendMode::kDstOut:
    501             case SkBlendMode::kSrcATop:
    502             case SkBlendMode::kDstATop:
    503             case SkBlendMode::kModulate:
    504                 return true;
    505             default:
    506                 return false;
    507         }
    508     }
    509 
    510     /* Returns true unless we only need the shape of the drawing. */
    511     bool needSource() {
    512         if (fBlendMode == SkBlendMode::kClear) {
    513             return false;
    514         }
    515         return true;
    516     }
    517 
    518     /* If the shape is different than the alpha component of the content, then
    519      * setShape should be called with the shape.  In particular, images and
    520      * devices have rectangular shape.
    521      */
    522     void setShape(const SkPath& shape) {
    523         fShape = shape;
    524     }
    525 
    526 private:
    527     SkPDFDevice* fDevice;
    528     SkPDFDevice::ContentEntry* fContentEntry;
    529     SkBlendMode fBlendMode;
    530     sk_sp<SkPDFObject> fDstFormXObject;
    531     SkPath fShape;
    532 };
    533 
    534 ////////////////////////////////////////////////////////////////////////////////
    535 
    536 SkPDFDevice::SkPDFDevice(SkISize pageSize, SkPDFDocument* doc)
    537     : INHERITED(SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height()),
    538                 SkSurfaceProps(0, kUnknown_SkPixelGeometry))
    539     , fPageSize(pageSize)
    540     , fInitialTransform(SkMatrix::I())
    541     , fDocument(doc)
    542 {
    543     SkASSERT(!pageSize.isEmpty());
    544 }
    545 
    546 void SkPDFDevice::setFlip() {
    547     // Skia generally uses the top left as the origin but PDF
    548     // natively has the origin at the bottom left. This matrix
    549     // corrects for that.  But that only needs to be done once, we
    550     // don't do it when layering.
    551     fInitialTransform.setTranslate(0, SkIntToScalar(fPageSize.fHeight));
    552     fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1);
    553 }
    554 
    555 SkPDFDevice::~SkPDFDevice() {
    556     this->cleanUp();
    557 }
    558 
    559 void SkPDFDevice::init() {
    560     fContentEntries.reset();
    561 }
    562 
    563 void SkPDFDevice::cleanUp() {
    564     fGraphicStateResources.unrefAll();
    565     fXObjectResources.unrefAll();
    566     fFontResources.unrefAll();
    567     fShaderResources.unrefAll();
    568 }
    569 
    570 void SkPDFDevice::drawAnnotation(const SkRect& rect, const char key[], SkData* value) {
    571     if (!value) {
    572         return;
    573     }
    574     if (rect.isEmpty()) {
    575         if (!strcmp(SkAnnotationKeys::Define_Named_Dest_Key(), key)) {
    576             SkPoint transformedPoint;
    577             this->ctm().mapXY(rect.x(), rect.y(), &transformedPoint);
    578             fNamedDestinations.emplace_back(NamedDestination{sk_ref_sp(value), transformedPoint});
    579         }
    580         return;
    581     }
    582     // Convert to path to handle non-90-degree rotations.
    583     SkPath path;
    584     path.addRect(rect);
    585     path.transform(this->ctm(), &path);
    586     SkPath clip;
    587     (void)this->cs().asPath(&clip);
    588     Op(clip, path, kIntersect_SkPathOp, &path);
    589     // PDF wants a rectangle only.
    590     SkRect transformedRect = path.getBounds();
    591     if (transformedRect.isEmpty()) {
    592         return;
    593     }
    594     if (!strcmp(SkAnnotationKeys::URL_Key(), key)) {
    595         fLinkToURLs.emplace_back(RectWithData{transformedRect, sk_ref_sp(value)});
    596     } else if (!strcmp(SkAnnotationKeys::Link_Named_Dest_Key(), key)) {
    597         fLinkToDestinations.emplace_back(RectWithData{transformedRect, sk_ref_sp(value)});
    598     }
    599 }
    600 
    601 void SkPDFDevice::drawPaint(const SkPaint& srcPaint) {
    602     SkPaint newPaint = srcPaint;
    603     remove_color_filter(&newPaint);
    604     replace_srcmode_on_opaque_paint(&newPaint);
    605     newPaint.setStyle(SkPaint::kFill_Style);
    606 
    607     SkMatrix ctm = this->ctm();
    608     if (ctm.getType() & SkMatrix::kPerspective_Mask) {
    609         if (newPaint.getShader()) {
    610             transform_shader(&newPaint, ctm);
    611         }
    612         ctm = SkMatrix::I();
    613     }
    614     ScopedContentEntry content(this, this->cs(), ctm, newPaint);
    615     this->internalDrawPaint(newPaint, content.entry());
    616 }
    617 
    618 void SkPDFDevice::internalDrawPaint(const SkPaint& paint,
    619                                     SkPDFDevice::ContentEntry* contentEntry) {
    620     if (!contentEntry) {
    621         return;
    622     }
    623     SkRect bbox = SkRect::Make(fPageSize);
    624     SkMatrix inverse;
    625     if (!contentEntry->fState.fMatrix.invert(&inverse)) {
    626         return;
    627     }
    628     inverse.mapRect(&bbox);
    629 
    630     SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent);
    631     SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
    632                           &contentEntry->fContent);
    633 }
    634 
    635 void SkPDFDevice::drawPoints(SkCanvas::PointMode mode,
    636                              size_t count,
    637                              const SkPoint* points,
    638                              const SkPaint& srcPaint) {
    639     SkPaint passedPaint = srcPaint;
    640     remove_color_filter(&passedPaint);
    641     replace_srcmode_on_opaque_paint(&passedPaint);
    642     if (SkCanvas::kPoints_PointMode != mode) {
    643         passedPaint.setStyle(SkPaint::kStroke_Style);
    644     }
    645     if (count == 0) {
    646         return;
    647     }
    648 
    649     // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath.
    650     // We only use this when there's a path effect because of the overhead
    651     // of multiple calls to setUpContentEntry it causes.
    652     if (passedPaint.getPathEffect()) {
    653         if (this->cs().isEmpty(this->bounds())) {
    654             return;
    655         }
    656         draw_points(mode, count, points, passedPaint,
    657                     this->devClipBounds(), this->ctm(), this);
    658         return;
    659     }
    660 
    661     const SkPaint* paint = &passedPaint;
    662     SkPaint modifiedPaint;
    663 
    664     if (mode == SkCanvas::kPoints_PointMode &&
    665             paint->getStrokeCap() != SkPaint::kRound_Cap) {
    666         modifiedPaint = *paint;
    667         paint = &modifiedPaint;
    668         if (paint->getStrokeWidth()) {
    669             // PDF won't draw a single point with square/butt caps because the
    670             // orientation is ambiguous.  Draw a rectangle instead.
    671             modifiedPaint.setStyle(SkPaint::kFill_Style);
    672             SkScalar strokeWidth = paint->getStrokeWidth();
    673             SkScalar halfStroke = SkScalarHalf(strokeWidth);
    674             for (size_t i = 0; i < count; i++) {
    675                 SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0);
    676                 r.inset(-halfStroke, -halfStroke);
    677                 this->drawRect(r, modifiedPaint);
    678             }
    679             return;
    680         } else {
    681             modifiedPaint.setStrokeCap(SkPaint::kRound_Cap);
    682         }
    683     }
    684 
    685     ScopedContentEntry content(this, *paint);
    686     if (!content.entry()) {
    687         return;
    688     }
    689     SkDynamicMemoryWStream* contentStream = content.stream();
    690     switch (mode) {
    691         case SkCanvas::kPolygon_PointMode:
    692             SkPDFUtils::MoveTo(points[0].fX, points[0].fY, contentStream);
    693             for (size_t i = 1; i < count; i++) {
    694                 SkPDFUtils::AppendLine(points[i].fX, points[i].fY, contentStream);
    695             }
    696             SkPDFUtils::StrokePath(contentStream);
    697             break;
    698         case SkCanvas::kLines_PointMode:
    699             for (size_t i = 0; i < count/2; i++) {
    700                 SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, contentStream);
    701                 SkPDFUtils::AppendLine(points[i * 2 + 1].fX, points[i * 2 + 1].fY, contentStream);
    702                 SkPDFUtils::StrokePath(contentStream);
    703             }
    704             break;
    705         case SkCanvas::kPoints_PointMode:
    706             SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap);
    707             for (size_t i = 0; i < count; i++) {
    708                 SkPDFUtils::MoveTo(points[i].fX, points[i].fY, contentStream);
    709                 SkPDFUtils::ClosePath(contentStream);
    710                 SkPDFUtils::StrokePath(contentStream);
    711             }
    712             break;
    713         default:
    714             SkASSERT(false);
    715     }
    716 }
    717 
    718 static sk_sp<SkPDFDict> create_link_annotation(const SkRect& translatedRect) {
    719     auto annotation = sk_make_sp<SkPDFDict>("Annot");
    720     annotation->insertName("Subtype", "Link");
    721     annotation->insertInt("F", 4);  // required by ISO 19005
    722 
    723     auto border = sk_make_sp<SkPDFArray>();
    724     border->reserve(3);
    725     border->appendInt(0);  // Horizontal corner radius.
    726     border->appendInt(0);  // Vertical corner radius.
    727     border->appendInt(0);  // Width, 0 = no border.
    728     annotation->insertObject("Border", std::move(border));
    729 
    730     auto rect = sk_make_sp<SkPDFArray>();
    731     rect->reserve(4);
    732     rect->appendScalar(translatedRect.fLeft);
    733     rect->appendScalar(translatedRect.fTop);
    734     rect->appendScalar(translatedRect.fRight);
    735     rect->appendScalar(translatedRect.fBottom);
    736     annotation->insertObject("Rect", std::move(rect));
    737 
    738     return annotation;
    739 }
    740 
    741 static sk_sp<SkPDFDict> create_link_to_url(const SkData* urlData, const SkRect& r) {
    742     sk_sp<SkPDFDict> annotation = create_link_annotation(r);
    743     SkString url(static_cast<const char *>(urlData->data()),
    744                  urlData->size() - 1);
    745     auto action = sk_make_sp<SkPDFDict>("Action");
    746     action->insertName("S", "URI");
    747     action->insertString("URI", url);
    748     annotation->insertObject("A", std::move(action));
    749     return annotation;
    750 }
    751 
    752 static sk_sp<SkPDFDict> create_link_named_dest(const SkData* nameData,
    753                                                const SkRect& r) {
    754     sk_sp<SkPDFDict> annotation = create_link_annotation(r);
    755     SkString name(static_cast<const char *>(nameData->data()),
    756                   nameData->size() - 1);
    757     annotation->insertName("Dest", name);
    758     return annotation;
    759 }
    760 
    761 void SkPDFDevice::drawRect(const SkRect& rect,
    762                            const SkPaint& srcPaint) {
    763     SkPaint paint = srcPaint;
    764     remove_color_filter(&paint);
    765     replace_srcmode_on_opaque_paint(&paint);
    766     SkRect r = rect;
    767     r.sort();
    768 
    769     if (paint.getPathEffect() || paint.getMaskFilter()) {
    770         if (this->cs().isEmpty(this->bounds())) {
    771             return;
    772         }
    773         SkPath path;
    774         path.addRect(r);
    775         this->drawPath(path, paint, nullptr, true);
    776         return;
    777     }
    778 
    779     ScopedContentEntry content(this, paint);
    780     if (!content.entry()) {
    781         return;
    782     }
    783     SkPDFUtils::AppendRectangle(r, content.stream());
    784     SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, content.stream());
    785 }
    786 
    787 void SkPDFDevice::drawRRect(const SkRRect& rrect,
    788                             const SkPaint& srcPaint) {
    789     SkPaint paint = srcPaint;
    790     remove_color_filter(&paint);
    791     replace_srcmode_on_opaque_paint(&paint);
    792     SkPath  path;
    793     path.addRRect(rrect);
    794     this->drawPath(path, paint, nullptr, true);
    795 }
    796 
    797 void SkPDFDevice::drawOval(const SkRect& oval,
    798                            const SkPaint& srcPaint) {
    799     SkPaint paint = srcPaint;
    800     remove_color_filter(&paint);
    801     replace_srcmode_on_opaque_paint(&paint);
    802     SkPath  path;
    803     path.addOval(oval);
    804     this->drawPath(path, paint, nullptr, true);
    805 }
    806 
    807 void SkPDFDevice::drawPath(const SkPath& origPath,
    808                            const SkPaint& srcPaint,
    809                            const SkMatrix* prePathMatrix,
    810                            bool pathIsMutable) {
    811     this->internalDrawPath(
    812             this->cs(), this->ctm(), origPath, srcPaint, prePathMatrix, pathIsMutable);
    813 }
    814 
    815 void SkPDFDevice::internalDrawPathWithFilter(const SkClipStack& clipStack,
    816                                              const SkMatrix& ctm,
    817                                              const SkPath& origPath,
    818                                              const SkPaint& origPaint,
    819                                              const SkMatrix* prePathMatrix) {
    820     SkASSERT(origPaint.getMaskFilter());
    821     SkPath path(origPath);
    822     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
    823     if (prePathMatrix) {
    824         path.transform(*prePathMatrix, &path);
    825     }
    826     SkStrokeRec::InitStyle initStyle = paint->getFillPath(path, &path)
    827                                      ? SkStrokeRec::kFill_InitStyle
    828                                      : SkStrokeRec::kHairline_InitStyle;
    829     path.transform(ctm, &path);
    830 
    831     // TODO(halcanary): respect fDocument->rasterDpi().
    832     //        SkScalar rasterScale = (float)rasterDpi / SkPDFUtils::kDpiForRasterScaleOne;
    833     // Would it be easier to just change the device size (and pre-scale the canvas)?
    834     SkIRect bounds = clipStack.bounds(this->bounds()).roundOut();
    835     SkMask sourceMask;
    836     if (!SkDraw::DrawToMask(path, &bounds, paint->getMaskFilter(), &SkMatrix::I(),
    837                             &sourceMask, SkMask::kComputeBoundsAndRenderImage_CreateMode,
    838                             initStyle)) {
    839         return;
    840     }
    841     SkAutoMaskFreeImage srcAutoMaskFreeImage(sourceMask.fImage);
    842     SkMask dstMask;
    843     SkIPoint margin;
    844     if (!as_MFB(paint->getMaskFilter())->filterMask(&dstMask, sourceMask, ctm, &margin)) {
    845         return;
    846     }
    847     SkIRect dstMaskBounds = dstMask.fBounds;
    848     sk_sp<SkImage> mask = mask_to_greyscale_image(&dstMask);
    849     // PDF doesn't seem to allow masking vector graphics with an Image XObject.
    850     // Must mask with a Form XObject.
    851     sk_sp<SkPDFDevice> maskDevice = this->makeCongruentDevice();
    852     {
    853         SkCanvas canvas(maskDevice.get());
    854         canvas.drawImage(mask, dstMaskBounds.x(), dstMaskBounds.y());
    855     }
    856     if (!ctm.isIdentity() && paint->getShader()) {
    857         transform_shader(paint.writable(), ctm); // Since we are using identity matrix.
    858     }
    859     ScopedContentEntry content(this, clipStack, SkMatrix::I(), *paint);
    860     if (!content.entry()) {
    861         return;
    862     }
    863     this->addSMaskGraphicState(std::move(maskDevice), content.stream());
    864     SkPDFUtils::AppendRectangle(SkRect::Make(dstMaskBounds), content.stream());
    865     SkPDFUtils::PaintPath(SkPaint::kFill_Style, path.getFillType(), content.stream());
    866     this->clearMaskOnGraphicState(content.stream());
    867 }
    868 
    869 void SkPDFDevice::addSMaskGraphicState(sk_sp<SkPDFDevice> maskDevice,
    870                                        SkDynamicMemoryWStream* contentStream) {
    871     sk_sp<SkPDFDict> sMaskGS = SkPDFGraphicState::GetSMaskGraphicState(
    872             maskDevice->makeFormXObjectFromDevice(true), false,
    873             SkPDFGraphicState::kLuminosity_SMaskMode, this->getCanon());
    874     SkPDFUtils::ApplyGraphicState(this->addGraphicStateResource(sMaskGS.get()), contentStream);
    875 }
    876 
    877 void SkPDFDevice::clearMaskOnGraphicState(SkDynamicMemoryWStream* contentStream) {
    878     // The no-softmask graphic state is used to "turn off" the mask for later draw calls.
    879     sk_sp<SkPDFDict>& noSMaskGS = this->getCanon()->fNoSmaskGraphicState;
    880     if (!noSMaskGS) {
    881         noSMaskGS = sk_make_sp<SkPDFDict>("ExtGState");
    882         noSMaskGS->insertName("SMask", "None");
    883     }
    884     SkPDFUtils::ApplyGraphicState(this->addGraphicStateResource(noSMaskGS.get()), contentStream);
    885 }
    886 
    887 void SkPDFDevice::internalDrawPath(const SkClipStack& clipStack,
    888                                    const SkMatrix& ctm,
    889                                    const SkPath& origPath,
    890                                    const SkPaint& srcPaint,
    891                                    const SkMatrix* prePathMatrix,
    892                                    bool pathIsMutable) {
    893     SkPaint paint = srcPaint;
    894     remove_color_filter(&paint);
    895     replace_srcmode_on_opaque_paint(&paint);
    896     SkPath modifiedPath;
    897     SkPath* pathPtr = const_cast<SkPath*>(&origPath);
    898 
    899     if (paint.getMaskFilter()) {
    900         this->internalDrawPathWithFilter(clipStack, ctm, origPath, paint, prePathMatrix);
    901         return;
    902     }
    903 
    904     SkMatrix matrix = ctm;
    905     if (prePathMatrix) {
    906         if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
    907             if (!pathIsMutable) {
    908                 pathPtr = &modifiedPath;
    909                 pathIsMutable = true;
    910             }
    911             origPath.transform(*prePathMatrix, pathPtr);
    912         } else {
    913             matrix.preConcat(*prePathMatrix);
    914         }
    915     }
    916 
    917     if (paint.getPathEffect()) {
    918         if (clipStack.isEmpty(this->bounds())) {
    919             return;
    920         }
    921         if (!pathIsMutable) {
    922             modifiedPath = origPath;
    923             pathPtr = &modifiedPath;
    924             pathIsMutable = true;
    925         }
    926         if (paint.getFillPath(*pathPtr, pathPtr)) {
    927             paint.setStyle(SkPaint::kFill_Style);
    928         } else {
    929             paint.setStyle(SkPaint::kStroke_Style);
    930             paint.setStrokeWidth(0);
    931         }
    932         paint.setPathEffect(nullptr);
    933     }
    934 
    935     if (this->handleInversePath(*pathPtr, paint, pathIsMutable, prePathMatrix)) {
    936         return;
    937     }
    938     if (matrix.getType() & SkMatrix::kPerspective_Mask) {
    939         if (!pathIsMutable) {
    940             modifiedPath = origPath;
    941             pathPtr = &modifiedPath;
    942             pathIsMutable = true;
    943         }
    944         pathPtr->transform(matrix);
    945         if (paint.getShader()) {
    946             transform_shader(&paint, matrix);
    947         }
    948         matrix = SkMatrix::I();
    949     }
    950 
    951     ScopedContentEntry content(this, clipStack, matrix, paint);
    952     if (!content.entry()) {
    953         return;
    954     }
    955     constexpr SkScalar kToleranceScale = 0.0625f;  // smaller = better conics (circles).
    956     SkScalar matrixScale = matrix.mapRadius(1.0f);
    957     SkScalar tolerance = matrixScale > 0.0f ? kToleranceScale / matrixScale : kToleranceScale;
    958     bool consumeDegeratePathSegments =
    959            paint.getStyle() == SkPaint::kFill_Style ||
    960            (paint.getStrokeCap() != SkPaint::kRound_Cap &&
    961             paint.getStrokeCap() != SkPaint::kSquare_Cap);
    962     SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(), consumeDegeratePathSegments, content.stream(),
    963                          tolerance);
    964     SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(), content.stream());
    965 }
    966 
    967 ////////////////////////////////////////////////////////////////////////////////
    968 
    969 void SkPDFDevice::drawImageRect(const SkImage* image,
    970                                 const SkRect* src,
    971                                 const SkRect& dst,
    972                                 const SkPaint& paint,
    973                                 SkCanvas::SrcRectConstraint) {
    974     SkASSERT(image);
    975     this->internalDrawImageRect(SkKeyedImage(sk_ref_sp(const_cast<SkImage*>(image))),
    976                                 src, dst, paint, this->ctm());
    977 }
    978 
    979 void SkPDFDevice::drawBitmapRect(const SkBitmap& bm,
    980                                  const SkRect* src,
    981                                  const SkRect& dst,
    982                                  const SkPaint& paint,
    983                                  SkCanvas::SrcRectConstraint) {
    984     SkASSERT(!bm.drawsNothing());
    985     this->internalDrawImageRect(SkKeyedImage(bm), src, dst, paint, this->ctm());
    986 }
    987 
    988 void SkPDFDevice::drawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y, const SkPaint& paint) {
    989     SkASSERT(!bm.drawsNothing());
    990     auto r = SkRect::MakeXYWH(x, y, bm.width(), bm.height());
    991     this->internalDrawImageRect(SkKeyedImage(bm), nullptr, r, paint, this->ctm());
    992 }
    993 
    994 void SkPDFDevice::drawSprite(const SkBitmap& bm, int x, int y, const SkPaint& paint) {
    995     SkASSERT(!bm.drawsNothing());
    996     auto r = SkRect::MakeXYWH(x, y, bm.width(), bm.height());
    997     this->internalDrawImageRect(SkKeyedImage(bm), nullptr, r, paint, SkMatrix::I());
    998 }
    999 
   1000 void SkPDFDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint& paint) {
   1001     SkASSERT(image);
   1002     auto r = SkRect::MakeXYWH(x, y, image->width(), image->height());
   1003     this->internalDrawImageRect(SkKeyedImage(sk_ref_sp(const_cast<SkImage*>(image))),
   1004                                 nullptr, r, paint, this->ctm());
   1005 }
   1006 
   1007 ////////////////////////////////////////////////////////////////////////////////
   1008 
   1009 namespace {
   1010 class GlyphPositioner {
   1011 public:
   1012     GlyphPositioner(SkDynamicMemoryWStream* content,
   1013                     SkScalar textSkewX,
   1014                     bool wideChars,
   1015                     bool defaultPositioning,
   1016                     SkPoint origin)
   1017         : fContent(content)
   1018         , fCurrentMatrixOrigin(origin)
   1019         , fTextSkewX(textSkewX)
   1020         , fWideChars(wideChars)
   1021         , fDefaultPositioning(defaultPositioning) {
   1022     }
   1023     ~GlyphPositioner() { this->flush(); }
   1024     void flush() {
   1025         if (fInText) {
   1026             fContent->writeText("> Tj\n");
   1027             fInText = false;
   1028         }
   1029     }
   1030     void writeGlyph(SkPoint xy,
   1031                     SkScalar advanceWidth,
   1032                     uint16_t glyph) {
   1033         if (!fInitialized) {
   1034             // Flip the text about the x-axis to account for origin swap and include
   1035             // the passed parameters.
   1036             fContent->writeText("1 0 ");
   1037             SkPDFUtils::AppendScalar(-fTextSkewX, fContent);
   1038             fContent->writeText(" -1 ");
   1039             SkPDFUtils::AppendScalar(fCurrentMatrixOrigin.x(), fContent);
   1040             fContent->writeText(" ");
   1041             SkPDFUtils::AppendScalar(fCurrentMatrixOrigin.y(), fContent);
   1042             fContent->writeText(" Tm\n");
   1043             fCurrentMatrixOrigin.set(0.0f, 0.0f);
   1044             fInitialized = true;
   1045         }
   1046         if (!fDefaultPositioning) {
   1047             SkPoint position = xy - fCurrentMatrixOrigin;
   1048             if (position != SkPoint{fXAdvance, 0}) {
   1049                 this->flush();
   1050                 SkPDFUtils::AppendScalar(position.x(), fContent);
   1051                 fContent->writeText(" ");
   1052                 SkPDFUtils::AppendScalar(-position.y(), fContent);
   1053                 fContent->writeText(" Td ");
   1054                 fCurrentMatrixOrigin = xy;
   1055                 fXAdvance = 0;
   1056             }
   1057             fXAdvance += advanceWidth;
   1058         }
   1059         if (!fInText) {
   1060             fContent->writeText("<");
   1061             fInText = true;
   1062         }
   1063         if (fWideChars) {
   1064             SkPDFUtils::WriteUInt16BE(fContent, glyph);
   1065         } else {
   1066             SkASSERT(0 == glyph >> 8);
   1067             SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph));
   1068         }
   1069     }
   1070 
   1071 private:
   1072     SkDynamicMemoryWStream* fContent;
   1073     SkPoint fCurrentMatrixOrigin;
   1074     SkScalar fXAdvance = 0.0f;
   1075     SkScalar fTextSkewX;
   1076     bool fWideChars;
   1077     bool fInText = false;
   1078     bool fInitialized = false;
   1079     const bool fDefaultPositioning;
   1080 };
   1081 
   1082 /** Given the m-to-n glyph-to-character mapping data (as returned by
   1083     harfbuzz), iterate over the clusters. */
   1084 class Clusterator {
   1085 public:
   1086     Clusterator() : fClusters(nullptr), fUtf8Text(nullptr), fGlyphCount(0), fTextByteLength(0) {}
   1087     explicit Clusterator(uint32_t glyphCount)
   1088         : fClusters(nullptr)
   1089         , fUtf8Text(nullptr)
   1090         , fGlyphCount(glyphCount)
   1091         , fTextByteLength(0) {}
   1092     // The clusters[] array is an array of offsets into utf8Text[],
   1093     // one offset for each glyph.  See SkTextBlobBuilder for more info.
   1094     Clusterator(const uint32_t* clusters,
   1095                 const char* utf8Text,
   1096                 uint32_t glyphCount,
   1097                 uint32_t textByteLength)
   1098         : fClusters(clusters)
   1099         , fUtf8Text(utf8Text)
   1100         , fGlyphCount(glyphCount)
   1101         , fTextByteLength(textByteLength) {
   1102         // This is a cheap heuristic for /ReversedChars which seems to
   1103         // work for clusters produced by HarfBuzz, which either
   1104         // increase from zero (LTR) or decrease to zero (RTL).
   1105         // "ReversedChars" is how PDF deals with RTL text.
   1106         fReversedChars =
   1107             fUtf8Text && fClusters && fGlyphCount && fClusters[0] != 0;
   1108     }
   1109     struct Cluster {
   1110         const char* fUtf8Text;
   1111         uint32_t fTextByteLength;
   1112         uint32_t fGlyphIndex;
   1113         uint32_t fGlyphCount;
   1114         explicit operator bool() const { return fGlyphCount != 0; }
   1115     };
   1116     // True if this looks like right-to-left text.
   1117     bool reversedChars() const { return fReversedChars; }
   1118     Cluster next() {
   1119         if ((!fUtf8Text || !fClusters) && fGlyphCount) {
   1120             // These glyphs have no text.  Treat as one "cluster".
   1121             uint32_t glyphCount = fGlyphCount;
   1122             fGlyphCount = 0;
   1123             return Cluster{nullptr, 0, 0, glyphCount};
   1124         }
   1125         if (fGlyphCount == 0 || fTextByteLength == 0) {
   1126             return Cluster{nullptr, 0, 0, 0};  // empty
   1127         }
   1128         SkASSERT(fUtf8Text);
   1129         SkASSERT(fClusters);
   1130         uint32_t cluster = fClusters[0];
   1131         if (cluster >= fTextByteLength) {
   1132             return Cluster{nullptr, 0, 0, 0};  // bad input.
   1133         }
   1134         uint32_t glyphsInCluster = 1;
   1135         while (glyphsInCluster < fGlyphCount &&
   1136                fClusters[glyphsInCluster] == cluster) {
   1137             ++glyphsInCluster;
   1138         }
   1139         SkASSERT(glyphsInCluster <= fGlyphCount);
   1140         uint32_t textLength = 0;
   1141         if (glyphsInCluster == fGlyphCount) {
   1142             // consumes rest of glyphs and rest of text
   1143             if (kInvalidCluster == fPreviousCluster) { // LTR text or single cluster
   1144                 textLength = fTextByteLength - cluster;
   1145             } else { // RTL text; last cluster.
   1146                 SkASSERT(fPreviousCluster < fTextByteLength);
   1147                 if (fPreviousCluster <= cluster) {  // bad input.
   1148                     return Cluster{nullptr, 0, 0, 0};
   1149                 }
   1150                 textLength = fPreviousCluster - cluster;
   1151             }
   1152             fGlyphCount = 0;
   1153             return Cluster{fUtf8Text + cluster,
   1154                            textLength,
   1155                            fGlyphIndex,
   1156                            glyphsInCluster};
   1157         }
   1158         SkASSERT(glyphsInCluster < fGlyphCount);
   1159         uint32_t nextCluster = fClusters[glyphsInCluster];
   1160         if (nextCluster >= fTextByteLength) {
   1161             return Cluster{nullptr, 0, 0, 0};  // bad input.
   1162         }
   1163         if (nextCluster > cluster) { // LTR text
   1164             if (kInvalidCluster != fPreviousCluster) {
   1165                 return Cluster{nullptr, 0, 0, 0};  // bad input.
   1166             }
   1167             textLength = nextCluster - cluster;
   1168         } else { // RTL text
   1169             SkASSERT(nextCluster < cluster);
   1170             if (kInvalidCluster == fPreviousCluster) { // first cluster
   1171                 textLength = fTextByteLength - cluster;
   1172             } else { // later cluster
   1173                 if (fPreviousCluster <= cluster) {
   1174                     return Cluster{nullptr, 0, 0, 0}; // bad input.
   1175                 }
   1176                 textLength = fPreviousCluster - cluster;
   1177             }
   1178             fPreviousCluster = cluster;
   1179         }
   1180         uint32_t glyphIndex = fGlyphIndex;
   1181         fGlyphCount -= glyphsInCluster;
   1182         fGlyphIndex += glyphsInCluster;
   1183         fClusters   += glyphsInCluster;
   1184         return Cluster{fUtf8Text + cluster,
   1185                        textLength,
   1186                        glyphIndex,
   1187                        glyphsInCluster};
   1188     }
   1189 
   1190 private:
   1191     static constexpr uint32_t kInvalidCluster = 0xFFFFFFFF;
   1192     const uint32_t* fClusters;
   1193     const char* fUtf8Text;
   1194     uint32_t fGlyphCount;
   1195     uint32_t fTextByteLength;
   1196     uint32_t fGlyphIndex = 0;
   1197     uint32_t fPreviousCluster = kInvalidCluster;
   1198     bool fReversedChars = false;
   1199 };
   1200 
   1201 struct TextStorage {
   1202     SkAutoTMalloc<char> fUtf8textStorage;
   1203     SkAutoTMalloc<uint32_t> fClusterStorage;
   1204     SkAutoTMalloc<SkGlyphID> fGlyphStorage;
   1205 };
   1206 }  // namespace
   1207 
   1208 /** Given some unicode text (as passed to drawText(), convert to
   1209     glyphs (via primitive shaping), while preserving
   1210     glyph-to-character mapping information. */
   1211 static Clusterator make_clusterator(
   1212         const void* sourceText,
   1213         size_t sourceByteCount,
   1214         const SkPaint& paint,
   1215         TextStorage* storage,
   1216         int glyphCount) {
   1217     SkASSERT(SkPaint::kGlyphID_TextEncoding != paint.getTextEncoding());
   1218     SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, nullptr));
   1219     SkASSERT(glyphCount > 0);
   1220     storage->fGlyphStorage.reset(SkToSizeT(glyphCount));
   1221     (void)paint.textToGlyphs(sourceText, sourceByteCount, storage->fGlyphStorage.get());
   1222     storage->fClusterStorage.reset(SkToSizeT(glyphCount));
   1223     uint32_t* clusters = storage->fClusterStorage.get();
   1224     uint32_t utf8ByteCount = 0;
   1225     const char* utf8Text = nullptr;
   1226     switch (paint.getTextEncoding()) {
   1227         case SkPaint::kUTF8_TextEncoding: {
   1228             const char* txtPtr = (const char*)sourceText;
   1229             for (int i = 0; i < glyphCount; ++i) {
   1230                 clusters[i] = SkToU32(txtPtr - (const char*)sourceText);
   1231                 txtPtr += SkUTF8_LeadByteToCount(*(const unsigned char*)txtPtr);
   1232                 SkASSERT(txtPtr <= (const char*)sourceText + sourceByteCount);
   1233             }
   1234             SkASSERT(txtPtr == (const char*)sourceText + sourceByteCount);
   1235             utf8ByteCount = SkToU32(sourceByteCount);
   1236             utf8Text = (const char*)sourceText;
   1237             break;
   1238         }
   1239         case SkPaint::kUTF16_TextEncoding: {
   1240             const uint16_t* utf16ptr = (const uint16_t*)sourceText;
   1241             int utf16count = SkToInt(sourceByteCount / sizeof(uint16_t));
   1242             utf8ByteCount = SkToU32(SkUTF16_ToUTF8(utf16ptr, utf16count));
   1243             storage->fUtf8textStorage.reset(utf8ByteCount);
   1244             char* txtPtr = storage->fUtf8textStorage.get();
   1245             utf8Text = txtPtr;
   1246             int clusterIndex = 0;
   1247             while (utf16ptr < (const uint16_t*)sourceText + utf16count) {
   1248                 clusters[clusterIndex++] = SkToU32(txtPtr - utf8Text);
   1249                 SkUnichar uni = SkUTF16_NextUnichar(&utf16ptr);
   1250                 txtPtr += SkUTF8_FromUnichar(uni, txtPtr);
   1251             }
   1252             SkASSERT(clusterIndex == glyphCount);
   1253             SkASSERT(txtPtr == storage->fUtf8textStorage.get() + utf8ByteCount);
   1254             SkASSERT(utf16ptr == (const uint16_t*)sourceText + utf16count);
   1255             break;
   1256         }
   1257         case SkPaint::kUTF32_TextEncoding: {
   1258             const SkUnichar* utf32 = (const SkUnichar*)sourceText;
   1259             int utf32count = SkToInt(sourceByteCount / sizeof(SkUnichar));
   1260             SkASSERT(glyphCount == utf32count);
   1261             for (int i = 0; i < utf32count; ++i) {
   1262                 utf8ByteCount += SkToU32(SkUTF8_FromUnichar(utf32[i]));
   1263             }
   1264             storage->fUtf8textStorage.reset(SkToSizeT(utf8ByteCount));
   1265             char* txtPtr = storage->fUtf8textStorage.get();
   1266             utf8Text = txtPtr;
   1267             for (int i = 0; i < utf32count; ++i) {
   1268                 clusters[i] = SkToU32(txtPtr - utf8Text);
   1269                 txtPtr += SkUTF8_FromUnichar(utf32[i], txtPtr);
   1270             }
   1271             break;
   1272         }
   1273         default:
   1274             SkDEBUGFAIL("");
   1275             break;
   1276     }
   1277     return Clusterator(clusters, utf8Text, SkToU32(glyphCount), utf8ByteCount);
   1278 }
   1279 
   1280 static SkUnichar map_glyph(const SkTDArray<SkUnichar>& glyphToUnicode, SkGlyphID glyph) {
   1281     return SkToInt(glyph) < glyphToUnicode.count() ? glyphToUnicode[SkToInt(glyph)] : -1;
   1282 }
   1283 
   1284 static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) {
   1285     wStream->writeText("/");
   1286     char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kFont_ResourceType);
   1287     wStream->write(&prefix, 1);
   1288     wStream->writeDecAsText(fontIndex);
   1289     wStream->writeText(" ");
   1290     SkPDFUtils::AppendScalar(textSize, wStream);
   1291     wStream->writeText(" Tf\n");
   1292 }
   1293 
   1294 static SkPath draw_text_as_path(const void* sourceText, size_t sourceByteCount,
   1295                                const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
   1296                                SkPoint offset, const SkPaint& srcPaint) {
   1297     SkPath path;
   1298     int glyphCount;
   1299     SkAutoTMalloc<SkPoint> tmpPoints;
   1300     switch (positioning) {
   1301         case SkTextBlob::kDefault_Positioning:
   1302             srcPaint.getTextPath(sourceText, sourceByteCount, offset.x(), offset.y(), &path);
   1303             break;
   1304         case SkTextBlob::kHorizontal_Positioning:
   1305             glyphCount = srcPaint.countText(sourceText, sourceByteCount);
   1306             tmpPoints.realloc(glyphCount);
   1307             for (int i = 0; i < glyphCount; ++i) {
   1308                 tmpPoints[i] = {pos[i] + offset.x(), offset.y()};
   1309             }
   1310             srcPaint.getPosTextPath(sourceText, sourceByteCount, tmpPoints.get(), &path);
   1311             break;
   1312         case SkTextBlob::kFull_Positioning:
   1313             srcPaint.getPosTextPath(sourceText, sourceByteCount, (const SkPoint*)pos, &path);
   1314             path.offset(offset.x(), offset.y());
   1315             break;
   1316     }
   1317     return path;
   1318 }
   1319 
   1320 static bool has_outline_glyph(SkGlyphID gid, SkGlyphCache* cache) {
   1321     const SkGlyph& glyph = cache->getGlyphIDMetrics(gid);
   1322     const SkPath* path = cache->findPath(glyph);
   1323     return (path && !path->isEmpty()) || (glyph.fWidth == 0 && glyph.fHeight == 0);
   1324 }
   1325 
   1326 static SkRect get_glyph_bounds_device_space(SkGlyphID gid, SkGlyphCache* cache,
   1327                                             SkScalar xScale, SkScalar yScale,
   1328                                             SkPoint xy, const SkMatrix& ctm) {
   1329     const SkGlyph& glyph = cache->getGlyphIDMetrics(gid);
   1330     SkRect glyphBounds = {glyph.fLeft * xScale,
   1331                           glyph.fTop * yScale,
   1332                           (glyph.fLeft + glyph.fWidth) * xScale,
   1333                           (glyph.fTop + glyph.fHeight) * yScale};
   1334     glyphBounds.offset(xy);
   1335     ctm.mapRect(&glyphBounds); // now in dev space.
   1336     return glyphBounds;
   1337 }
   1338 
   1339 static bool contains(const SkRect& r, SkPoint p) {
   1340    return r.left() <= p.x() && p.x() <= r.right() &&
   1341           r.top()  <= p.y() && p.y() <= r.bottom();
   1342 }
   1343 
   1344 static sk_sp<SkImage> image_from_mask(const SkMask& mask) {
   1345     if (!mask.fImage) {
   1346         return nullptr;
   1347     }
   1348     SkIRect bounds = mask.fBounds;
   1349     SkBitmap bm;
   1350     switch (mask.fFormat) {
   1351         case SkMask::kBW_Format:
   1352             bm.allocPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()));
   1353             for (int y = 0; y < bm.height(); ++y) {
   1354                 for (int x8 = 0; x8 < bm.width(); x8 += 8) {
   1355                     uint8_t v = *mask.getAddr1(x8 + bounds.x(), y + bounds.y());
   1356                     int e = SkTMin(x8 + 8, bm.width());
   1357                     for (int x = x8; x < e; ++x) {
   1358                         *bm.getAddr8(x, y) = (v >> (x & 0x7)) & 0x1 ? 0xFF : 0x00;
   1359                     }
   1360                 }
   1361             }
   1362             bm.setImmutable();
   1363             return SkImage::MakeFromBitmap(bm);
   1364         case SkMask::kA8_Format:
   1365             bm.installPixels(SkImageInfo::MakeA8(bounds.width(), bounds.height()),
   1366                              mask.fImage, mask.fRowBytes);
   1367             return SkMakeImageFromRasterBitmap(bm, kAlways_SkCopyPixelsMode);
   1368         case SkMask::kARGB32_Format:
   1369             bm.installPixels(SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()),
   1370                              mask.fImage, mask.fRowBytes);
   1371             return SkMakeImageFromRasterBitmap(bm, kAlways_SkCopyPixelsMode);
   1372         case SkMask::k3D_Format:
   1373             SkASSERT(false);
   1374             return nullptr;
   1375         case SkMask::kLCD16_Format:
   1376             SkASSERT(false);
   1377             return nullptr;
   1378         default:
   1379             SkASSERT(false);
   1380             return nullptr;
   1381     }
   1382 }
   1383 
   1384 void SkPDFDevice::internalDrawText(
   1385         const void* sourceText, size_t sourceByteCount,
   1386         const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
   1387         SkPoint offset, const SkPaint& srcPaint, const uint32_t* clusters,
   1388         uint32_t textByteLength, const char* utf8Text) {
   1389     if (0 == sourceByteCount || !sourceText || srcPaint.getTextSize() <= 0) {
   1390         return;
   1391     }
   1392     if (this->cs().isEmpty(this->bounds())) {
   1393         return;
   1394     }
   1395     NOT_IMPLEMENTED(srcPaint.isVerticalText(), false);
   1396     if (srcPaint.isVerticalText()) {
   1397         // Don't pretend we support drawing vertical text.  It is not
   1398         // clear to me how to switch to "vertical writing" mode in PDF.
   1399         // Currently neither Chromium or Android set this flag.
   1400         // https://bug.skia.org/5665
   1401     }
   1402     if (srcPaint.getPathEffect()
   1403             || srcPaint.getMaskFilter()
   1404             || SkPaint::kFill_Style != srcPaint.getStyle()) {
   1405         // Stroked Text doesn't work well with Type3 fonts.
   1406         SkPath path = draw_text_as_path(sourceText, sourceByteCount, pos,
   1407                                         positioning, offset, srcPaint);
   1408         this->drawPath(path, srcPaint, nullptr, true);
   1409         return;
   1410     }
   1411     SkPaint paint = calculate_text_paint(srcPaint);
   1412     remove_color_filter(&paint);
   1413     replace_srcmode_on_opaque_paint(&paint);
   1414     if (!paint.getTypeface()) {
   1415         paint.setTypeface(SkTypeface::MakeDefault());
   1416     }
   1417     SkTypeface* typeface = paint.getTypeface();
   1418     if (!typeface) {
   1419         SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n");
   1420         return;
   1421     }
   1422 
   1423     const SkAdvancedTypefaceMetrics* metrics =
   1424         SkPDFFont::GetMetrics(typeface, fDocument->canon());
   1425     if (!metrics) {
   1426         return;
   1427     }
   1428     int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr);
   1429     if (glyphCount <= 0) {
   1430         return;
   1431     }
   1432 
   1433     // These three heap buffers are only used in the case where no glyphs
   1434     // are passed to drawText() (most clients pass glyphs or a textblob).
   1435     TextStorage storage;
   1436     const SkGlyphID* glyphs = nullptr;
   1437     Clusterator clusterator;
   1438     if (textByteLength > 0) {
   1439         SkASSERT(glyphCount == SkToInt(sourceByteCount / sizeof(SkGlyphID)));
   1440         glyphs = (const SkGlyphID*)sourceText;
   1441         clusterator = Clusterator(clusters, utf8Text, SkToU32(glyphCount), textByteLength);
   1442         SkASSERT(clusters);
   1443         SkASSERT(utf8Text);
   1444         SkASSERT(srcPaint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
   1445         SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, nullptr));
   1446     } else if (SkPaint::kGlyphID_TextEncoding == srcPaint.getTextEncoding()) {
   1447         SkASSERT(glyphCount == SkToInt(sourceByteCount / sizeof(SkGlyphID)));
   1448         glyphs = (const SkGlyphID*)sourceText;
   1449         clusterator = Clusterator(SkToU32(glyphCount));
   1450         SkASSERT(glyphCount == paint.textToGlyphs(sourceText, sourceByteCount, nullptr));
   1451         SkASSERT(nullptr == clusters);
   1452         SkASSERT(nullptr == utf8Text);
   1453     } else {
   1454         SkASSERT(nullptr == clusters);
   1455         SkASSERT(nullptr == utf8Text);
   1456         clusterator = make_clusterator(sourceText, sourceByteCount, srcPaint,
   1457                                        &storage, glyphCount);
   1458         glyphs = storage.fGlyphStorage;
   1459     }
   1460     bool defaultPositioning = (positioning == SkTextBlob::kDefault_Positioning);
   1461     paint.setHinting(SkPaint::kNo_Hinting);
   1462 
   1463     int emSize;
   1464     SkAutoGlyphCache glyphCache = SkPDFFont::MakeVectorCache(typeface, &emSize);
   1465 
   1466     SkScalar textSize = paint.getTextSize();
   1467     SkScalar advanceScale = textSize * paint.getTextScaleX() / emSize;
   1468 
   1469     // textScaleX and textScaleY are used to get a conservative bounding box for glyphs.
   1470     SkScalar textScaleY = textSize / emSize;
   1471     SkScalar textScaleX = advanceScale + paint.getTextSkewX() * textScaleY;
   1472 
   1473     SkPaint::Align alignment = paint.getTextAlign();
   1474     float alignmentFactor = SkPaint::kLeft_Align   == alignment ?  0.0f :
   1475                             SkPaint::kCenter_Align == alignment ? -0.5f :
   1476                             /* SkPaint::kRight_Align */           -1.0f;
   1477     if (defaultPositioning && alignment != SkPaint::kLeft_Align) {
   1478         SkScalar advance = 0;
   1479         for (int i = 0; i < glyphCount; ++i) {
   1480             advance += advanceScale * glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX;
   1481         }
   1482         offset.offset(alignmentFactor * advance, 0);
   1483     }
   1484     SkRect clipStackBounds = this->cs().bounds(this->bounds());
   1485     struct PositionedGlyph {
   1486         SkPoint fPos;
   1487         SkGlyphID fGlyph;
   1488     };
   1489     SkTArray<PositionedGlyph> fMissingGlyphs;
   1490     {
   1491         ScopedContentEntry content(this, paint, true);
   1492         if (!content.entry()) {
   1493             return;
   1494         }
   1495         SkDynamicMemoryWStream* out = content.stream();
   1496         const SkTDArray<SkUnichar>& glyphToUnicode = metrics->fGlyphToUnicode;
   1497 
   1498         out->writeText("BT\n");
   1499         SK_AT_SCOPE_EXIT(out->writeText("ET\n"));
   1500 
   1501         const SkGlyphID maxGlyphID = SkToU16(typeface->countGlyphs() - 1);
   1502 
   1503         bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics));
   1504         if (clusterator.reversedChars()) {
   1505             out->writeText("/ReversedChars BMC\n");
   1506         }
   1507         SK_AT_SCOPE_EXIT(if (clusterator.reversedChars()) { out->writeText("EMC\n"); } );
   1508         GlyphPositioner glyphPositioner(out,
   1509                                         paint.getTextSkewX(),
   1510                                         multiByteGlyphs,
   1511                                         defaultPositioning,
   1512                                         offset);
   1513         SkPDFFont* font = nullptr;
   1514 
   1515         while (Clusterator::Cluster c = clusterator.next()) {
   1516             int index = c.fGlyphIndex;
   1517             int glyphLimit = index + c.fGlyphCount;
   1518 
   1519             bool actualText = false;
   1520             SK_AT_SCOPE_EXIT(if (actualText) {
   1521                                  glyphPositioner.flush();
   1522                                  out->writeText("EMC\n");
   1523                              });
   1524             if (c.fUtf8Text) {  // real cluster
   1525                 // Check if `/ActualText` needed.
   1526                 const char* textPtr = c.fUtf8Text;
   1527                 const char* textEnd = c.fUtf8Text + c.fTextByteLength;
   1528                 SkUnichar unichar = SkUTF8_NextUnicharWithError(&textPtr, textEnd);
   1529                 if (unichar < 0) {
   1530                     return;
   1531                 }
   1532                 if (textPtr < textEnd ||                                  // more characters left
   1533                     glyphLimit > index + 1 ||                             // toUnicode wouldn't work
   1534                     unichar != map_glyph(glyphToUnicode, glyphs[index]))  // test single Unichar map
   1535                 {
   1536                     glyphPositioner.flush();
   1537                     out->writeText("/Span<</ActualText <");
   1538                     SkPDFUtils::WriteUTF16beHex(out, 0xFEFF);  // U+FEFF = BYTE ORDER MARK
   1539                     // the BOM marks this text as UTF-16BE, not PDFDocEncoding.
   1540                     SkPDFUtils::WriteUTF16beHex(out, unichar);  // first char
   1541                     while (textPtr < textEnd) {
   1542                         unichar = SkUTF8_NextUnicharWithError(&textPtr, textEnd);
   1543                         if (unichar < 0) {
   1544                             break;
   1545                         }
   1546                         SkPDFUtils::WriteUTF16beHex(out, unichar);
   1547                     }
   1548                     out->writeText("> >> BDC\n");  // begin marked-content sequence
   1549                                                    // with an associated property list.
   1550                     actualText = true;
   1551                 }
   1552             }
   1553             for (; index < glyphLimit; ++index) {
   1554                 SkGlyphID gid = glyphs[index];
   1555                 if (gid > maxGlyphID) {
   1556                     continue;
   1557                 }
   1558                 if (!font || !font->hasGlyph(gid)) {
   1559                     // Not yet specified font or need to switch font.
   1560                     int fontIndex = this->getFontResourceIndex(typeface, gid);
   1561                     // All preconditions for SkPDFFont::GetFontResource are met.
   1562                     SkASSERT(fontIndex >= 0);
   1563                     if (fontIndex < 0) {
   1564                         return;
   1565                     }
   1566                     glyphPositioner.flush();
   1567                     update_font(out, fontIndex, textSize);
   1568                     font = fFontResources[fontIndex];
   1569                     SkASSERT(font);  // All preconditions for SkPDFFont::GetFontResource are met.
   1570                     if (!font) {
   1571                         return;
   1572                     }
   1573                     SkASSERT(font->multiByteGlyphs() == multiByteGlyphs);
   1574                 }
   1575                 SkPoint xy = {0, 0};
   1576                 SkScalar advance = advanceScale * glyphCache->getGlyphIDAdvance(gid).fAdvanceX;
   1577                 if (!defaultPositioning) {
   1578                     xy = SkTextBlob::kFull_Positioning == positioning
   1579                        ? SkPoint{pos[2 * index], pos[2 * index + 1]}
   1580                        : SkPoint{pos[index], 0};
   1581                     if (alignment != SkPaint::kLeft_Align) {
   1582                         xy.offset(alignmentFactor * advance, 0);
   1583                     }
   1584                     // Do a glyph-by-glyph bounds-reject if positions are absolute.
   1585                     SkRect glyphBounds = get_glyph_bounds_device_space(
   1586                             gid, glyphCache.get(), textScaleX, textScaleY,
   1587                             xy + offset, this->ctm());
   1588                     if (glyphBounds.isEmpty()) {
   1589                         if (!contains(clipStackBounds, {glyphBounds.x(), glyphBounds.y()})) {
   1590                             continue;
   1591                         }
   1592                     } else {
   1593                         if (!clipStackBounds.intersects(glyphBounds)) {
   1594                             continue;  // reject glyphs as out of bounds
   1595                         }
   1596                     }
   1597                     if (!has_outline_glyph(gid, glyphCache.get())) {
   1598                         fMissingGlyphs.push_back({xy + offset, gid});
   1599                     }
   1600                 } else {
   1601                     if (!has_outline_glyph(gid, glyphCache.get())) {
   1602                         fMissingGlyphs.push_back({offset, gid});
   1603                     }
   1604                     offset += SkPoint{advance, 0};
   1605                 }
   1606                 font->noteGlyphUsage(gid);
   1607 
   1608                 SkGlyphID encodedGlyph = multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid);
   1609                 glyphPositioner.writeGlyph(xy, advance, encodedGlyph);
   1610             }
   1611         }
   1612     }
   1613     if (fMissingGlyphs.count() > 0) {
   1614         // Fall back on images.
   1615         SkPaint scaledGlyphCachePaint;
   1616         scaledGlyphCachePaint.setTextSize(paint.getTextSize());
   1617         scaledGlyphCachePaint.setTextScaleX(paint.getTextScaleX());
   1618         scaledGlyphCachePaint.setTextSkewX(paint.getTextSkewX());
   1619         scaledGlyphCachePaint.setTypeface(sk_ref_sp(typeface));
   1620         SkAutoGlyphCache scaledGlyphCache(scaledGlyphCachePaint, nullptr, nullptr);
   1621         SkTHashMap<SkPDFCanon::BitmapGlyphKey, SkPDFCanon::BitmapGlyph>* map =
   1622             &this->getCanon()->fBitmapGlyphImages;
   1623         for (PositionedGlyph positionedGlyph : fMissingGlyphs) {
   1624             SkPDFCanon::BitmapGlyphKey key = {typeface->uniqueID(),
   1625                                               paint.getTextSize(),
   1626                                               paint.getTextScaleX(),
   1627                                               paint.getTextSkewX(),
   1628                                               positionedGlyph.fGlyph,
   1629                                               0};
   1630             SkImage* img = nullptr;
   1631             SkIPoint imgOffset = {0, 0};
   1632             if (SkPDFCanon::BitmapGlyph* ptr = map->find(key)) {
   1633                 img = ptr->fImage.get();
   1634                 imgOffset = ptr->fOffset;
   1635             } else {
   1636                 (void)scaledGlyphCache->findImage(
   1637                         scaledGlyphCache->getGlyphIDMetrics(positionedGlyph.fGlyph));
   1638                 SkMask mask;
   1639                 scaledGlyphCache->getGlyphIDMetrics(positionedGlyph.fGlyph).toMask(&mask);
   1640                 imgOffset = {mask.fBounds.x(), mask.fBounds.y()};
   1641                 img = map->set(key, {image_from_mask(mask), imgOffset})->fImage.get();
   1642             }
   1643             if (img) {
   1644                 SkPoint pt = positionedGlyph.fPos +
   1645                              SkPoint{(SkScalar)imgOffset.x(), (SkScalar)imgOffset.y()};
   1646                 this->drawImage(img, pt.x(), pt.y(), srcPaint);
   1647             }
   1648         }
   1649     }
   1650 }
   1651 
   1652 void SkPDFDevice::drawText(const void* text, size_t len,
   1653                            SkScalar x, SkScalar y, const SkPaint& paint) {
   1654     this->internalDrawText(text, len, nullptr, SkTextBlob::kDefault_Positioning,
   1655                            SkPoint{x, y}, paint, nullptr, 0, nullptr);
   1656 }
   1657 
   1658 void SkPDFDevice::drawPosText(const void* text, size_t len,
   1659                               const SkScalar pos[], int scalarsPerPos,
   1660                               const SkPoint& offset, const SkPaint& paint) {
   1661     this->internalDrawText(text, len, pos, (SkTextBlob::GlyphPositioning)scalarsPerPos,
   1662                            offset, paint, nullptr, 0, nullptr);
   1663 }
   1664 
   1665 void SkPDFDevice::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
   1666                                const SkPaint &paint, SkDrawFilter* drawFilter) {
   1667     for (SkTextBlobRunIterator it(blob); !it.done(); it.next()) {
   1668         SkPaint runPaint(paint);
   1669         it.applyFontToPaint(&runPaint);
   1670         if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) {
   1671             continue;
   1672         }
   1673         runPaint.setFlags(this->filterTextFlags(runPaint));
   1674         SkPoint offset = it.offset() + SkPoint{x, y};
   1675         this->internalDrawText(it.glyphs(), sizeof(SkGlyphID) * it.glyphCount(),
   1676                                it.pos(), it.positioning(), offset, runPaint,
   1677                                it.clusters(), it.textSize(), it.text());
   1678     }
   1679 }
   1680 
   1681 void SkPDFDevice::drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) {
   1682     if (this->cs().isEmpty(this->bounds())) {
   1683         return;
   1684     }
   1685     // TODO: implement drawVertices
   1686 }
   1687 
   1688 void SkPDFDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) {
   1689     SkASSERT(!paint.getImageFilter());
   1690 
   1691     // Check if the source device is really a bitmapdevice (because that's what we returned
   1692     // from createDevice (likely due to an imagefilter)
   1693     SkPixmap pmap;
   1694     if (device->peekPixels(&pmap)) {
   1695         SkBitmap bitmap;
   1696         bitmap.installPixels(pmap);
   1697         this->drawSprite(bitmap, x, y, paint);
   1698         return;
   1699     }
   1700 
   1701     // our onCreateCompatibleDevice() always creates SkPDFDevice subclasses.
   1702     SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device);
   1703 
   1704     SkScalar scalarX = SkIntToScalar(x);
   1705     SkScalar scalarY = SkIntToScalar(y);
   1706     for (const RectWithData& l : pdfDevice->fLinkToURLs) {
   1707         SkRect r = l.rect.makeOffset(scalarX, scalarY);
   1708         fLinkToURLs.emplace_back(RectWithData{r, l.data});
   1709     }
   1710     for (const RectWithData& l : pdfDevice->fLinkToDestinations) {
   1711         SkRect r = l.rect.makeOffset(scalarX, scalarY);
   1712         fLinkToDestinations.emplace_back(RectWithData{r, l.data});
   1713     }
   1714     for (const NamedDestination& d : pdfDevice->fNamedDestinations) {
   1715         SkPoint p = d.point + SkPoint::Make(scalarX, scalarY);
   1716         fNamedDestinations.emplace_back(NamedDestination{d.nameData, p});
   1717     }
   1718 
   1719     if (pdfDevice->isContentEmpty()) {
   1720         return;
   1721     }
   1722 
   1723     SkMatrix matrix = SkMatrix::MakeTrans(SkIntToScalar(x), SkIntToScalar(y));
   1724     ScopedContentEntry content(this, this->cs(), matrix, paint);
   1725     if (!content.entry()) {
   1726         return;
   1727     }
   1728     if (content.needShape()) {
   1729         SkPath shape;
   1730         shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
   1731                                        SkIntToScalar(device->width()),
   1732                                        SkIntToScalar(device->height())));
   1733         content.setShape(shape);
   1734     }
   1735     if (!content.needSource()) {
   1736         return;
   1737     }
   1738 
   1739     sk_sp<SkPDFObject> xObject = pdfDevice->makeFormXObjectFromDevice();
   1740     SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), content.stream());
   1741 }
   1742 
   1743 sk_sp<SkSurface> SkPDFDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
   1744     return SkSurface::MakeRaster(info, &props);
   1745 }
   1746 
   1747 
   1748 sk_sp<SkPDFDict> SkPDFDevice::makeResourceDict() const {
   1749     SkTDArray<SkPDFObject*> fonts;
   1750     fonts.setReserve(fFontResources.count());
   1751     for (SkPDFFont* font : fFontResources) {
   1752         fonts.push(font);
   1753     }
   1754     return SkPDFResourceDict::Make(
   1755             &fGraphicStateResources,
   1756             &fShaderResources,
   1757             &fXObjectResources,
   1758             &fonts);
   1759 }
   1760 
   1761 sk_sp<SkPDFArray> SkPDFDevice::copyMediaBox() const {
   1762     auto mediaBox = sk_make_sp<SkPDFArray>();
   1763     mediaBox->reserve(4);
   1764     mediaBox->appendInt(0);
   1765     mediaBox->appendInt(0);
   1766     mediaBox->appendInt(fPageSize.width());
   1767     mediaBox->appendInt(fPageSize.height());
   1768     return mediaBox;
   1769 }
   1770 
   1771 std::unique_ptr<SkStreamAsset> SkPDFDevice::content() const {
   1772     SkDynamicMemoryWStream buffer;
   1773     if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
   1774         SkPDFUtils::AppendTransform(fInitialTransform, &buffer);
   1775     }
   1776 
   1777     GraphicStackState gsState(fExistingClipStack, &buffer);
   1778     for (const auto& entry : fContentEntries) {
   1779         gsState.updateClip(entry.fState.fClipStack,
   1780                 {0, 0}, SkRect::Make(this->bounds()));
   1781         gsState.updateMatrix(entry.fState.fMatrix);
   1782         gsState.updateDrawingState(entry.fState);
   1783 
   1784         entry.fContent.writeToStream(&buffer);
   1785     }
   1786     gsState.drainStack();
   1787     if (buffer.bytesWritten() > 0) {
   1788         return std::unique_ptr<SkStreamAsset>(buffer.detachAsStream());
   1789     } else {
   1790         return skstd::make_unique<SkMemoryStream>();
   1791     }
   1792 }
   1793 
   1794 /* Draws an inverse filled path by using Path Ops to compute the positive
   1795  * inverse using the current clip as the inverse bounds.
   1796  * Return true if this was an inverse path and was properly handled,
   1797  * otherwise returns false and the normal drawing routine should continue,
   1798  * either as a (incorrect) fallback or because the path was not inverse
   1799  * in the first place.
   1800  */
   1801 bool SkPDFDevice::handleInversePath(const SkPath& origPath,
   1802                                     const SkPaint& paint, bool pathIsMutable,
   1803                                     const SkMatrix* prePathMatrix) {
   1804     if (!origPath.isInverseFillType()) {
   1805         return false;
   1806     }
   1807 
   1808     if (this->cs().isEmpty(this->bounds())) {
   1809         return false;
   1810     }
   1811 
   1812     SkPath modifiedPath;
   1813     SkPath* pathPtr = const_cast<SkPath*>(&origPath);
   1814     SkPaint noInversePaint(paint);
   1815 
   1816     // Merge stroking operations into final path.
   1817     if (SkPaint::kStroke_Style == paint.getStyle() ||
   1818         SkPaint::kStrokeAndFill_Style == paint.getStyle()) {
   1819         bool doFillPath = paint.getFillPath(origPath, &modifiedPath);
   1820         if (doFillPath) {
   1821             noInversePaint.setStyle(SkPaint::kFill_Style);
   1822             noInversePaint.setStrokeWidth(0);
   1823             pathPtr = &modifiedPath;
   1824         } else {
   1825             // To be consistent with the raster output, hairline strokes
   1826             // are rendered as non-inverted.
   1827             modifiedPath.toggleInverseFillType();
   1828             this->drawPath(modifiedPath, paint, nullptr, true);
   1829             return true;
   1830         }
   1831     }
   1832 
   1833     // Get bounds of clip in current transform space
   1834     // (clip bounds are given in device space).
   1835     SkMatrix transformInverse;
   1836     SkMatrix totalMatrix = this->ctm();
   1837     if (prePathMatrix) {
   1838         totalMatrix.preConcat(*prePathMatrix);
   1839     }
   1840     if (!totalMatrix.invert(&transformInverse)) {
   1841         return false;
   1842     }
   1843     SkRect bounds = this->cs().bounds(this->bounds());
   1844     transformInverse.mapRect(&bounds);
   1845 
   1846     // Extend the bounds by the line width (plus some padding)
   1847     // so the edge doesn't cause a visible stroke.
   1848     bounds.outset(paint.getStrokeWidth() + SK_Scalar1,
   1849                   paint.getStrokeWidth() + SK_Scalar1);
   1850 
   1851     if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) {
   1852         return false;
   1853     }
   1854 
   1855     this->drawPath(modifiedPath, noInversePaint, prePathMatrix, true);
   1856     return true;
   1857 }
   1858 
   1859 void SkPDFDevice::appendAnnotations(SkPDFArray* array) const {
   1860     array->reserve(fLinkToURLs.count() + fLinkToDestinations.count());
   1861     for (const RectWithData& rectWithURL : fLinkToURLs) {
   1862         SkRect r;
   1863         fInitialTransform.mapRect(&r, rectWithURL.rect);
   1864         array->appendObject(create_link_to_url(rectWithURL.data.get(), r));
   1865     }
   1866     for (const RectWithData& linkToDestination : fLinkToDestinations) {
   1867         SkRect r;
   1868         fInitialTransform.mapRect(&r, linkToDestination.rect);
   1869         array->appendObject(
   1870                 create_link_named_dest(linkToDestination.data.get(), r));
   1871     }
   1872 }
   1873 
   1874 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const {
   1875     for (const NamedDestination& dest : fNamedDestinations) {
   1876         auto pdfDest = sk_make_sp<SkPDFArray>();
   1877         pdfDest->reserve(5);
   1878         pdfDest->appendObjRef(sk_ref_sp(page));
   1879         pdfDest->appendName("XYZ");
   1880         SkPoint p = fInitialTransform.mapXY(dest.point.x(), dest.point.y());
   1881         pdfDest->appendScalar(p.x());
   1882         pdfDest->appendScalar(p.y());
   1883         pdfDest->appendInt(0);  // Leave zoom unchanged
   1884         SkString name(static_cast<const char*>(dest.nameData->data()));
   1885         dict->insertObject(name, std::move(pdfDest));
   1886     }
   1887 }
   1888 
   1889 sk_sp<SkPDFObject> SkPDFDevice::makeFormXObjectFromDevice(bool alpha) {
   1890     SkMatrix inverseTransform = SkMatrix::I();
   1891     if (!fInitialTransform.isIdentity()) {
   1892         if (!fInitialTransform.invert(&inverseTransform)) {
   1893             SkDEBUGFAIL("Layer initial transform should be invertible.");
   1894             inverseTransform.reset();
   1895         }
   1896     }
   1897     const char* colorSpace = alpha ? "DeviceGray" : nullptr;
   1898     sk_sp<SkPDFObject> xobject =
   1899         SkPDFMakeFormXObject(this->content(), this->copyMediaBox(),
   1900                              this->makeResourceDict(), inverseTransform, colorSpace);
   1901     // We always draw the form xobjects that we create back into the device, so
   1902     // we simply preserve the font usage instead of pulling it out and merging
   1903     // it back in later.
   1904     this->cleanUp();  // Reset this device to have no content.
   1905     this->init();
   1906     return xobject;
   1907 }
   1908 
   1909 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex,
   1910                                           sk_sp<SkPDFObject> mask,
   1911                                           const SkClipStack& clipStack,
   1912                                           SkBlendMode mode,
   1913                                           bool invertClip) {
   1914     if (!invertClip && clipStack.isEmpty(this->bounds())) {
   1915         return;
   1916     }
   1917 
   1918     sk_sp<SkPDFDict> sMaskGS = SkPDFGraphicState::GetSMaskGraphicState(
   1919             std::move(mask), invertClip,
   1920             SkPDFGraphicState::kAlpha_SMaskMode, fDocument->canon());
   1921 
   1922     SkPaint paint;
   1923     paint.setBlendMode(mode);
   1924     ScopedContentEntry content(this, clipStack, SkMatrix::I(), paint);
   1925     if (!content.entry()) {
   1926         return;
   1927     }
   1928     SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()), content.stream());
   1929     SkPDFUtils::DrawFormXObject(xObjectIndex, content.stream());
   1930     this->clearMaskOnGraphicState(content.stream());
   1931 }
   1932 
   1933 SkPDFDevice::ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack& clipStack,
   1934                                                           const SkMatrix& matrix,
   1935                                                           const SkPaint& paint,
   1936                                                           bool hasText,
   1937                                                           sk_sp<SkPDFObject>* dst) {
   1938     *dst = nullptr;
   1939     SkBlendMode blendMode = paint.getBlendMode();
   1940 
   1941     // For the following modes, we want to handle source and destination
   1942     // separately, so make an object of what's already there.
   1943     if (blendMode == SkBlendMode::kClear       ||
   1944             blendMode == SkBlendMode::kSrc     ||
   1945             blendMode == SkBlendMode::kSrcIn   ||
   1946             blendMode == SkBlendMode::kDstIn   ||
   1947             blendMode == SkBlendMode::kSrcOut  ||
   1948             blendMode == SkBlendMode::kDstOut  ||
   1949             blendMode == SkBlendMode::kSrcATop ||
   1950             blendMode == SkBlendMode::kDstATop ||
   1951             blendMode == SkBlendMode::kModulate) {
   1952         if (!isContentEmpty()) {
   1953             *dst = this->makeFormXObjectFromDevice();
   1954             SkASSERT(isContentEmpty());
   1955         } else if (blendMode != SkBlendMode::kSrc &&
   1956                    blendMode != SkBlendMode::kSrcOut) {
   1957             // Except for Src and SrcOut, if there isn't anything already there,
   1958             // then we're done.
   1959             return nullptr;
   1960         }
   1961     }
   1962     // TODO(vandebo): Figure out how/if we can handle the following modes:
   1963     // Xor, Plus.
   1964 
   1965     // Dst xfer mode doesn't draw source at all.
   1966     if (blendMode == SkBlendMode::kDst) {
   1967         return nullptr;
   1968     }
   1969 
   1970     SkPDFDevice::ContentEntry* entry;
   1971     if (fContentEntries.back() && fContentEntries.back()->fContent.bytesWritten() == 0) {
   1972         entry = fContentEntries.back();
   1973     } else if (blendMode != SkBlendMode::kDstOver) {
   1974         entry = fContentEntries.emplace_back();
   1975     } else {
   1976         entry = fContentEntries.emplace_front();
   1977     }
   1978     populateGraphicStateEntryFromPaint(matrix, clipStack, paint, hasText, &entry->fState);
   1979     return entry;
   1980 }
   1981 
   1982 void SkPDFDevice::finishContentEntry(SkBlendMode blendMode,
   1983                                      sk_sp<SkPDFObject> dst,
   1984                                      SkPath* shape) {
   1985     if (blendMode != SkBlendMode::kClear       &&
   1986             blendMode != SkBlendMode::kSrc     &&
   1987             blendMode != SkBlendMode::kDstOver &&
   1988             blendMode != SkBlendMode::kSrcIn   &&
   1989             blendMode != SkBlendMode::kDstIn   &&
   1990             blendMode != SkBlendMode::kSrcOut  &&
   1991             blendMode != SkBlendMode::kDstOut  &&
   1992             blendMode != SkBlendMode::kSrcATop &&
   1993             blendMode != SkBlendMode::kDstATop &&
   1994             blendMode != SkBlendMode::kModulate) {
   1995         SkASSERT(!dst);
   1996         return;
   1997     }
   1998     if (blendMode == SkBlendMode::kDstOver) {
   1999         SkASSERT(!dst);
   2000         if (fContentEntries.front()->fContent.bytesWritten() == 0) {
   2001             // For DstOver, an empty content entry was inserted before the rest
   2002             // of the content entries. If nothing was drawn, it needs to be
   2003             // removed.
   2004             fContentEntries.pop_front();
   2005         }
   2006         return;
   2007     }
   2008     if (!dst) {
   2009         SkASSERT(blendMode == SkBlendMode::kSrc ||
   2010                  blendMode == SkBlendMode::kSrcOut);
   2011         return;
   2012     }
   2013 
   2014     SkASSERT(dst);
   2015     SkASSERT(fContentEntries.count() == 1);
   2016     // Changing the current content into a form-xobject will destroy the clip
   2017     // objects which is fine since the xobject will already be clipped. However
   2018     // if source has shape, we need to clip it too, so a copy of the clip is
   2019     // saved.
   2020 
   2021     SkClipStack clipStack = fContentEntries.front()->fState.fClipStack;
   2022 
   2023     SkPaint stockPaint;
   2024 
   2025     sk_sp<SkPDFObject> srcFormXObject;
   2026     if (isContentEmpty()) {
   2027         // If nothing was drawn and there's no shape, then the draw was a
   2028         // no-op, but dst needs to be restored for that to be true.
   2029         // If there is shape, then an empty source with Src, SrcIn, SrcOut,
   2030         // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop
   2031         // reduces to Dst.
   2032         if (shape == nullptr || blendMode == SkBlendMode::kDstOut ||
   2033                 blendMode == SkBlendMode::kSrcATop) {
   2034             ScopedContentEntry content(this, fExistingClipStack, SkMatrix::I(), stockPaint);
   2035             // TODO: addXObjectResource take sk_sp
   2036             SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()), content.stream());
   2037             return;
   2038         } else {
   2039             blendMode = SkBlendMode::kClear;
   2040         }
   2041     } else {
   2042         SkASSERT(fContentEntries.count() == 1);
   2043         srcFormXObject = this->makeFormXObjectFromDevice();
   2044     }
   2045 
   2046     // TODO(vandebo) srcFormXObject may contain alpha, but here we want it
   2047     // without alpha.
   2048     if (blendMode == SkBlendMode::kSrcATop) {
   2049         // TODO(vandebo): In order to properly support SrcATop we have to track
   2050         // the shape of what's been drawn at all times. It's the intersection of
   2051         // the non-transparent parts of the device and the outlines (shape) of
   2052         // all images and devices drawn.
   2053         drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
   2054                                 fExistingClipStack, SkBlendMode::kSrcOver, true);
   2055     } else {
   2056         if (shape != nullptr) {
   2057             // Draw shape into a form-xobject.
   2058             SkPaint filledPaint;
   2059             filledPaint.setColor(SK_ColorBLACK);
   2060             filledPaint.setStyle(SkPaint::kFill_Style);
   2061             this->internalDrawPath(clipStack, SkMatrix::I(), *shape, filledPaint, nullptr, true);
   2062             this->drawFormXObjectWithMask(this->addXObjectResource(dst.get()),
   2063                                           this->makeFormXObjectFromDevice(),
   2064                                           fExistingClipStack,
   2065                                           SkBlendMode::kSrcOver, true);
   2066         } else {
   2067             this->drawFormXObjectWithMask(this->addXObjectResource(dst.get()),
   2068                                           srcFormXObject,
   2069                                           fExistingClipStack,
   2070                                           SkBlendMode::kSrcOver, true);
   2071         }
   2072     }
   2073 
   2074     if (blendMode == SkBlendMode::kClear) {
   2075         return;
   2076     } else if (blendMode == SkBlendMode::kSrc ||
   2077             blendMode == SkBlendMode::kDstATop) {
   2078         ScopedContentEntry content(this, fExistingClipStack, SkMatrix::I(), stockPaint);
   2079         if (content.entry()) {
   2080             SkPDFUtils::DrawFormXObject(this->addXObjectResource(srcFormXObject.get()),
   2081                                         content.stream());
   2082         }
   2083         if (blendMode == SkBlendMode::kSrc) {
   2084             return;
   2085         }
   2086     } else if (blendMode == SkBlendMode::kSrcATop) {
   2087         ScopedContentEntry content(this, fExistingClipStack,
   2088                                    SkMatrix::I(), stockPaint);
   2089         if (content.entry()) {
   2090             SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst.get()), content.stream());
   2091         }
   2092     }
   2093 
   2094     SkASSERT(blendMode == SkBlendMode::kSrcIn   ||
   2095              blendMode == SkBlendMode::kDstIn   ||
   2096              blendMode == SkBlendMode::kSrcOut  ||
   2097              blendMode == SkBlendMode::kDstOut  ||
   2098              blendMode == SkBlendMode::kSrcATop ||
   2099              blendMode == SkBlendMode::kDstATop ||
   2100              blendMode == SkBlendMode::kModulate);
   2101 
   2102     if (blendMode == SkBlendMode::kSrcIn ||
   2103             blendMode == SkBlendMode::kSrcOut ||
   2104             blendMode == SkBlendMode::kSrcATop) {
   2105         drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
   2106                                 std::move(dst),
   2107                                 fExistingClipStack,
   2108                                 SkBlendMode::kSrcOver,
   2109                                 blendMode == SkBlendMode::kSrcOut);
   2110         return;
   2111     } else {
   2112         SkBlendMode mode = SkBlendMode::kSrcOver;
   2113         int resourceID = addXObjectResource(dst.get());
   2114         if (blendMode == SkBlendMode::kModulate) {
   2115             drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
   2116                                     std::move(dst), fExistingClipStack,
   2117                                     SkBlendMode::kSrcOver, false);
   2118             mode = SkBlendMode::kMultiply;
   2119         }
   2120         drawFormXObjectWithMask(resourceID, std::move(srcFormXObject),
   2121                                 fExistingClipStack, mode,
   2122                                 blendMode == SkBlendMode::kDstOut);
   2123         return;
   2124     }
   2125 }
   2126 
   2127 bool SkPDFDevice::isContentEmpty() {
   2128     if (!fContentEntries.front() || fContentEntries.front()->fContent.bytesWritten() == 0) {
   2129         SkASSERT(fContentEntries.count() <= 1);
   2130         return true;
   2131     }
   2132     return false;
   2133 }
   2134 
   2135 void SkPDFDevice::populateGraphicStateEntryFromPaint(
   2136         const SkMatrix& matrix,
   2137         const SkClipStack& clipStack,
   2138         const SkPaint& paint,
   2139         bool hasText,
   2140         SkPDFDevice::GraphicStateEntry* entry) {
   2141     NOT_IMPLEMENTED(paint.getPathEffect() != nullptr, false);
   2142     NOT_IMPLEMENTED(paint.getMaskFilter() != nullptr, false);
   2143     NOT_IMPLEMENTED(paint.getColorFilter() != nullptr, false);
   2144 
   2145     entry->fMatrix = matrix;
   2146     entry->fClipStack = clipStack;
   2147     entry->fColor = SkColorSetA(paint.getColor(), 0xFF);
   2148     entry->fShaderIndex = -1;
   2149 
   2150     // PDF treats a shader as a color, so we only set one or the other.
   2151     sk_sp<SkPDFObject> pdfShader;
   2152     SkShader* shader = paint.getShader();
   2153     SkColor color = paint.getColor();
   2154     if (shader) {
   2155         if (SkShader::kColor_GradientType == shader->asAGradient(nullptr)) {
   2156             // We don't have to set a shader just for a color.
   2157             SkShader::GradientInfo gradientInfo;
   2158             SkColor gradientColor = SK_ColorBLACK;
   2159             gradientInfo.fColors = &gradientColor;
   2160             gradientInfo.fColorOffsets = nullptr;
   2161             gradientInfo.fColorCount = 1;
   2162             SkAssertResult(shader->asAGradient(&gradientInfo) == SkShader::kColor_GradientType);
   2163             entry->fColor = SkColorSetA(gradientColor, 0xFF);
   2164             color = gradientColor;
   2165         } else {
   2166             // PDF positions patterns relative to the initial transform, so
   2167             // we need to apply the current transform to the shader parameters.
   2168             SkMatrix transform = matrix;
   2169             transform.postConcat(fInitialTransform);
   2170 
   2171             // PDF doesn't support kClamp_TileMode, so we simulate it by making
   2172             // a pattern the size of the current clip.
   2173             SkRect clipStackBounds = clipStack.bounds(this->bounds());
   2174 
   2175             // We need to apply the initial transform to bounds in order to get
   2176             // bounds in a consistent coordinate system.
   2177             fInitialTransform.mapRect(&clipStackBounds);
   2178             SkIRect bounds;
   2179             clipStackBounds.roundOut(&bounds);
   2180 
   2181             pdfShader = SkPDFMakeShader(fDocument, shader, transform, bounds, paint.getColor());
   2182 
   2183             if (pdfShader.get()) {
   2184                 // pdfShader has been canonicalized so we can directly compare
   2185                 // pointers.
   2186                 int resourceIndex = fShaderResources.find(pdfShader.get());
   2187                 if (resourceIndex < 0) {
   2188                     resourceIndex = fShaderResources.count();
   2189                     fShaderResources.push(pdfShader.get());
   2190                     pdfShader.get()->ref();
   2191                 }
   2192                 entry->fShaderIndex = resourceIndex;
   2193             }
   2194         }
   2195     }
   2196 
   2197     sk_sp<SkPDFDict> newGraphicState;
   2198     if (color == paint.getColor()) {
   2199         newGraphicState = SkPDFGraphicState::GetGraphicStateForPaint(fDocument->canon(), paint);
   2200     } else {
   2201         SkPaint newPaint = paint;
   2202         newPaint.setColor(color);
   2203         newGraphicState = SkPDFGraphicState::GetGraphicStateForPaint(fDocument->canon(), newPaint);
   2204     }
   2205     int resourceIndex = addGraphicStateResource(newGraphicState.get());
   2206     entry->fGraphicStateIndex = resourceIndex;
   2207 
   2208     if (hasText) {
   2209         entry->fTextScaleX = paint.getTextScaleX();
   2210         entry->fTextFill = paint.getStyle();
   2211     } else {
   2212         entry->fTextScaleX = 0;
   2213     }
   2214 }
   2215 
   2216 int SkPDFDevice::addGraphicStateResource(SkPDFObject* gs) {
   2217     // Assumes that gs has been canonicalized (so we can directly compare
   2218     // pointers).
   2219     int result = fGraphicStateResources.find(gs);
   2220     if (result < 0) {
   2221         result = fGraphicStateResources.count();
   2222         fGraphicStateResources.push(gs);
   2223         gs->ref();
   2224     }
   2225     return result;
   2226 }
   2227 
   2228 int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) {
   2229     // TODO(halcanary): make this take a sk_sp<SkPDFObject>
   2230     // Assumes that xobject has been canonicalized (so we can directly compare
   2231     // pointers).
   2232     int result = fXObjectResources.find(xObject);
   2233     if (result < 0) {
   2234         result = fXObjectResources.count();
   2235         fXObjectResources.push(SkRef(xObject));
   2236     }
   2237     return result;
   2238 }
   2239 
   2240 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
   2241     sk_sp<SkPDFFont> newFont = SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID);
   2242     if (!newFont) {
   2243         return -1;
   2244     }
   2245     int resourceIndex = fFontResources.find(newFont.get());
   2246     if (resourceIndex < 0) {
   2247         fDocument->registerFont(newFont.get());
   2248         resourceIndex = fFontResources.count();
   2249         fFontResources.push(newFont.release());
   2250     }
   2251     return resourceIndex;
   2252 }
   2253 
   2254 static SkSize rect_to_size(const SkRect& r) { return {r.width(), r.height()}; }
   2255 
   2256 static sk_sp<SkImage> color_filter(const SkImage* image,
   2257                                    SkColorFilter* colorFilter) {
   2258     auto surface =
   2259         SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(image->dimensions()));
   2260     SkASSERT(surface);
   2261     SkCanvas* canvas = surface->getCanvas();
   2262     canvas->clear(SK_ColorTRANSPARENT);
   2263     SkPaint paint;
   2264     paint.setColorFilter(sk_ref_sp(colorFilter));
   2265     canvas->drawImage(image, 0, 0, &paint);
   2266     return surface->makeImageSnapshot();
   2267 }
   2268 
   2269 ////////////////////////////////////////////////////////////////////////////////
   2270 
   2271 static bool is_integer(SkScalar x) {
   2272     return x == SkScalarTruncToScalar(x);
   2273 }
   2274 
   2275 static bool is_integral(const SkRect& r) {
   2276     return is_integer(r.left()) &&
   2277            is_integer(r.top()) &&
   2278            is_integer(r.right()) &&
   2279            is_integer(r.bottom());
   2280 }
   2281 
   2282 void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset,
   2283                                         const SkRect* src,
   2284                                         const SkRect& dst,
   2285                                         const SkPaint& srcPaint,
   2286                                         const SkMatrix& ctm) {
   2287     if (!imageSubset) {
   2288         return;
   2289     }
   2290 
   2291     // First, figure out the src->dst transform and subset the image if needed.
   2292     SkIRect bounds = imageSubset.image()->bounds();
   2293     SkRect srcRect = src ? *src : SkRect::Make(bounds);
   2294     SkMatrix transform;
   2295     transform.setRectToRect(srcRect, dst, SkMatrix::kFill_ScaleToFit);
   2296     if (src && *src != SkRect::Make(bounds)) {
   2297         if (!srcRect.intersect(SkRect::Make(bounds))) {
   2298             return;
   2299         }
   2300         srcRect.roundOut(&bounds);
   2301         transform.preTranslate(SkIntToScalar(bounds.x()),
   2302                                SkIntToScalar(bounds.y()));
   2303         if (bounds != imageSubset.image()->bounds()) {
   2304             imageSubset = imageSubset.subset(bounds);
   2305         }
   2306         if (!imageSubset) {
   2307             return;
   2308         }
   2309     }
   2310 
   2311     // If the image is opaque and the paint's alpha is too, replace
   2312     // kSrc blendmode with kSrcOver.
   2313     SkPaint paint = srcPaint;
   2314     if (imageSubset.image()->isOpaque()) {
   2315         replace_srcmode_on_opaque_paint(&paint);
   2316     }
   2317 
   2318     // Alpha-only images need to get their color from the shader, before
   2319     // applying the colorfilter.
   2320     if (imageSubset.image()->isAlphaOnly() && paint.getColorFilter()) {
   2321         // must blend alpha image and shader before applying colorfilter.
   2322         auto surface =
   2323             SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(imageSubset.image()->dimensions()));
   2324         SkCanvas* canvas = surface->getCanvas();
   2325         SkPaint tmpPaint;
   2326         // In the case of alpha images with shaders, the shader's coordinate
   2327         // system is the image's coordiantes.
   2328         tmpPaint.setShader(sk_ref_sp(paint.getShader()));
   2329         tmpPaint.setColor(paint.getColor());
   2330         canvas->clear(0x00000000);
   2331         canvas->drawImage(imageSubset.image().get(), 0, 0, &tmpPaint);
   2332         paint.setShader(nullptr);
   2333         imageSubset = SkKeyedImage(surface->makeImageSnapshot());
   2334         SkASSERT(!imageSubset.image()->isAlphaOnly());
   2335     }
   2336 
   2337     if (imageSubset.image()->isAlphaOnly()) {
   2338         // The ColorFilter applies to the paint color/shader, not the alpha layer.
   2339         SkASSERT(nullptr == paint.getColorFilter());
   2340 
   2341         sk_sp<SkImage> mask = alpha_image_to_greyscale_image(imageSubset.image().get());
   2342         if (!mask) {
   2343             return;
   2344         }
   2345         // PDF doesn't seem to allow masking vector graphics with an Image XObject.
   2346         // Must mask with a Form XObject.
   2347         sk_sp<SkPDFDevice> maskDevice = this->makeCongruentDevice();
   2348         {
   2349             SkCanvas canvas(maskDevice.get());
   2350             if (paint.getMaskFilter()) {
   2351                 // This clip prevents the mask image shader from covering
   2352                 // entire device if unnecessary.
   2353                 canvas.clipRect(this->cs().bounds(this->bounds()));
   2354                 canvas.concat(ctm);
   2355                 SkPaint tmpPaint;
   2356                 tmpPaint.setShader(mask->makeShader(&transform));
   2357                 tmpPaint.setMaskFilter(sk_ref_sp(paint.getMaskFilter()));
   2358                 canvas.drawRect(dst, tmpPaint);
   2359             } else {
   2360                 canvas.concat(ctm);
   2361                 if (src && !is_integral(*src)) {
   2362                     canvas.clipRect(dst);
   2363                 }
   2364                 canvas.concat(transform);
   2365                 canvas.drawImage(mask, 0, 0);
   2366             }
   2367         }
   2368         if (!ctm.isIdentity() && paint.getShader()) {
   2369             transform_shader(&paint, ctm); // Since we are using identity matrix.
   2370         }
   2371         ScopedContentEntry content(this, this->cs(), SkMatrix::I(), paint);
   2372         if (!content.entry()) {
   2373             return;
   2374         }
   2375         this->addSMaskGraphicState(std::move(maskDevice), content.stream());
   2376         SkPDFUtils::AppendRectangle(SkRect::Make(fPageSize), content.stream());
   2377         SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kWinding_FillType, content.stream());
   2378         this->clearMaskOnGraphicState(content.stream());
   2379         return;
   2380     }
   2381     if (paint.getMaskFilter()) {
   2382         paint.setShader(imageSubset.image()->makeShader(&transform));
   2383         SkPath path;
   2384         path.addRect(dst);  // handles non-integral clipping.
   2385         this->internalDrawPath(this->cs(), this->ctm(), path, paint, nullptr, true);
   2386         return;
   2387     }
   2388     transform.postConcat(ctm);
   2389 
   2390     bool needToRestore = false;
   2391     if (src && !is_integral(*src)) {
   2392         // Need sub-pixel clipping to fix https://bug.skia.org/4374
   2393         this->cs().save();
   2394         this->cs().clipRect(dst, ctm, SkClipOp::kIntersect, true);
   2395         needToRestore = true;
   2396     }
   2397     SK_AT_SCOPE_EXIT(if (needToRestore) { this->cs().restore(); });
   2398 
   2399     #ifdef SK_PDF_IMAGE_STATS
   2400     gDrawImageCalls.fetch_add(1);
   2401     #endif
   2402     SkMatrix matrix = transform;
   2403 
   2404     // Rasterize the bitmap using perspective in a new bitmap.
   2405     if (transform.hasPerspective()) {
   2406         SkASSERT(fDocument->rasterDpi() > 0);
   2407         // Transform the bitmap in the new space, without taking into
   2408         // account the initial transform.
   2409         SkPath perspectiveOutline;
   2410         SkRect imageBounds = SkRect::Make(imageSubset.image()->bounds());
   2411         perspectiveOutline.addRect(imageBounds);
   2412         perspectiveOutline.transform(transform);
   2413 
   2414         // TODO(edisonn): perf - use current clip too.
   2415         // Retrieve the bounds of the new shape.
   2416         SkRect bounds = perspectiveOutline.getBounds();
   2417 
   2418         // Transform the bitmap in the new space, taking into
   2419         // account the initial transform.
   2420         SkMatrix total = transform;
   2421         total.postConcat(fInitialTransform);
   2422         SkScalar dpiScale = SkIntToScalar(fDocument->rasterDpi()) /
   2423                             SkIntToScalar(SkPDFUtils::kDpiForRasterScaleOne);
   2424         total.postScale(dpiScale, dpiScale);
   2425 
   2426         SkPath physicalPerspectiveOutline;
   2427         physicalPerspectiveOutline.addRect(imageBounds);
   2428         physicalPerspectiveOutline.transform(total);
   2429 
   2430         SkRect physicalPerspectiveBounds =
   2431                 physicalPerspectiveOutline.getBounds();
   2432         SkScalar scaleX = physicalPerspectiveBounds.width() / bounds.width();
   2433         SkScalar scaleY = physicalPerspectiveBounds.height() / bounds.height();
   2434 
   2435         // TODO(edisonn): A better approach would be to use a bitmap shader
   2436         // (in clamp mode) and draw a rect over the entire bounding box. Then
   2437         // intersect perspectiveOutline to the clip. That will avoid introducing
   2438         // alpha to the image while still giving good behavior at the edge of
   2439         // the image.  Avoiding alpha will reduce the pdf size and generation
   2440         // CPU time some.
   2441 
   2442         SkISize wh = rect_to_size(physicalPerspectiveBounds).toCeil();
   2443 
   2444         auto surface = SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(wh));
   2445         if (!surface) {
   2446             return;
   2447         }
   2448         SkCanvas* canvas = surface->getCanvas();
   2449         canvas->clear(SK_ColorTRANSPARENT);
   2450 
   2451         SkScalar deltaX = bounds.left();
   2452         SkScalar deltaY = bounds.top();
   2453 
   2454         SkMatrix offsetMatrix = transform;
   2455         offsetMatrix.postTranslate(-deltaX, -deltaY);
   2456         offsetMatrix.postScale(scaleX, scaleY);
   2457 
   2458         // Translate the draw in the new canvas, so we perfectly fit the
   2459         // shape in the bitmap.
   2460         canvas->setMatrix(offsetMatrix);
   2461         canvas->drawImage(imageSubset.image(), 0, 0);
   2462         // Make sure the final bits are in the bitmap.
   2463         canvas->flush();
   2464 
   2465         // In the new space, we use the identity matrix translated
   2466         // and scaled to reflect DPI.
   2467         matrix.setScale(1 / scaleX, 1 / scaleY);
   2468         matrix.postTranslate(deltaX, deltaY);
   2469 
   2470         imageSubset = SkKeyedImage(surface->makeImageSnapshot());
   2471         if (!imageSubset) {
   2472             return;
   2473         }
   2474     }
   2475 
   2476     SkMatrix scaled;
   2477     // Adjust for origin flip.
   2478     scaled.setScale(SK_Scalar1, -SK_Scalar1);
   2479     scaled.postTranslate(0, SK_Scalar1);
   2480     // Scale the image up from 1x1 to WxH.
   2481     SkIRect subset = imageSubset.image()->bounds();
   2482     scaled.postScale(SkIntToScalar(subset.width()),
   2483                      SkIntToScalar(subset.height()));
   2484     scaled.postConcat(matrix);
   2485     ScopedContentEntry content(this, this->cs(), scaled, paint);
   2486     if (!content.entry()) {
   2487         return;
   2488     }
   2489     if (content.needShape()) {
   2490         SkPath shape;
   2491         shape.addRect(SkRect::Make(subset));
   2492         shape.transform(matrix);
   2493         content.setShape(shape);
   2494     }
   2495     if (!content.needSource()) {
   2496         return;
   2497     }
   2498 
   2499     if (SkColorFilter* colorFilter = paint.getColorFilter()) {
   2500         sk_sp<SkImage> img = color_filter(imageSubset.image().get(), colorFilter);
   2501         imageSubset = SkKeyedImage(std::move(img));
   2502         if (!imageSubset) {
   2503             return;
   2504         }
   2505         // TODO(halcanary): de-dupe this by caching filtered images.
   2506         // (maybe in the resource cache?)
   2507     }
   2508 
   2509     SkBitmapKey key = imageSubset.key();
   2510     sk_sp<SkPDFObject>* pdfimagePtr = fDocument->canon()->fPDFBitmapMap.find(key);
   2511     sk_sp<SkPDFObject> pdfimage = pdfimagePtr ? *pdfimagePtr : nullptr;
   2512     if (!pdfimage) {
   2513         SkASSERT(imageSubset);
   2514         pdfimage = SkPDFCreateBitmapObject(imageSubset.release(),
   2515                                            fDocument->metadata().fEncodingQuality);
   2516         if (!pdfimage) {
   2517             return;
   2518         }
   2519         fDocument->serialize(pdfimage);  // serialize images early.
   2520         SkASSERT((key != SkBitmapKey{{0, 0, 0, 0}, 0}));
   2521         fDocument->canon()->fPDFBitmapMap.set(key, pdfimage);
   2522     }
   2523     // TODO(halcanary): addXObjectResource() should take a sk_sp<SkPDFObject>
   2524     SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), content.stream());
   2525 }
   2526 
   2527 ///////////////////////////////////////////////////////////////////////////////////////////////////
   2528 
   2529 #include "SkSpecialImage.h"
   2530 #include "SkImageFilter.h"
   2531 
   2532 void SkPDFDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y, const SkPaint& paint,
   2533                               SkImage* clipImage, const SkMatrix& clipMatrix) {
   2534     SkASSERT(!srcImg->isTextureBacked());
   2535 
   2536     //TODO: clipImage support
   2537 
   2538     SkBitmap resultBM;
   2539 
   2540     SkImageFilter* filter = paint.getImageFilter();
   2541     if (filter) {
   2542         SkIPoint offset = SkIPoint::Make(0, 0);
   2543         SkMatrix matrix = this->ctm();
   2544         matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
   2545         const SkIRect clipBounds =
   2546             this->cs().bounds(this->bounds()).roundOut().makeOffset(-x, -y);
   2547         sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
   2548         // TODO: Should PDF be operating in a specified color space? For now, run the filter
   2549         // in the same color space as the source (this is different from all other backends).
   2550         SkImageFilter::OutputProperties outputProperties(srcImg->getColorSpace());
   2551         SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
   2552 
   2553         sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
   2554         if (resultImg) {
   2555             SkPaint tmpUnfiltered(paint);
   2556             tmpUnfiltered.setImageFilter(nullptr);
   2557             if (resultImg->getROPixels(&resultBM)) {
   2558                 this->drawSprite(resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered);
   2559             }
   2560         }
   2561     } else {
   2562         if (srcImg->getROPixels(&resultBM)) {
   2563             this->drawSprite(resultBM, x, y, paint);
   2564         }
   2565     }
   2566 }
   2567 
   2568 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkBitmap& bitmap) {
   2569     return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap);
   2570 }
   2571 
   2572 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) {
   2573     // TODO: See comment above in drawSpecial. The color mode we use for decode should be driven
   2574     // by the destination where we're going to draw thing thing (ie this device). But we don't have
   2575     // a color space, so we always decode in legacy mode for now.
   2576     SkColorSpace* legacyColorSpace = nullptr;
   2577     return SkSpecialImage::MakeFromImage(image->bounds(),
   2578                                          image->makeNonTextureImage(), legacyColorSpace);
   2579 }
   2580 
   2581 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() {
   2582     return nullptr;
   2583 }
   2584 
   2585 SkImageFilterCache* SkPDFDevice::getImageFilterCache() {
   2586     // We always return a transient cache, so it is freed after each
   2587     // filter traversal.
   2588     return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
   2589 }
   2590