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