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 "SkAnnotation.h"
     11 #include "SkColor.h"
     12 #include "SkClipStack.h"
     13 #include "SkData.h"
     14 #include "SkDraw.h"
     15 #include "SkGlyphCache.h"
     16 #include "SkPaint.h"
     17 #include "SkPath.h"
     18 #include "SkPathOps.h"
     19 #include "SkPDFBitmap.h"
     20 #include "SkPDFFont.h"
     21 #include "SkPDFFormXObject.h"
     22 #include "SkPDFGraphicState.h"
     23 #include "SkPDFResourceDict.h"
     24 #include "SkPDFShader.h"
     25 #include "SkPDFStream.h"
     26 #include "SkPDFTypes.h"
     27 #include "SkPDFUtils.h"
     28 #include "SkRect.h"
     29 #include "SkRRect.h"
     30 #include "SkString.h"
     31 #include "SkSurface.h"
     32 #include "SkTextFormatParams.h"
     33 #include "SkTemplates.h"
     34 #include "SkTypefacePriv.h"
     35 #include "SkXfermodeInterpretation.h"
     36 
     37 #define DPI_FOR_RASTER_SCALE_ONE 72
     38 
     39 // Utility functions
     40 
     41 // If the paint will definitely draw opaquely, replace kSrc_Mode with
     42 // kSrcOver_Mode.  http://crbug.com/473572
     43 static void replace_srcmode_on_opaque_paint(SkPaint* paint) {
     44     if (kSrcOver_SkXfermodeInterpretation
     45         == SkInterpretXfermode(*paint, false)) {
     46         paint->setXfermode(NULL);
     47     }
     48 }
     49 
     50 static void emit_pdf_color(SkColor color, SkWStream* result) {
     51     SkASSERT(SkColorGetA(color) == 0xFF);  // We handle alpha elsewhere.
     52     SkScalar colorScale = SkScalarInvert(0xFF);
     53     SkPDFUtils::AppendScalar(SkColorGetR(color) * colorScale, result);
     54     result->writeText(" ");
     55     SkPDFUtils::AppendScalar(SkColorGetG(color) * colorScale, result);
     56     result->writeText(" ");
     57     SkPDFUtils::AppendScalar(SkColorGetB(color) * colorScale, result);
     58     result->writeText(" ");
     59 }
     60 
     61 static SkPaint calculate_text_paint(const SkPaint& paint) {
     62     SkPaint result = paint;
     63     if (result.isFakeBoldText()) {
     64         SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(),
     65                                                     kStdFakeBoldInterpKeys,
     66                                                     kStdFakeBoldInterpValues,
     67                                                     kStdFakeBoldInterpLength);
     68         SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale);
     69         if (result.getStyle() == SkPaint::kFill_Style) {
     70             result.setStyle(SkPaint::kStrokeAndFill_Style);
     71         } else {
     72             width += result.getStrokeWidth();
     73         }
     74         result.setStrokeWidth(width);
     75     }
     76     return result;
     77 }
     78 
     79 // Stolen from measure_text in SkDraw.cpp and then tweaked.
     80 static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
     81                        const uint16_t* glyphs, size_t len,
     82                        SkScalar* x, SkScalar* y) {
     83     if (paint.getTextAlign() == SkPaint::kLeft_Align) {
     84         return;
     85     }
     86 
     87     SkMatrix ident;
     88     ident.reset();
     89     SkAutoGlyphCache autoCache(paint, NULL, &ident);
     90     SkGlyphCache* cache = autoCache.getCache();
     91 
     92     const char* start = reinterpret_cast<const char*>(glyphs);
     93     const char* stop = reinterpret_cast<const char*>(glyphs + len);
     94     SkFixed xAdv = 0, yAdv = 0;
     95 
     96     // TODO(vandebo): This probably needs to take kerning into account.
     97     while (start < stop) {
     98         const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0);
     99         xAdv += glyph.fAdvanceX;
    100         yAdv += glyph.fAdvanceY;
    101     };
    102     if (paint.getTextAlign() == SkPaint::kLeft_Align) {
    103         return;
    104     }
    105 
    106     SkScalar xAdj = SkFixedToScalar(xAdv);
    107     SkScalar yAdj = SkFixedToScalar(yAdv);
    108     if (paint.getTextAlign() == SkPaint::kCenter_Align) {
    109         xAdj = SkScalarHalf(xAdj);
    110         yAdj = SkScalarHalf(yAdj);
    111     }
    112     *x = *x - xAdj;
    113     *y = *y - yAdj;
    114 }
    115 
    116 static int max_glyphid_for_typeface(SkTypeface* typeface) {
    117     SkAutoResolveDefaultTypeface autoResolve(typeface);
    118     typeface = autoResolve.get();
    119     return typeface->countGlyphs() - 1;
    120 }
    121 
    122 typedef SkAutoSTMalloc<128, uint16_t> SkGlyphStorage;
    123 
    124 static int force_glyph_encoding(const SkPaint& paint, const void* text,
    125                                 size_t len, SkGlyphStorage* storage,
    126                                 const uint16_t** glyphIDs) {
    127     // Make sure we have a glyph id encoding.
    128     if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
    129         int numGlyphs = paint.textToGlyphs(text, len, NULL);
    130         storage->reset(numGlyphs);
    131         paint.textToGlyphs(text, len, storage->get());
    132         *glyphIDs = storage->get();
    133         return numGlyphs;
    134     }
    135 
    136     // For user supplied glyph ids we need to validate them.
    137     SkASSERT((len & 1) == 0);
    138     int numGlyphs = SkToInt(len / 2);
    139     const uint16_t* input = static_cast<const uint16_t*>(text);
    140 
    141     int maxGlyphID = max_glyphid_for_typeface(paint.getTypeface());
    142     int validated;
    143     for (validated = 0; validated < numGlyphs; ++validated) {
    144         if (input[validated] > maxGlyphID) {
    145             break;
    146         }
    147     }
    148     if (validated >= numGlyphs) {
    149         *glyphIDs = static_cast<const uint16_t*>(text);
    150         return numGlyphs;
    151     }
    152 
    153     // Silently drop anything out of range.
    154     storage->reset(numGlyphs);
    155     if (validated > 0) {
    156         memcpy(storage->get(), input, validated * sizeof(uint16_t));
    157     }
    158 
    159     for (int i = validated; i < numGlyphs; ++i) {
    160         storage->get()[i] = input[i];
    161         if (input[i] > maxGlyphID) {
    162             storage->get()[i] = 0;
    163         }
    164     }
    165     *glyphIDs = storage->get();
    166     return numGlyphs;
    167 }
    168 
    169 static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX,
    170                                SkWStream* content) {
    171     // Flip the text about the x-axis to account for origin swap and include
    172     // the passed parameters.
    173     content->writeText("1 0 ");
    174     SkPDFUtils::AppendScalar(0 - textSkewX, content);
    175     content->writeText(" -1 ");
    176     SkPDFUtils::AppendScalar(x, content);
    177     content->writeText(" ");
    178     SkPDFUtils::AppendScalar(y, content);
    179     content->writeText(" Tm\n");
    180 }
    181 
    182 // It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
    183 // later being our representation of an object in the PDF file.
    184 struct GraphicStateEntry {
    185     GraphicStateEntry();
    186 
    187     // Compare the fields we care about when setting up a new content entry.
    188     bool compareInitialState(const GraphicStateEntry& b);
    189 
    190     SkMatrix fMatrix;
    191     // We can't do set operations on Paths, though PDF natively supports
    192     // intersect.  If the clip stack does anything other than intersect,
    193     // we have to fall back to the region.  Treat fClipStack as authoritative.
    194     // See http://code.google.com/p/skia/issues/detail?id=221
    195     SkClipStack fClipStack;
    196     SkRegion fClipRegion;
    197 
    198     // When emitting the content entry, we will ensure the graphic state
    199     // is set to these values first.
    200     SkColor fColor;
    201     SkScalar fTextScaleX;  // Zero means we don't care what the value is.
    202     SkPaint::Style fTextFill;  // Only if TextScaleX is non-zero.
    203     int fShaderIndex;
    204     int fGraphicStateIndex;
    205 
    206     // We may change the font (i.e. for Type1 support) within a
    207     // ContentEntry.  This is the one currently in effect, or NULL if none.
    208     SkPDFFont* fFont;
    209     // In PDF, text size has no default value. It is only valid if fFont is
    210     // not NULL.
    211     SkScalar fTextSize;
    212 };
    213 
    214 GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK),
    215                                          fTextScaleX(SK_Scalar1),
    216                                          fTextFill(SkPaint::kFill_Style),
    217                                          fShaderIndex(-1),
    218                                          fGraphicStateIndex(-1),
    219                                          fFont(NULL),
    220                                          fTextSize(SK_ScalarNaN) {
    221     fMatrix.reset();
    222 }
    223 
    224 bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& cur) {
    225     return fColor == cur.fColor &&
    226            fShaderIndex == cur.fShaderIndex &&
    227            fGraphicStateIndex == cur.fGraphicStateIndex &&
    228            fMatrix == cur.fMatrix &&
    229            fClipStack == cur.fClipStack &&
    230            (fTextScaleX == 0 ||
    231                (fTextScaleX == cur.fTextScaleX && fTextFill == cur.fTextFill));
    232 }
    233 
    234 class GraphicStackState {
    235 public:
    236     GraphicStackState(const SkClipStack& existingClipStack,
    237                       const SkRegion& existingClipRegion,
    238                       SkWStream* contentStream)
    239             : fStackDepth(0),
    240               fContentStream(contentStream) {
    241         fEntries[0].fClipStack = existingClipStack;
    242         fEntries[0].fClipRegion = existingClipRegion;
    243     }
    244 
    245     void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion,
    246                     const SkPoint& translation);
    247     void updateMatrix(const SkMatrix& matrix);
    248     void updateDrawingState(const GraphicStateEntry& state);
    249 
    250     void drainStack();
    251 
    252 private:
    253     void push();
    254     void pop();
    255     GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; }
    256 
    257     // Conservative limit on save depth, see impl. notes in PDF 1.4 spec.
    258     static const int kMaxStackDepth = 12;
    259     GraphicStateEntry fEntries[kMaxStackDepth + 1];
    260     int fStackDepth;
    261     SkWStream* fContentStream;
    262 };
    263 
    264 void GraphicStackState::drainStack() {
    265     while (fStackDepth) {
    266         pop();
    267     }
    268 }
    269 
    270 void GraphicStackState::push() {
    271     SkASSERT(fStackDepth < kMaxStackDepth);
    272     fContentStream->writeText("q\n");
    273     fStackDepth++;
    274     fEntries[fStackDepth] = fEntries[fStackDepth - 1];
    275 }
    276 
    277 void GraphicStackState::pop() {
    278     SkASSERT(fStackDepth > 0);
    279     fContentStream->writeText("Q\n");
    280     fStackDepth--;
    281 }
    282 
    283 // This function initializes iter to be an iterator on the "stack" argument
    284 // and then skips over the leading entries as specified in prefix.  It requires
    285 // and asserts that "prefix" will be a prefix to "stack."
    286 static void skip_clip_stack_prefix(const SkClipStack& prefix,
    287                                    const SkClipStack& stack,
    288                                    SkClipStack::Iter* iter) {
    289     SkClipStack::B2TIter prefixIter(prefix);
    290     iter->reset(stack, SkClipStack::Iter::kBottom_IterStart);
    291 
    292     const SkClipStack::Element* prefixEntry;
    293     const SkClipStack::Element* iterEntry;
    294 
    295     for (prefixEntry = prefixIter.next(); prefixEntry;
    296             prefixEntry = prefixIter.next()) {
    297         iterEntry = iter->next();
    298         SkASSERT(iterEntry);
    299         // Because of SkClipStack does internal intersection, the last clip
    300         // entry may differ.
    301         if (*prefixEntry != *iterEntry) {
    302             SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op);
    303             SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op);
    304             SkASSERT(iterEntry->getType() == prefixEntry->getType());
    305             // back up the iterator by one
    306             iter->prev();
    307             prefixEntry = prefixIter.next();
    308             break;
    309         }
    310     }
    311 
    312     SkASSERT(prefixEntry == NULL);
    313 }
    314 
    315 static void emit_clip(SkPath* clipPath, SkRect* clipRect,
    316                       SkWStream* contentStream) {
    317     SkASSERT(clipPath || clipRect);
    318 
    319     SkPath::FillType clipFill;
    320     if (clipPath) {
    321         SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream);
    322         clipFill = clipPath->getFillType();
    323     } else {
    324         SkPDFUtils::AppendRectangle(*clipRect, contentStream);
    325         clipFill = SkPath::kWinding_FillType;
    326     }
    327 
    328     NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false);
    329     NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false);
    330     if (clipFill == SkPath::kEvenOdd_FillType) {
    331         contentStream->writeText("W* n\n");
    332     } else {
    333         contentStream->writeText("W n\n");
    334     }
    335 }
    336 
    337 /* Calculate an inverted path's equivalent non-inverted path, given the
    338  * canvas bounds.
    339  * outPath may alias with invPath (since this is supported by PathOps).
    340  */
    341 static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath,
    342                                    SkPath* outPath) {
    343     SkASSERT(invPath.isInverseFillType());
    344 
    345     SkPath clipPath;
    346     clipPath.addRect(bounds);
    347 
    348     return Op(clipPath, invPath, kIntersect_PathOp, outPath);
    349 }
    350 
    351 #ifdef SK_PDF_USE_PATHOPS_CLIPPING
    352 // Sanity check the numerical values of the SkRegion ops and PathOps ops
    353 // enums so region_op_to_pathops_op can do a straight passthrough cast.
    354 // If these are failing, it may be necessary to make region_op_to_pathops_op
    355 // do more.
    356 SK_COMPILE_ASSERT(SkRegion::kDifference_Op == (int)kDifference_PathOp,
    357                   region_pathop_mismatch);
    358 SK_COMPILE_ASSERT(SkRegion::kIntersect_Op == (int)kIntersect_PathOp,
    359                   region_pathop_mismatch);
    360 SK_COMPILE_ASSERT(SkRegion::kUnion_Op == (int)kUnion_PathOp,
    361                   region_pathop_mismatch);
    362 SK_COMPILE_ASSERT(SkRegion::kXOR_Op == (int)kXOR_PathOp,
    363                   region_pathop_mismatch);
    364 SK_COMPILE_ASSERT(SkRegion::kReverseDifference_Op ==
    365                   (int)kReverseDifference_PathOp,
    366                   region_pathop_mismatch);
    367 
    368 static SkPathOp region_op_to_pathops_op(SkRegion::Op op) {
    369     SkASSERT(op >= 0);
    370     SkASSERT(op <= SkRegion::kReverseDifference_Op);
    371     return (SkPathOp)op;
    372 }
    373 
    374 /* Uses Path Ops to calculate a vector SkPath clip from a clip stack.
    375  * Returns true if successful, or false if not successful.
    376  * If successful, the resulting clip is stored in outClipPath.
    377  * If not successful, outClipPath is undefined, and a fallback method
    378  * should be used.
    379  */
    380 static bool get_clip_stack_path(const SkMatrix& transform,
    381                                 const SkClipStack& clipStack,
    382                                 const SkRegion& clipRegion,
    383                                 SkPath* outClipPath) {
    384     outClipPath->reset();
    385     outClipPath->setFillType(SkPath::kInverseWinding_FillType);
    386 
    387     const SkClipStack::Element* clipEntry;
    388     SkClipStack::Iter iter;
    389     iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart);
    390     for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
    391         SkPath entryPath;
    392         if (SkClipStack::Element::kEmpty_Type == clipEntry->getType()) {
    393             outClipPath->reset();
    394             outClipPath->setFillType(SkPath::kInverseWinding_FillType);
    395             continue;
    396         } else {
    397             clipEntry->asPath(&entryPath);
    398         }
    399         entryPath.transform(transform);
    400 
    401         if (SkRegion::kReplace_Op == clipEntry->getOp()) {
    402             *outClipPath = entryPath;
    403         } else {
    404             SkPathOp op = region_op_to_pathops_op(clipEntry->getOp());
    405             if (!Op(*outClipPath, entryPath, op, outClipPath)) {
    406                 return false;
    407             }
    408         }
    409     }
    410 
    411     if (outClipPath->isInverseFillType()) {
    412         // The bounds are slightly outset to ensure this is correct in the
    413         // face of floating-point accuracy and possible SkRegion bitmap
    414         // approximations.
    415         SkRect clipBounds = SkRect::Make(clipRegion.getBounds());
    416         clipBounds.outset(SK_Scalar1, SK_Scalar1);
    417         if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) {
    418             return false;
    419         }
    420     }
    421     return true;
    422 }
    423 #endif
    424 
    425 // TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF
    426 // graphic state stack, and the fact that we can know all the clips used
    427 // on the page to optimize this.
    428 void GraphicStackState::updateClip(const SkClipStack& clipStack,
    429                                    const SkRegion& clipRegion,
    430                                    const SkPoint& translation) {
    431     if (clipStack == currentEntry()->fClipStack) {
    432         return;
    433     }
    434 
    435     while (fStackDepth > 0) {
    436         pop();
    437         if (clipStack == currentEntry()->fClipStack) {
    438             return;
    439         }
    440     }
    441     push();
    442 
    443     currentEntry()->fClipStack = clipStack;
    444     currentEntry()->fClipRegion = clipRegion;
    445 
    446     SkMatrix transform;
    447     transform.setTranslate(translation.fX, translation.fY);
    448 
    449 #ifdef SK_PDF_USE_PATHOPS_CLIPPING
    450     SkPath clipPath;
    451     if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) {
    452         emit_clip(&clipPath, NULL, fContentStream);
    453         return;
    454     }
    455 #endif
    456     // gsState->initialEntry()->fClipStack/Region specifies the clip that has
    457     // already been applied.  (If this is a top level device, then it specifies
    458     // a clip to the content area.  If this is a layer, then it specifies
    459     // the clip in effect when the layer was created.)  There's no need to
    460     // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the
    461     // initial clip on the parent layer.  (This means there's a bug if the user
    462     // expands the clip and then uses any xfer mode that uses dst:
    463     // http://code.google.com/p/skia/issues/detail?id=228 )
    464     SkClipStack::Iter iter;
    465     skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
    466 
    467     // If the clip stack does anything other than intersect or if it uses
    468     // an inverse fill type, we have to fall back to the clip region.
    469     bool needRegion = false;
    470     const SkClipStack::Element* clipEntry;
    471     for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
    472         if (clipEntry->getOp() != SkRegion::kIntersect_Op ||
    473                 clipEntry->isInverseFilled()) {
    474             needRegion = true;
    475             break;
    476         }
    477     }
    478 
    479     if (needRegion) {
    480         SkPath clipPath;
    481         SkAssertResult(clipRegion.getBoundaryPath(&clipPath));
    482         emit_clip(&clipPath, NULL, fContentStream);
    483     } else {
    484         skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
    485         const SkClipStack::Element* clipEntry;
    486         for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
    487             SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op);
    488             switch (clipEntry->getType()) {
    489                 case SkClipStack::Element::kRect_Type: {
    490                     SkRect translatedClip;
    491                     transform.mapRect(&translatedClip, clipEntry->getRect());
    492                     emit_clip(NULL, &translatedClip, fContentStream);
    493                     break;
    494                 }
    495                 default: {
    496                     SkPath translatedPath;
    497                     clipEntry->asPath(&translatedPath);
    498                     translatedPath.transform(transform, &translatedPath);
    499                     emit_clip(&translatedPath, NULL, fContentStream);
    500                     break;
    501                 }
    502             }
    503         }
    504     }
    505 }
    506 
    507 void GraphicStackState::updateMatrix(const SkMatrix& matrix) {
    508     if (matrix == currentEntry()->fMatrix) {
    509         return;
    510     }
    511 
    512     if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) {
    513         SkASSERT(fStackDepth > 0);
    514         SkASSERT(fEntries[fStackDepth].fClipStack ==
    515                  fEntries[fStackDepth -1].fClipStack);
    516         pop();
    517 
    518         SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask);
    519     }
    520     if (matrix.getType() == SkMatrix::kIdentity_Mask) {
    521         return;
    522     }
    523 
    524     push();
    525     SkPDFUtils::AppendTransform(matrix, fContentStream);
    526     currentEntry()->fMatrix = matrix;
    527 }
    528 
    529 void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
    530     // PDF treats a shader as a color, so we only set one or the other.
    531     if (state.fShaderIndex >= 0) {
    532         if (state.fShaderIndex != currentEntry()->fShaderIndex) {
    533             SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream);
    534             currentEntry()->fShaderIndex = state.fShaderIndex;
    535         }
    536     } else {
    537         if (state.fColor != currentEntry()->fColor ||
    538                 currentEntry()->fShaderIndex >= 0) {
    539             emit_pdf_color(state.fColor, fContentStream);
    540             fContentStream->writeText("RG ");
    541             emit_pdf_color(state.fColor, fContentStream);
    542             fContentStream->writeText("rg\n");
    543             currentEntry()->fColor = state.fColor;
    544             currentEntry()->fShaderIndex = -1;
    545         }
    546     }
    547 
    548     if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) {
    549         SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream);
    550         currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex;
    551     }
    552 
    553     if (state.fTextScaleX) {
    554         if (state.fTextScaleX != currentEntry()->fTextScaleX) {
    555             SkScalar pdfScale = SkScalarMul(state.fTextScaleX,
    556                                             SkIntToScalar(100));
    557             SkPDFUtils::AppendScalar(pdfScale, fContentStream);
    558             fContentStream->writeText(" Tz\n");
    559             currentEntry()->fTextScaleX = state.fTextScaleX;
    560         }
    561         if (state.fTextFill != currentEntry()->fTextFill) {
    562             SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value);
    563             SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1,
    564                               enum_must_match_value);
    565             SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2,
    566                               enum_must_match_value);
    567             fContentStream->writeDecAsText(state.fTextFill);
    568             fContentStream->writeText(" Tr\n");
    569             currentEntry()->fTextFill = state.fTextFill;
    570         }
    571     }
    572 }
    573 
    574 static bool not_supported_for_layers(const SkPaint& layerPaint) {
    575     // PDF does not support image filters, so render them on CPU.
    576     // Note that this rendering is done at "screen" resolution (100dpi), not
    577     // printer resolution.
    578     // FIXME: It may be possible to express some filters natively using PDF
    579     // to improve quality and file size (http://skbug.com/3043)
    580 
    581     // TODO: should we return true if there is a colorfilter?
    582     return layerPaint.getImageFilter() != NULL;
    583 }
    584 
    585 SkBaseDevice* SkPDFDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint* layerPaint) {
    586     if (cinfo.fForImageFilter ||
    587         (layerPaint && not_supported_for_layers(*layerPaint))) {
    588         return NULL;
    589     }
    590     SkISize size = SkISize::Make(cinfo.fInfo.width(), cinfo.fInfo.height());
    591     return SkPDFDevice::Create(size, fRasterDpi, fCanon);
    592 }
    593 
    594 
    595 struct ContentEntry {
    596     GraphicStateEntry fState;
    597     SkDynamicMemoryWStream fContent;
    598     SkAutoTDelete<ContentEntry> fNext;
    599 
    600     // If the stack is too deep we could get Stack Overflow.
    601     // So we manually destruct the object.
    602     ~ContentEntry() {
    603         ContentEntry* val = fNext.detach();
    604         while (val != NULL) {
    605             ContentEntry* valNext = val->fNext.detach();
    606             // When the destructor is called, fNext is NULL and exits.
    607             delete val;
    608             val = valNext;
    609         }
    610     }
    611 };
    612 
    613 // A helper class to automatically finish a ContentEntry at the end of a
    614 // drawing method and maintain the state needed between set up and finish.
    615 class ScopedContentEntry {
    616 public:
    617     ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw,
    618                        const SkPaint& paint, bool hasText = false)
    619         : fDevice(device),
    620           fContentEntry(NULL),
    621           fXfermode(SkXfermode::kSrcOver_Mode),
    622           fDstFormXObject(NULL) {
    623         init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText);
    624     }
    625     ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack,
    626                        const SkRegion& clipRegion, const SkMatrix& matrix,
    627                        const SkPaint& paint, bool hasText = false)
    628         : fDevice(device),
    629           fContentEntry(NULL),
    630           fXfermode(SkXfermode::kSrcOver_Mode),
    631           fDstFormXObject(NULL) {
    632         init(clipStack, clipRegion, matrix, paint, hasText);
    633     }
    634 
    635     ~ScopedContentEntry() {
    636         if (fContentEntry) {
    637             SkPath* shape = &fShape;
    638             if (shape->isEmpty()) {
    639                 shape = NULL;
    640             }
    641             fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape);
    642         }
    643         SkSafeUnref(fDstFormXObject);
    644     }
    645 
    646     ContentEntry* entry() { return fContentEntry; }
    647 
    648     /* Returns true when we explicitly need the shape of the drawing. */
    649     bool needShape() {
    650         switch (fXfermode) {
    651             case SkXfermode::kClear_Mode:
    652             case SkXfermode::kSrc_Mode:
    653             case SkXfermode::kSrcIn_Mode:
    654             case SkXfermode::kSrcOut_Mode:
    655             case SkXfermode::kDstIn_Mode:
    656             case SkXfermode::kDstOut_Mode:
    657             case SkXfermode::kSrcATop_Mode:
    658             case SkXfermode::kDstATop_Mode:
    659             case SkXfermode::kModulate_Mode:
    660                 return true;
    661             default:
    662                 return false;
    663         }
    664     }
    665 
    666     /* Returns true unless we only need the shape of the drawing. */
    667     bool needSource() {
    668         if (fXfermode == SkXfermode::kClear_Mode) {
    669             return false;
    670         }
    671         return true;
    672     }
    673 
    674     /* If the shape is different than the alpha component of the content, then
    675      * setShape should be called with the shape.  In particular, images and
    676      * devices have rectangular shape.
    677      */
    678     void setShape(const SkPath& shape) {
    679         fShape = shape;
    680     }
    681 
    682 private:
    683     SkPDFDevice* fDevice;
    684     ContentEntry* fContentEntry;
    685     SkXfermode::Mode fXfermode;
    686     SkPDFFormXObject* fDstFormXObject;
    687     SkPath fShape;
    688 
    689     void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
    690               const SkMatrix& matrix, const SkPaint& paint, bool hasText) {
    691         // Shape has to be flatten before we get here.
    692         if (matrix.hasPerspective()) {
    693             NOT_IMPLEMENTED(!matrix.hasPerspective(), false);
    694             return;
    695         }
    696         if (paint.getXfermode()) {
    697             paint.getXfermode()->asMode(&fXfermode);
    698         }
    699         fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion,
    700                                                    matrix, paint, hasText,
    701                                                    &fDstFormXObject);
    702     }
    703 };
    704 
    705 ////////////////////////////////////////////////////////////////////////////////
    706 
    707 SkPDFDevice::SkPDFDevice(SkISize pageSize,
    708                          SkScalar rasterDpi,
    709                          SkPDFCanon* canon,
    710                          bool flip)
    711     : fPageSize(pageSize)
    712     , fContentSize(pageSize)
    713     , fExistingClipRegion(SkIRect::MakeSize(pageSize))
    714     , fAnnotations(NULL)
    715     , fLastContentEntry(NULL)
    716     , fLastMarginContentEntry(NULL)
    717     , fDrawingArea(kContent_DrawingArea)
    718     , fClipStack(NULL)
    719     , fFontGlyphUsage(SkNEW(SkPDFGlyphSetMap))
    720     , fRasterDpi(rasterDpi)
    721     , fCanon(canon) {
    722     SkASSERT(pageSize.width() > 0);
    723     SkASSERT(pageSize.height() > 0);
    724     fLegacyBitmap.setInfo(
    725             SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height()));
    726     if (flip) {
    727         // Skia generally uses the top left as the origin but PDF
    728         // natively has the origin at the bottom left. This matrix
    729         // corrects for that.  But that only needs to be done once, we
    730         // don't do it when layering.
    731         fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight));
    732         fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1);
    733     } else {
    734         fInitialTransform.setIdentity();
    735     }
    736 }
    737 
    738 SkPDFDevice::~SkPDFDevice() {
    739     this->cleanUp(true);
    740 }
    741 
    742 void SkPDFDevice::init() {
    743     fAnnotations = NULL;
    744     fContentEntries.free();
    745     fLastContentEntry = NULL;
    746     fMarginContentEntries.free();
    747     fLastMarginContentEntry = NULL;
    748     fDrawingArea = kContent_DrawingArea;
    749     if (fFontGlyphUsage.get() == NULL) {
    750         fFontGlyphUsage.reset(SkNEW(SkPDFGlyphSetMap));
    751     }
    752 }
    753 
    754 void SkPDFDevice::cleanUp(bool clearFontUsage) {
    755     fGraphicStateResources.unrefAll();
    756     fXObjectResources.unrefAll();
    757     fFontResources.unrefAll();
    758     fShaderResources.unrefAll();
    759     SkSafeUnref(fAnnotations);
    760     fNamedDestinations.deleteAll();
    761 
    762     if (clearFontUsage) {
    763         fFontGlyphUsage->reset();
    764     }
    765 }
    766 
    767 void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
    768     SkPaint newPaint = paint;
    769     replace_srcmode_on_opaque_paint(&newPaint);
    770 
    771     newPaint.setStyle(SkPaint::kFill_Style);
    772     ScopedContentEntry content(this, d, newPaint);
    773     internalDrawPaint(newPaint, content.entry());
    774 }
    775 
    776 void SkPDFDevice::internalDrawPaint(const SkPaint& paint,
    777                                     ContentEntry* contentEntry) {
    778     if (!contentEntry) {
    779         return;
    780     }
    781     SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()),
    782                                  SkIntToScalar(this->height()));
    783     SkMatrix inverse;
    784     if (!contentEntry->fState.fMatrix.invert(&inverse)) {
    785         return;
    786     }
    787     inverse.mapRect(&bbox);
    788 
    789     SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent);
    790     SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
    791                           &contentEntry->fContent);
    792 }
    793 
    794 void SkPDFDevice::drawPoints(const SkDraw& d,
    795                              SkCanvas::PointMode mode,
    796                              size_t count,
    797                              const SkPoint* points,
    798                              const SkPaint& srcPaint) {
    799     SkPaint passedPaint = srcPaint;
    800     replace_srcmode_on_opaque_paint(&passedPaint);
    801 
    802     if (count == 0) {
    803         return;
    804     }
    805 
    806     if (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) {
    807         return;
    808     }
    809 
    810     // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath.
    811     // We only use this when there's a path effect because of the overhead
    812     // of multiple calls to setUpContentEntry it causes.
    813     if (passedPaint.getPathEffect()) {
    814         if (d.fClip->isEmpty()) {
    815             return;
    816         }
    817         SkDraw pointDraw(d);
    818         pointDraw.fDevice = this;
    819         pointDraw.drawPoints(mode, count, points, passedPaint, true);
    820         return;
    821     }
    822 
    823     const SkPaint* paint = &passedPaint;
    824     SkPaint modifiedPaint;
    825 
    826     if (mode == SkCanvas::kPoints_PointMode &&
    827             paint->getStrokeCap() != SkPaint::kRound_Cap) {
    828         modifiedPaint = *paint;
    829         paint = &modifiedPaint;
    830         if (paint->getStrokeWidth()) {
    831             // PDF won't draw a single point with square/butt caps because the
    832             // orientation is ambiguous.  Draw a rectangle instead.
    833             modifiedPaint.setStyle(SkPaint::kFill_Style);
    834             SkScalar strokeWidth = paint->getStrokeWidth();
    835             SkScalar halfStroke = SkScalarHalf(strokeWidth);
    836             for (size_t i = 0; i < count; i++) {
    837                 SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0);
    838                 r.inset(-halfStroke, -halfStroke);
    839                 drawRect(d, r, modifiedPaint);
    840             }
    841             return;
    842         } else {
    843             modifiedPaint.setStrokeCap(SkPaint::kRound_Cap);
    844         }
    845     }
    846 
    847     ScopedContentEntry content(this, d, *paint);
    848     if (!content.entry()) {
    849         return;
    850     }
    851 
    852     switch (mode) {
    853         case SkCanvas::kPolygon_PointMode:
    854             SkPDFUtils::MoveTo(points[0].fX, points[0].fY,
    855                                &content.entry()->fContent);
    856             for (size_t i = 1; i < count; i++) {
    857                 SkPDFUtils::AppendLine(points[i].fX, points[i].fY,
    858                                        &content.entry()->fContent);
    859             }
    860             SkPDFUtils::StrokePath(&content.entry()->fContent);
    861             break;
    862         case SkCanvas::kLines_PointMode:
    863             for (size_t i = 0; i < count/2; i++) {
    864                 SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY,
    865                                    &content.entry()->fContent);
    866                 SkPDFUtils::AppendLine(points[i * 2 + 1].fX,
    867                                        points[i * 2 + 1].fY,
    868                                        &content.entry()->fContent);
    869                 SkPDFUtils::StrokePath(&content.entry()->fContent);
    870             }
    871             break;
    872         case SkCanvas::kPoints_PointMode:
    873             SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap);
    874             for (size_t i = 0; i < count; i++) {
    875                 SkPDFUtils::MoveTo(points[i].fX, points[i].fY,
    876                                    &content.entry()->fContent);
    877                 SkPDFUtils::ClosePath(&content.entry()->fContent);
    878                 SkPDFUtils::StrokePath(&content.entry()->fContent);
    879             }
    880             break;
    881         default:
    882             SkASSERT(false);
    883     }
    884 }
    885 
    886 void SkPDFDevice::drawRect(const SkDraw& d,
    887                            const SkRect& rect,
    888                            const SkPaint& srcPaint) {
    889     SkPaint paint = srcPaint;
    890     replace_srcmode_on_opaque_paint(&paint);
    891     SkRect r = rect;
    892     r.sort();
    893 
    894     if (paint.getPathEffect()) {
    895         if (d.fClip->isEmpty()) {
    896             return;
    897         }
    898         SkPath path;
    899         path.addRect(r);
    900         drawPath(d, path, paint, NULL, true);
    901         return;
    902     }
    903 
    904     if (handleRectAnnotation(r, *d.fMatrix, paint)) {
    905         return;
    906     }
    907 
    908     ScopedContentEntry content(this, d, paint);
    909     if (!content.entry()) {
    910         return;
    911     }
    912     SkPDFUtils::AppendRectangle(r, &content.entry()->fContent);
    913     SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
    914                           &content.entry()->fContent);
    915 }
    916 
    917 void SkPDFDevice::drawRRect(const SkDraw& draw,
    918                             const SkRRect& rrect,
    919                             const SkPaint& srcPaint) {
    920     SkPaint paint = srcPaint;
    921     replace_srcmode_on_opaque_paint(&paint);
    922     SkPath  path;
    923     path.addRRect(rrect);
    924     this->drawPath(draw, path, paint, NULL, true);
    925 }
    926 
    927 void SkPDFDevice::drawOval(const SkDraw& draw,
    928                            const SkRect& oval,
    929                            const SkPaint& srcPaint) {
    930     SkPaint paint = srcPaint;
    931     replace_srcmode_on_opaque_paint(&paint);
    932     SkPath  path;
    933     path.addOval(oval);
    934     this->drawPath(draw, path, paint, NULL, true);
    935 }
    936 
    937 void SkPDFDevice::drawPath(const SkDraw& d,
    938                            const SkPath& origPath,
    939                            const SkPaint& srcPaint,
    940                            const SkMatrix* prePathMatrix,
    941                            bool pathIsMutable) {
    942     SkPaint paint = srcPaint;
    943     replace_srcmode_on_opaque_paint(&paint);
    944     SkPath modifiedPath;
    945     SkPath* pathPtr = const_cast<SkPath*>(&origPath);
    946 
    947     SkMatrix matrix = *d.fMatrix;
    948     if (prePathMatrix) {
    949         if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
    950             if (!pathIsMutable) {
    951                 pathPtr = &modifiedPath;
    952                 pathIsMutable = true;
    953             }
    954             origPath.transform(*prePathMatrix, pathPtr);
    955         } else {
    956             matrix.preConcat(*prePathMatrix);
    957         }
    958     }
    959 
    960     if (paint.getPathEffect()) {
    961         if (d.fClip->isEmpty()) {
    962             return;
    963         }
    964         if (!pathIsMutable) {
    965             pathPtr = &modifiedPath;
    966             pathIsMutable = true;
    967         }
    968         bool fill = paint.getFillPath(origPath, pathPtr);
    969 
    970         SkPaint noEffectPaint(paint);
    971         noEffectPaint.setPathEffect(NULL);
    972         if (fill) {
    973             noEffectPaint.setStyle(SkPaint::kFill_Style);
    974         } else {
    975             noEffectPaint.setStyle(SkPaint::kStroke_Style);
    976             noEffectPaint.setStrokeWidth(0);
    977         }
    978         drawPath(d, *pathPtr, noEffectPaint, NULL, true);
    979         return;
    980     }
    981 
    982     if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) {
    983         return;
    984     }
    985 
    986     if (handleRectAnnotation(pathPtr->getBounds(), matrix, paint)) {
    987         return;
    988     }
    989 
    990     ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
    991     if (!content.entry()) {
    992         return;
    993     }
    994     SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(),
    995                          &content.entry()->fContent);
    996     SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
    997                           &content.entry()->fContent);
    998 }
    999 
   1000 void SkPDFDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
   1001                                  const SkRect* src, const SkRect& dst,
   1002                                  const SkPaint& srcPaint,
   1003                                  SkCanvas::DrawBitmapRectFlags flags) {
   1004     SkPaint paint = srcPaint;
   1005     if (bitmap.isOpaque()) {
   1006         replace_srcmode_on_opaque_paint(&paint);
   1007     }
   1008 
   1009     // TODO: this code path must be updated to respect the flags parameter
   1010     SkMatrix    matrix;
   1011     SkRect      bitmapBounds, tmpSrc, tmpDst;
   1012     SkBitmap    tmpBitmap;
   1013 
   1014     bitmapBounds.isetWH(bitmap.width(), bitmap.height());
   1015 
   1016     // Compute matrix from the two rectangles
   1017     if (src) {
   1018         tmpSrc = *src;
   1019     } else {
   1020         tmpSrc = bitmapBounds;
   1021     }
   1022     matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
   1023 
   1024     const SkBitmap* bitmapPtr = &bitmap;
   1025 
   1026     // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
   1027     // needed (if the src was clipped). No check needed if src==null.
   1028     if (src) {
   1029         if (!bitmapBounds.contains(*src)) {
   1030             if (!tmpSrc.intersect(bitmapBounds)) {
   1031                 return; // nothing to draw
   1032             }
   1033             // recompute dst, based on the smaller tmpSrc
   1034             matrix.mapRect(&tmpDst, tmpSrc);
   1035         }
   1036 
   1037         // since we may need to clamp to the borders of the src rect within
   1038         // the bitmap, we extract a subset.
   1039         // TODO: make sure this is handled in drawBitmap and remove from here.
   1040         SkIRect srcIR;
   1041         tmpSrc.roundOut(&srcIR);
   1042         if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
   1043             return;
   1044         }
   1045         bitmapPtr = &tmpBitmap;
   1046 
   1047         // Since we did an extract, we need to adjust the matrix accordingly
   1048         SkScalar dx = 0, dy = 0;
   1049         if (srcIR.fLeft > 0) {
   1050             dx = SkIntToScalar(srcIR.fLeft);
   1051         }
   1052         if (srcIR.fTop > 0) {
   1053             dy = SkIntToScalar(srcIR.fTop);
   1054         }
   1055         if (dx || dy) {
   1056             matrix.preTranslate(dx, dy);
   1057         }
   1058     }
   1059     this->drawBitmap(draw, *bitmapPtr, matrix, paint);
   1060 }
   1061 
   1062 void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
   1063                              const SkMatrix& matrix, const SkPaint& srcPaint) {
   1064     SkPaint paint = srcPaint;
   1065     if (bitmap.isOpaque()) {
   1066         replace_srcmode_on_opaque_paint(&paint);
   1067     }
   1068 
   1069     if (d.fClip->isEmpty()) {
   1070         return;
   1071     }
   1072 
   1073     SkMatrix transform = matrix;
   1074     transform.postConcat(*d.fMatrix);
   1075     this->internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, NULL,
   1076                              paint);
   1077 }
   1078 
   1079 void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap,
   1080                              int x, int y, const SkPaint& srcPaint) {
   1081     SkPaint paint = srcPaint;
   1082     if (bitmap.isOpaque()) {
   1083         replace_srcmode_on_opaque_paint(&paint);
   1084     }
   1085 
   1086     if (d.fClip->isEmpty()) {
   1087         return;
   1088     }
   1089 
   1090     SkMatrix matrix;
   1091     matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
   1092     this->internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL,
   1093                              paint);
   1094 }
   1095 
   1096 //  Create a PDF string. Maximum length (in bytes) is 65,535.
   1097 //  @param input     A string value.
   1098 //  @param len       The length of the input array.
   1099 //  @param wideChars True iff the upper byte in each uint16_t is
   1100 //                   significant and should be encoded and not
   1101 //                   discarded.  If true, the upper byte is encoded
   1102 //                   first.  Otherwise, we assert the upper byte is
   1103 //                   zero.
   1104 static SkString format_wide_string(const uint16_t* input,
   1105                                    size_t len,
   1106                                    bool wideChars) {
   1107     if (wideChars) {
   1108         SkASSERT(2 * len < 65535);
   1109         static const char gHex[] = "0123456789ABCDEF";
   1110         SkString result(4 * len + 2);
   1111         result[0] = '<';
   1112         for (size_t i = 0; i < len; i++) {
   1113             result[4 * i + 1] = gHex[(input[i] >> 12) & 0xF];
   1114             result[4 * i + 2] = gHex[(input[i] >>  8) & 0xF];
   1115             result[4 * i + 3] = gHex[(input[i] >>  4) & 0xF];
   1116             result[4 * i + 4] = gHex[(input[i]      ) & 0xF];
   1117         }
   1118         result[4 * len + 1] = '>';
   1119         return result;
   1120     } else {
   1121         SkASSERT(len <= 65535);
   1122         SkString tmp(len);
   1123         for (size_t i = 0; i < len; i++) {
   1124             SkASSERT(0 == input[i] >> 8);
   1125             tmp[i] = static_cast<uint8_t>(input[i]);
   1126         }
   1127         return SkPDFUtils::FormatString(tmp.c_str(), tmp.size());
   1128     }
   1129 }
   1130 
   1131 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
   1132                            SkScalar x, SkScalar y, const SkPaint& srcPaint) {
   1133     SkPaint paint = srcPaint;
   1134     replace_srcmode_on_opaque_paint(&paint);
   1135 
   1136     NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
   1137     if (paint.getMaskFilter() != NULL) {
   1138         // Don't pretend we support drawing MaskFilters, it makes for artifacts
   1139         // making text unreadable (e.g. same text twice when using CSS shadows).
   1140         return;
   1141     }
   1142     SkPaint textPaint = calculate_text_paint(paint);
   1143     ScopedContentEntry content(this, d, textPaint, true);
   1144     if (!content.entry()) {
   1145         return;
   1146     }
   1147 
   1148     SkGlyphStorage storage(0);
   1149     const uint16_t* glyphIDs = NULL;
   1150     int numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs);
   1151     textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
   1152 
   1153     SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
   1154     align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y);
   1155     content.entry()->fContent.writeText("BT\n");
   1156     set_text_transform(x, y, textPaint.getTextSkewX(),
   1157                        &content.entry()->fContent);
   1158     int consumedGlyphCount = 0;
   1159 
   1160     SkTDArray<uint16_t> glyphIDsCopy(glyphIDs, numGlyphs);
   1161 
   1162     while (numGlyphs > consumedGlyphCount) {
   1163         updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry());
   1164         SkPDFFont* font = content.entry()->fState.fFont;
   1165 
   1166         int availableGlyphs = font->glyphsToPDFFontEncoding(
   1167                 glyphIDsCopy.begin() + consumedGlyphCount,
   1168                 numGlyphs - consumedGlyphCount);
   1169         fFontGlyphUsage->noteGlyphUsage(
   1170                 font,  glyphIDsCopy.begin() + consumedGlyphCount,
   1171                 availableGlyphs);
   1172         SkString encodedString =
   1173                 format_wide_string(glyphIDsCopy.begin() + consumedGlyphCount,
   1174                                    availableGlyphs, font->multiByteGlyphs());
   1175         content.entry()->fContent.writeText(encodedString.c_str());
   1176         consumedGlyphCount += availableGlyphs;
   1177         content.entry()->fContent.writeText(" Tj\n");
   1178     }
   1179     content.entry()->fContent.writeText("ET\n");
   1180 }
   1181 
   1182 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
   1183                               const SkScalar pos[], int scalarsPerPos,
   1184                               const SkPoint& offset, const SkPaint& srcPaint) {
   1185     SkPaint paint = srcPaint;
   1186     replace_srcmode_on_opaque_paint(&paint);
   1187 
   1188     NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
   1189     if (paint.getMaskFilter() != NULL) {
   1190         // Don't pretend we support drawing MaskFilters, it makes for artifacts
   1191         // making text unreadable (e.g. same text twice when using CSS shadows).
   1192         return;
   1193     }
   1194     SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
   1195     SkPaint textPaint = calculate_text_paint(paint);
   1196     ScopedContentEntry content(this, d, textPaint, true);
   1197     if (!content.entry()) {
   1198         return;
   1199     }
   1200 
   1201     SkGlyphStorage storage(0);
   1202     const uint16_t* glyphIDs = NULL;
   1203     size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs);
   1204     textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
   1205 
   1206     SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
   1207     content.entry()->fContent.writeText("BT\n");
   1208     updateFont(textPaint, glyphIDs[0], content.entry());
   1209     for (size_t i = 0; i < numGlyphs; i++) {
   1210         SkPDFFont* font = content.entry()->fState.fFont;
   1211         uint16_t encodedValue = glyphIDs[i];
   1212         if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
   1213             // The current pdf font cannot encode the current glyph.
   1214             // Try to get a pdf font which can encode the current glyph.
   1215             updateFont(textPaint, glyphIDs[i], content.entry());
   1216             font = content.entry()->fState.fFont;
   1217             if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
   1218                 SkDEBUGFAIL("PDF could not encode glyph.");
   1219                 continue;
   1220             }
   1221         }
   1222 
   1223         fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1);
   1224         SkScalar x = offset.x() + pos[i * scalarsPerPos];
   1225         SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[i * scalarsPerPos + 1] : 0);
   1226 
   1227         align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y);
   1228         set_text_transform(x, y, textPaint.getTextSkewX(), &content.entry()->fContent);
   1229         SkString encodedString =
   1230                 format_wide_string(&encodedValue, 1, font->multiByteGlyphs());
   1231         content.entry()->fContent.writeText(encodedString.c_str());
   1232         content.entry()->fContent.writeText(" Tj\n");
   1233     }
   1234     content.entry()->fContent.writeText("ET\n");
   1235 }
   1236 
   1237 void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode,
   1238                                int vertexCount, const SkPoint verts[],
   1239                                const SkPoint texs[], const SkColor colors[],
   1240                                SkXfermode* xmode, const uint16_t indices[],
   1241                                int indexCount, const SkPaint& paint) {
   1242     if (d.fClip->isEmpty()) {
   1243         return;
   1244     }
   1245     // TODO: implement drawVertices
   1246 }
   1247 
   1248 void SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device,
   1249                              int x, int y, const SkPaint& paint) {
   1250     // our onCreateCompatibleDevice() always creates SkPDFDevice subclasses.
   1251     SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device);
   1252     if (pdfDevice->isContentEmpty()) {
   1253         return;
   1254     }
   1255 
   1256     SkMatrix matrix;
   1257     matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
   1258     ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
   1259     if (!content.entry()) {
   1260         return;
   1261     }
   1262     if (content.needShape()) {
   1263         SkPath shape;
   1264         shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
   1265                                        SkIntToScalar(device->width()),
   1266                                        SkIntToScalar(device->height())));
   1267         content.setShape(shape);
   1268     }
   1269     if (!content.needSource()) {
   1270         return;
   1271     }
   1272 
   1273     SkAutoTUnref<SkPDFFormXObject> xObject(new SkPDFFormXObject(pdfDevice));
   1274     SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()),
   1275                                 &content.entry()->fContent);
   1276 
   1277     // Merge glyph sets from the drawn device.
   1278     fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage());
   1279 }
   1280 
   1281 SkImageInfo SkPDFDevice::imageInfo() const {
   1282     return fLegacyBitmap.info();
   1283 }
   1284 
   1285 void SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) {
   1286     INHERITED::onAttachToCanvas(canvas);
   1287 
   1288     // Canvas promises that this ptr is valid until onDetachFromCanvas is called
   1289     fClipStack = canvas->getClipStack();
   1290 }
   1291 
   1292 void SkPDFDevice::onDetachFromCanvas() {
   1293     INHERITED::onDetachFromCanvas();
   1294 
   1295     fClipStack = NULL;
   1296 }
   1297 
   1298 SkSurface* SkPDFDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
   1299     return SkSurface::NewRaster(info, &props);
   1300 }
   1301 
   1302 ContentEntry* SkPDFDevice::getLastContentEntry() {
   1303     if (fDrawingArea == kContent_DrawingArea) {
   1304         return fLastContentEntry;
   1305     } else {
   1306         return fLastMarginContentEntry;
   1307     }
   1308 }
   1309 
   1310 SkAutoTDelete<ContentEntry>* SkPDFDevice::getContentEntries() {
   1311     if (fDrawingArea == kContent_DrawingArea) {
   1312         return &fContentEntries;
   1313     } else {
   1314         return &fMarginContentEntries;
   1315     }
   1316 }
   1317 
   1318 void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) {
   1319     if (fDrawingArea == kContent_DrawingArea) {
   1320         fLastContentEntry = contentEntry;
   1321     } else {
   1322         fLastMarginContentEntry = contentEntry;
   1323     }
   1324 }
   1325 
   1326 void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) {
   1327     // A ScopedContentEntry only exists during the course of a draw call, so
   1328     // this can't be called while a ScopedContentEntry exists.
   1329     fDrawingArea = drawingArea;
   1330 }
   1331 
   1332 SkPDFDict* SkPDFDevice::createResourceDict() const {
   1333     SkTDArray<SkPDFObject*> fonts;
   1334     fonts.setReserve(fFontResources.count());
   1335     for (SkPDFFont* font : fFontResources) {
   1336         fonts.push(font);
   1337     }
   1338     return SkPDFResourceDict::Create(
   1339             &fGraphicStateResources,
   1340             &fShaderResources,
   1341             &fXObjectResources,
   1342             &fonts);
   1343 }
   1344 
   1345 const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const {
   1346     return fFontResources;
   1347 }
   1348 
   1349 SkPDFArray* SkPDFDevice::copyMediaBox() const {
   1350     // should this be a singleton?
   1351 
   1352     SkAutoTUnref<SkPDFArray> mediaBox(SkNEW(SkPDFArray));
   1353     mediaBox->reserve(4);
   1354     mediaBox->appendInt(0);
   1355     mediaBox->appendInt(0);
   1356     mediaBox->appendInt(fPageSize.fWidth);
   1357     mediaBox->appendInt(fPageSize.fHeight);
   1358     return mediaBox.detach();
   1359 }
   1360 
   1361 SkStreamAsset* SkPDFDevice::content() const {
   1362     SkDynamicMemoryWStream buffer;
   1363     this->writeContent(&buffer);
   1364     return buffer.detachAsStream();
   1365 }
   1366 
   1367 void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry,
   1368         SkWStream* data) const {
   1369     // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the
   1370     // right thing to pass here.
   1371     GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data);
   1372     while (entry != NULL) {
   1373         SkPoint translation;
   1374         translation.iset(this->getOrigin());
   1375         translation.negate();
   1376         gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
   1377                            translation);
   1378         gsState.updateMatrix(entry->fState.fMatrix);
   1379         gsState.updateDrawingState(entry->fState);
   1380 
   1381         entry->fContent.writeToStream(data);
   1382         entry = entry->fNext.get();
   1383     }
   1384     gsState.drainStack();
   1385 }
   1386 
   1387 void SkPDFDevice::writeContent(SkWStream* out) const {
   1388     if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
   1389         SkPDFUtils::AppendTransform(fInitialTransform, out);
   1390     }
   1391 
   1392     // TODO(aayushkumar): Apply clip along the margins.  Currently, webkit
   1393     // colors the contentArea white before it starts drawing into it and
   1394     // that currently acts as our clip.
   1395     // Also, think about adding a transform here (or assume that the values
   1396     // sent across account for that)
   1397     SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), out);
   1398 
   1399     // If the content area is the entire page, then we don't need to clip
   1400     // the content area (PDF area clips to the page size).  Otherwise,
   1401     // we have to clip to the content area; we've already applied the
   1402     // initial transform, so just clip to the device size.
   1403     if (fPageSize != fContentSize) {
   1404         SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()),
   1405                                   SkIntToScalar(this->height()));
   1406         emit_clip(NULL, &r, out);
   1407     }
   1408 
   1409     SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), out);
   1410 }
   1411 
   1412 /* Draws an inverse filled path by using Path Ops to compute the positive
   1413  * inverse using the current clip as the inverse bounds.
   1414  * Return true if this was an inverse path and was properly handled,
   1415  * otherwise returns false and the normal drawing routine should continue,
   1416  * either as a (incorrect) fallback or because the path was not inverse
   1417  * in the first place.
   1418  */
   1419 bool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath,
   1420                                     const SkPaint& paint, bool pathIsMutable,
   1421                                     const SkMatrix* prePathMatrix) {
   1422     if (!origPath.isInverseFillType()) {
   1423         return false;
   1424     }
   1425 
   1426     if (d.fClip->isEmpty()) {
   1427         return false;
   1428     }
   1429 
   1430     SkPath modifiedPath;
   1431     SkPath* pathPtr = const_cast<SkPath*>(&origPath);
   1432     SkPaint noInversePaint(paint);
   1433 
   1434     // Merge stroking operations into final path.
   1435     if (SkPaint::kStroke_Style == paint.getStyle() ||
   1436         SkPaint::kStrokeAndFill_Style == paint.getStyle()) {
   1437         bool doFillPath = paint.getFillPath(origPath, &modifiedPath);
   1438         if (doFillPath) {
   1439             noInversePaint.setStyle(SkPaint::kFill_Style);
   1440             noInversePaint.setStrokeWidth(0);
   1441             pathPtr = &modifiedPath;
   1442         } else {
   1443             // To be consistent with the raster output, hairline strokes
   1444             // are rendered as non-inverted.
   1445             modifiedPath.toggleInverseFillType();
   1446             drawPath(d, modifiedPath, paint, NULL, true);
   1447             return true;
   1448         }
   1449     }
   1450 
   1451     // Get bounds of clip in current transform space
   1452     // (clip bounds are given in device space).
   1453     SkRect bounds;
   1454     SkMatrix transformInverse;
   1455     SkMatrix totalMatrix = *d.fMatrix;
   1456     if (prePathMatrix) {
   1457         totalMatrix.preConcat(*prePathMatrix);
   1458     }
   1459     if (!totalMatrix.invert(&transformInverse)) {
   1460         return false;
   1461     }
   1462     bounds.set(d.fClip->getBounds());
   1463     transformInverse.mapRect(&bounds);
   1464 
   1465     // Extend the bounds by the line width (plus some padding)
   1466     // so the edge doesn't cause a visible stroke.
   1467     bounds.outset(paint.getStrokeWidth() + SK_Scalar1,
   1468                   paint.getStrokeWidth() + SK_Scalar1);
   1469 
   1470     if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) {
   1471         return false;
   1472     }
   1473 
   1474     drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true);
   1475     return true;
   1476 }
   1477 
   1478 bool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix,
   1479                                        const SkPaint& p) {
   1480     SkAnnotation* annotationInfo = p.getAnnotation();
   1481     if (!annotationInfo) {
   1482         return false;
   1483     }
   1484     SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key());
   1485     if (urlData) {
   1486         handleLinkToURL(urlData, r, matrix);
   1487         return p.getAnnotation() != NULL;
   1488     }
   1489     SkData* linkToName = annotationInfo->find(
   1490             SkAnnotationKeys::Link_Named_Dest_Key());
   1491     if (linkToName) {
   1492         handleLinkToNamedDest(linkToName, r, matrix);
   1493         return p.getAnnotation() != NULL;
   1494     }
   1495     return false;
   1496 }
   1497 
   1498 bool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count,
   1499                                         const SkMatrix& matrix,
   1500                                         const SkPaint& paint) {
   1501     SkAnnotation* annotationInfo = paint.getAnnotation();
   1502     if (!annotationInfo) {
   1503         return false;
   1504     }
   1505     SkData* nameData = annotationInfo->find(
   1506             SkAnnotationKeys::Define_Named_Dest_Key());
   1507     if (nameData) {
   1508         for (size_t i = 0; i < count; i++) {
   1509             defineNamedDestination(nameData, points[i], matrix);
   1510         }
   1511         return paint.getAnnotation() != NULL;
   1512     }
   1513     return false;
   1514 }
   1515 
   1516 void SkPDFDevice::addAnnotation(SkPDFDict* annotation) {
   1517     if (NULL == fAnnotations) {
   1518         fAnnotations = SkNEW(SkPDFArray);
   1519     }
   1520     fAnnotations->appendObject(annotation);
   1521 }
   1522 
   1523 static SkPDFDict* create_link_annotation(const SkRect& r,
   1524                                          const SkMatrix& initialTransform,
   1525                                          const SkMatrix& matrix) {
   1526     SkMatrix transform = matrix;
   1527     transform.postConcat(initialTransform);
   1528     SkRect translatedRect;
   1529     transform.mapRect(&translatedRect, r);
   1530 
   1531     SkAutoTUnref<SkPDFDict> annotation(SkNEW_ARGS(SkPDFDict, ("Annot")));
   1532     annotation->insertName("Subtype", "Link");
   1533 
   1534     SkAutoTUnref<SkPDFArray> border(SkNEW(SkPDFArray));
   1535     border->reserve(3);
   1536     border->appendInt(0);  // Horizontal corner radius.
   1537     border->appendInt(0);  // Vertical corner radius.
   1538     border->appendInt(0);  // Width, 0 = no border.
   1539     annotation->insertObject("Border", border.detach());
   1540 
   1541     SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray));
   1542     rect->reserve(4);
   1543     rect->appendScalar(translatedRect.fLeft);
   1544     rect->appendScalar(translatedRect.fTop);
   1545     rect->appendScalar(translatedRect.fRight);
   1546     rect->appendScalar(translatedRect.fBottom);
   1547     annotation->insertObject("Rect", rect.detach());
   1548 
   1549     return annotation.detach();
   1550 }
   1551 
   1552 void SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r,
   1553                                   const SkMatrix& matrix) {
   1554     SkAutoTUnref<SkPDFDict> annotation(
   1555             create_link_annotation(r, fInitialTransform, matrix));
   1556 
   1557     SkString url(static_cast<const char *>(urlData->data()),
   1558                  urlData->size() - 1);
   1559     SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action")));
   1560     action->insertName("S", "URI");
   1561     action->insertString("URI", url);
   1562     annotation->insertObject("A", action.detach());
   1563     this->addAnnotation(annotation.detach());
   1564 }
   1565 
   1566 void SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r,
   1567                                         const SkMatrix& matrix) {
   1568     SkAutoTUnref<SkPDFDict> annotation(
   1569             create_link_annotation(r, fInitialTransform, matrix));
   1570     SkString name(static_cast<const char *>(nameData->data()),
   1571                   nameData->size() - 1);
   1572     annotation->insertName("Dest", name);
   1573     this->addAnnotation(annotation.detach());
   1574 }
   1575 
   1576 struct NamedDestination {
   1577     const SkData* nameData;
   1578     SkPoint point;
   1579 
   1580     NamedDestination(const SkData* nameData, const SkPoint& point)
   1581         : nameData(SkRef(nameData)), point(point) {}
   1582 
   1583     ~NamedDestination() {
   1584         nameData->unref();
   1585     }
   1586 };
   1587 
   1588 void SkPDFDevice::defineNamedDestination(SkData* nameData, const SkPoint& point,
   1589                                          const SkMatrix& matrix) {
   1590     SkMatrix transform = matrix;
   1591     transform.postConcat(fInitialTransform);
   1592     SkPoint translatedPoint;
   1593     transform.mapXY(point.x(), point.y(), &translatedPoint);
   1594     fNamedDestinations.push(
   1595         SkNEW_ARGS(NamedDestination, (nameData, translatedPoint)));
   1596 }
   1597 
   1598 void SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) const {
   1599     int nDest = fNamedDestinations.count();
   1600     for (int i = 0; i < nDest; i++) {
   1601         NamedDestination* dest = fNamedDestinations[i];
   1602         SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray));
   1603         pdfDest->reserve(5);
   1604         pdfDest->appendObjRef(SkRef(page));
   1605         pdfDest->appendName("XYZ");
   1606         pdfDest->appendScalar(dest->point.x());
   1607         pdfDest->appendScalar(dest->point.y());
   1608         pdfDest->appendInt(0);  // Leave zoom unchanged
   1609         SkString name(static_cast<const char*>(dest->nameData->data()));
   1610         dict->insertObject(name, pdfDest.detach());
   1611     }
   1612 }
   1613 
   1614 SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() {
   1615     SkPDFFormXObject* xobject = SkNEW_ARGS(SkPDFFormXObject, (this));
   1616     // We always draw the form xobjects that we create back into the device, so
   1617     // we simply preserve the font usage instead of pulling it out and merging
   1618     // it back in later.
   1619     cleanUp(false);  // Reset this device to have no content.
   1620     init();
   1621     return xobject;
   1622 }
   1623 
   1624 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex,
   1625                                           SkPDFFormXObject* mask,
   1626                                           const SkClipStack* clipStack,
   1627                                           const SkRegion& clipRegion,
   1628                                           SkXfermode::Mode mode,
   1629                                           bool invertClip) {
   1630     if (clipRegion.isEmpty() && !invertClip) {
   1631         return;
   1632     }
   1633 
   1634     SkAutoTUnref<SkPDFObject> sMaskGS(SkPDFGraphicState::GetSMaskGraphicState(
   1635             mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode));
   1636 
   1637     SkMatrix identity;
   1638     identity.reset();
   1639     SkPaint paint;
   1640     paint.setXfermodeMode(mode);
   1641     ScopedContentEntry content(this, clipStack, clipRegion, identity, paint);
   1642     if (!content.entry()) {
   1643         return;
   1644     }
   1645     SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
   1646                                   &content.entry()->fContent);
   1647     SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent);
   1648 
   1649     sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState());
   1650     SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
   1651                                   &content.entry()->fContent);
   1652 }
   1653 
   1654 ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
   1655                                              const SkRegion& clipRegion,
   1656                                              const SkMatrix& matrix,
   1657                                              const SkPaint& paint,
   1658                                              bool hasText,
   1659                                              SkPDFFormXObject** dst) {
   1660     *dst = NULL;
   1661     if (clipRegion.isEmpty()) {
   1662         return NULL;
   1663     }
   1664 
   1665     // The clip stack can come from an SkDraw where it is technically optional.
   1666     SkClipStack synthesizedClipStack;
   1667     if (clipStack == NULL) {
   1668         if (clipRegion == fExistingClipRegion) {
   1669             clipStack = &fExistingClipStack;
   1670         } else {
   1671             // GraphicStackState::updateClip expects the clip stack to have
   1672             // fExistingClip as a prefix, so start there, then set the clip
   1673             // to the passed region.
   1674             synthesizedClipStack = fExistingClipStack;
   1675             SkPath clipPath;
   1676             clipRegion.getBoundaryPath(&clipPath);
   1677             synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op,
   1678                                              false);
   1679             clipStack = &synthesizedClipStack;
   1680         }
   1681     }
   1682 
   1683     SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
   1684     if (paint.getXfermode()) {
   1685         paint.getXfermode()->asMode(&xfermode);
   1686     }
   1687 
   1688     // For the following modes, we want to handle source and destination
   1689     // separately, so make an object of what's already there.
   1690     if (xfermode == SkXfermode::kClear_Mode       ||
   1691             xfermode == SkXfermode::kSrc_Mode     ||
   1692             xfermode == SkXfermode::kSrcIn_Mode   ||
   1693             xfermode == SkXfermode::kDstIn_Mode   ||
   1694             xfermode == SkXfermode::kSrcOut_Mode  ||
   1695             xfermode == SkXfermode::kDstOut_Mode  ||
   1696             xfermode == SkXfermode::kSrcATop_Mode ||
   1697             xfermode == SkXfermode::kDstATop_Mode ||
   1698             xfermode == SkXfermode::kModulate_Mode) {
   1699         if (!isContentEmpty()) {
   1700             *dst = createFormXObjectFromDevice();
   1701             SkASSERT(isContentEmpty());
   1702         } else if (xfermode != SkXfermode::kSrc_Mode &&
   1703                    xfermode != SkXfermode::kSrcOut_Mode) {
   1704             // Except for Src and SrcOut, if there isn't anything already there,
   1705             // then we're done.
   1706             return NULL;
   1707         }
   1708     }
   1709     // TODO(vandebo): Figure out how/if we can handle the following modes:
   1710     // Xor, Plus.
   1711 
   1712     // Dst xfer mode doesn't draw source at all.
   1713     if (xfermode == SkXfermode::kDst_Mode) {
   1714         return NULL;
   1715     }
   1716 
   1717     ContentEntry* entry;
   1718     SkAutoTDelete<ContentEntry> newEntry;
   1719 
   1720     ContentEntry* lastContentEntry = getLastContentEntry();
   1721     if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) {
   1722         entry = lastContentEntry;
   1723     } else {
   1724         newEntry.reset(new ContentEntry);
   1725         entry = newEntry.get();
   1726     }
   1727 
   1728     populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
   1729                                        hasText, &entry->fState);
   1730     if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
   1731             entry->fState.compareInitialState(lastContentEntry->fState)) {
   1732         return lastContentEntry;
   1733     }
   1734 
   1735     SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries();
   1736     if (!lastContentEntry) {
   1737         contentEntries->reset(entry);
   1738         setLastContentEntry(entry);
   1739     } else if (xfermode == SkXfermode::kDstOver_Mode) {
   1740         entry->fNext.reset(contentEntries->detach());
   1741         contentEntries->reset(entry);
   1742     } else {
   1743         lastContentEntry->fNext.reset(entry);
   1744         setLastContentEntry(entry);
   1745     }
   1746     newEntry.detach();
   1747     return entry;
   1748 }
   1749 
   1750 void SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
   1751                                      SkPDFFormXObject* dst,
   1752                                      SkPath* shape) {
   1753     if (xfermode != SkXfermode::kClear_Mode       &&
   1754             xfermode != SkXfermode::kSrc_Mode     &&
   1755             xfermode != SkXfermode::kDstOver_Mode &&
   1756             xfermode != SkXfermode::kSrcIn_Mode   &&
   1757             xfermode != SkXfermode::kDstIn_Mode   &&
   1758             xfermode != SkXfermode::kSrcOut_Mode  &&
   1759             xfermode != SkXfermode::kDstOut_Mode  &&
   1760             xfermode != SkXfermode::kSrcATop_Mode &&
   1761             xfermode != SkXfermode::kDstATop_Mode &&
   1762             xfermode != SkXfermode::kModulate_Mode) {
   1763         SkASSERT(!dst);
   1764         return;
   1765     }
   1766     if (xfermode == SkXfermode::kDstOver_Mode) {
   1767         SkASSERT(!dst);
   1768         ContentEntry* firstContentEntry = getContentEntries()->get();
   1769         if (firstContentEntry->fContent.getOffset() == 0) {
   1770             // For DstOver, an empty content entry was inserted before the rest
   1771             // of the content entries. If nothing was drawn, it needs to be
   1772             // removed.
   1773             SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries();
   1774             contentEntries->reset(firstContentEntry->fNext.detach());
   1775         }
   1776         return;
   1777     }
   1778     if (!dst) {
   1779         SkASSERT(xfermode == SkXfermode::kSrc_Mode ||
   1780                  xfermode == SkXfermode::kSrcOut_Mode);
   1781         return;
   1782     }
   1783 
   1784     ContentEntry* contentEntries = getContentEntries()->get();
   1785     SkASSERT(dst);
   1786     SkASSERT(!contentEntries->fNext.get());
   1787     // Changing the current content into a form-xobject will destroy the clip
   1788     // objects which is fine since the xobject will already be clipped. However
   1789     // if source has shape, we need to clip it too, so a copy of the clip is
   1790     // saved.
   1791     SkClipStack clipStack = contentEntries->fState.fClipStack;
   1792     SkRegion clipRegion = contentEntries->fState.fClipRegion;
   1793 
   1794     SkMatrix identity;
   1795     identity.reset();
   1796     SkPaint stockPaint;
   1797 
   1798     SkAutoTUnref<SkPDFFormXObject> srcFormXObject;
   1799     if (isContentEmpty()) {
   1800         // If nothing was drawn and there's no shape, then the draw was a
   1801         // no-op, but dst needs to be restored for that to be true.
   1802         // If there is shape, then an empty source with Src, SrcIn, SrcOut,
   1803         // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop
   1804         // reduces to Dst.
   1805         if (shape == NULL || xfermode == SkXfermode::kDstOut_Mode ||
   1806                 xfermode == SkXfermode::kSrcATop_Mode) {
   1807             ScopedContentEntry content(this, &fExistingClipStack,
   1808                                        fExistingClipRegion, identity,
   1809                                        stockPaint);
   1810             SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
   1811                                         &content.entry()->fContent);
   1812             return;
   1813         } else {
   1814             xfermode = SkXfermode::kClear_Mode;
   1815         }
   1816     } else {
   1817         SkASSERT(!fContentEntries->fNext.get());
   1818         srcFormXObject.reset(createFormXObjectFromDevice());
   1819     }
   1820 
   1821     // TODO(vandebo) srcFormXObject may contain alpha, but here we want it
   1822     // without alpha.
   1823     if (xfermode == SkXfermode::kSrcATop_Mode) {
   1824         // TODO(vandebo): In order to properly support SrcATop we have to track
   1825         // the shape of what's been drawn at all times. It's the intersection of
   1826         // the non-transparent parts of the device and the outlines (shape) of
   1827         // all images and devices drawn.
   1828         drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
   1829                                 &fExistingClipStack, fExistingClipRegion,
   1830                                 SkXfermode::kSrcOver_Mode, true);
   1831     } else {
   1832         SkAutoTUnref<SkPDFFormXObject> dstMaskStorage;
   1833         SkPDFFormXObject* dstMask = srcFormXObject.get();
   1834         if (shape != NULL) {
   1835             // Draw shape into a form-xobject.
   1836             SkDraw d;
   1837             d.fMatrix = &identity;
   1838             d.fClip = &clipRegion;
   1839             d.fClipStack = &clipStack;
   1840             SkPaint filledPaint;
   1841             filledPaint.setColor(SK_ColorBLACK);
   1842             filledPaint.setStyle(SkPaint::kFill_Style);
   1843             this->drawPath(d, *shape, filledPaint, NULL, true);
   1844 
   1845             dstMaskStorage.reset(createFormXObjectFromDevice());
   1846             dstMask = dstMaskStorage.get();
   1847         }
   1848         drawFormXObjectWithMask(addXObjectResource(dst), dstMask,
   1849                                 &fExistingClipStack, fExistingClipRegion,
   1850                                 SkXfermode::kSrcOver_Mode, true);
   1851     }
   1852 
   1853     if (xfermode == SkXfermode::kClear_Mode) {
   1854         return;
   1855     } else if (xfermode == SkXfermode::kSrc_Mode ||
   1856             xfermode == SkXfermode::kDstATop_Mode) {
   1857         ScopedContentEntry content(this, &fExistingClipStack,
   1858                                    fExistingClipRegion, identity, stockPaint);
   1859         if (content.entry()) {
   1860             SkPDFUtils::DrawFormXObject(
   1861                     this->addXObjectResource(srcFormXObject.get()),
   1862                     &content.entry()->fContent);
   1863         }
   1864         if (xfermode == SkXfermode::kSrc_Mode) {
   1865             return;
   1866         }
   1867     } else if (xfermode == SkXfermode::kSrcATop_Mode) {
   1868         ScopedContentEntry content(this, &fExistingClipStack,
   1869                                    fExistingClipRegion, identity, stockPaint);
   1870         if (content.entry()) {
   1871             SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
   1872                                         &content.entry()->fContent);
   1873         }
   1874     }
   1875 
   1876     SkASSERT(xfermode == SkXfermode::kSrcIn_Mode   ||
   1877              xfermode == SkXfermode::kDstIn_Mode   ||
   1878              xfermode == SkXfermode::kSrcOut_Mode  ||
   1879              xfermode == SkXfermode::kDstOut_Mode  ||
   1880              xfermode == SkXfermode::kSrcATop_Mode ||
   1881              xfermode == SkXfermode::kDstATop_Mode ||
   1882              xfermode == SkXfermode::kModulate_Mode);
   1883 
   1884     if (xfermode == SkXfermode::kSrcIn_Mode ||
   1885             xfermode == SkXfermode::kSrcOut_Mode ||
   1886             xfermode == SkXfermode::kSrcATop_Mode) {
   1887         drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
   1888                                 &fExistingClipStack, fExistingClipRegion,
   1889                                 SkXfermode::kSrcOver_Mode,
   1890                                 xfermode == SkXfermode::kSrcOut_Mode);
   1891     } else {
   1892         SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
   1893         if (xfermode == SkXfermode::kModulate_Mode) {
   1894             drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
   1895                                     dst, &fExistingClipStack,
   1896                                     fExistingClipRegion,
   1897                                     SkXfermode::kSrcOver_Mode, false);
   1898             mode = SkXfermode::kMultiply_Mode;
   1899         }
   1900         drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(),
   1901                                 &fExistingClipStack, fExistingClipRegion, mode,
   1902                                 xfermode == SkXfermode::kDstOut_Mode);
   1903     }
   1904 }
   1905 
   1906 bool SkPDFDevice::isContentEmpty() {
   1907     ContentEntry* contentEntries = getContentEntries()->get();
   1908     if (!contentEntries || contentEntries->fContent.getOffset() == 0) {
   1909         SkASSERT(!contentEntries || !contentEntries->fNext.get());
   1910         return true;
   1911     }
   1912     return false;
   1913 }
   1914 
   1915 void SkPDFDevice::populateGraphicStateEntryFromPaint(
   1916         const SkMatrix& matrix,
   1917         const SkClipStack& clipStack,
   1918         const SkRegion& clipRegion,
   1919         const SkPaint& paint,
   1920         bool hasText,
   1921         GraphicStateEntry* entry) {
   1922     NOT_IMPLEMENTED(paint.getPathEffect() != NULL, false);
   1923     NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
   1924     NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false);
   1925 
   1926     entry->fMatrix = matrix;
   1927     entry->fClipStack = clipStack;
   1928     entry->fClipRegion = clipRegion;
   1929     entry->fColor = SkColorSetA(paint.getColor(), 0xFF);
   1930     entry->fShaderIndex = -1;
   1931 
   1932     // PDF treats a shader as a color, so we only set one or the other.
   1933     SkAutoTUnref<SkPDFObject> pdfShader;
   1934     const SkShader* shader = paint.getShader();
   1935     SkColor color = paint.getColor();
   1936     if (shader) {
   1937         // PDF positions patterns relative to the initial transform, so
   1938         // we need to apply the current transform to the shader parameters.
   1939         SkMatrix transform = matrix;
   1940         transform.postConcat(fInitialTransform);
   1941 
   1942         // PDF doesn't support kClamp_TileMode, so we simulate it by making
   1943         // a pattern the size of the current clip.
   1944         SkIRect bounds = clipRegion.getBounds();
   1945 
   1946         // We need to apply the initial transform to bounds in order to get
   1947         // bounds in a consistent coordinate system.
   1948         SkRect boundsTemp;
   1949         boundsTemp.set(bounds);
   1950         fInitialTransform.mapRect(&boundsTemp);
   1951         boundsTemp.roundOut(&bounds);
   1952 
   1953         SkScalar rasterScale =
   1954                 SkIntToScalar(fRasterDpi) / DPI_FOR_RASTER_SCALE_ONE;
   1955         pdfShader.reset(SkPDFShader::GetPDFShader(
   1956                 fCanon, fRasterDpi, *shader, transform, bounds, rasterScale));
   1957 
   1958         if (pdfShader.get()) {
   1959             // pdfShader has been canonicalized so we can directly compare
   1960             // pointers.
   1961             int resourceIndex = fShaderResources.find(pdfShader.get());
   1962             if (resourceIndex < 0) {
   1963                 resourceIndex = fShaderResources.count();
   1964                 fShaderResources.push(pdfShader.get());
   1965                 pdfShader.get()->ref();
   1966             }
   1967             entry->fShaderIndex = resourceIndex;
   1968         } else {
   1969             // A color shader is treated as an invalid shader so we don't have
   1970             // to set a shader just for a color.
   1971             SkShader::GradientInfo gradientInfo;
   1972             SkColor gradientColor;
   1973             gradientInfo.fColors = &gradientColor;
   1974             gradientInfo.fColorOffsets = NULL;
   1975             gradientInfo.fColorCount = 1;
   1976             if (shader->asAGradient(&gradientInfo) ==
   1977                     SkShader::kColor_GradientType) {
   1978                 entry->fColor = SkColorSetA(gradientColor, 0xFF);
   1979                 color = gradientColor;
   1980             }
   1981         }
   1982     }
   1983 
   1984     SkAutoTUnref<SkPDFGraphicState> newGraphicState;
   1985     if (color == paint.getColor()) {
   1986         newGraphicState.reset(
   1987                 SkPDFGraphicState::GetGraphicStateForPaint(fCanon, paint));
   1988     } else {
   1989         SkPaint newPaint = paint;
   1990         newPaint.setColor(color);
   1991         newGraphicState.reset(
   1992                 SkPDFGraphicState::GetGraphicStateForPaint(fCanon, newPaint));
   1993     }
   1994     int resourceIndex = addGraphicStateResource(newGraphicState.get());
   1995     entry->fGraphicStateIndex = resourceIndex;
   1996 
   1997     if (hasText) {
   1998         entry->fTextScaleX = paint.getTextScaleX();
   1999         entry->fTextFill = paint.getStyle();
   2000     } else {
   2001         entry->fTextScaleX = 0;
   2002     }
   2003 }
   2004 
   2005 int SkPDFDevice::addGraphicStateResource(SkPDFObject* gs) {
   2006     // Assumes that gs has been canonicalized (so we can directly compare
   2007     // pointers).
   2008     int result = fGraphicStateResources.find(gs);
   2009     if (result < 0) {
   2010         result = fGraphicStateResources.count();
   2011         fGraphicStateResources.push(gs);
   2012         gs->ref();
   2013     }
   2014     return result;
   2015 }
   2016 
   2017 int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) {
   2018     // Assumes that xobject has been canonicalized (so we can directly compare
   2019     // pointers).
   2020     int result = fXObjectResources.find(xObject);
   2021     if (result < 0) {
   2022         result = fXObjectResources.count();
   2023         fXObjectResources.push(xObject);
   2024         xObject->ref();
   2025     }
   2026     return result;
   2027 }
   2028 
   2029 void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
   2030                              ContentEntry* contentEntry) {
   2031     SkTypeface* typeface = paint.getTypeface();
   2032     if (contentEntry->fState.fFont == NULL ||
   2033             contentEntry->fState.fTextSize != paint.getTextSize() ||
   2034             !contentEntry->fState.fFont->hasGlyph(glyphID)) {
   2035         int fontIndex = getFontResourceIndex(typeface, glyphID);
   2036         contentEntry->fContent.writeText("/");
   2037         contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
   2038                 SkPDFResourceDict::kFont_ResourceType,
   2039                 fontIndex).c_str());
   2040         contentEntry->fContent.writeText(" ");
   2041         SkPDFUtils::AppendScalar(paint.getTextSize(), &contentEntry->fContent);
   2042         contentEntry->fContent.writeText(" Tf\n");
   2043         contentEntry->fState.fFont = fFontResources[fontIndex];
   2044     }
   2045 }
   2046 
   2047 int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
   2048     SkAutoTUnref<SkPDFFont> newFont(
   2049             SkPDFFont::GetFontResource(fCanon, typeface, glyphID));
   2050     int resourceIndex = fFontResources.find(newFont.get());
   2051     if (resourceIndex < 0) {
   2052         resourceIndex = fFontResources.count();
   2053         fFontResources.push(newFont.get());
   2054         newFont.get()->ref();
   2055     }
   2056     return resourceIndex;
   2057 }
   2058 
   2059 void SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix,
   2060                                      const SkClipStack* clipStack,
   2061                                      const SkRegion& origClipRegion,
   2062                                      const SkBitmap& origBitmap,
   2063                                      const SkIRect* srcRect,
   2064                                      const SkPaint& paint) {
   2065     SkMatrix matrix = origMatrix;
   2066     SkRegion perspectiveBounds;
   2067     const SkRegion* clipRegion = &origClipRegion;
   2068     SkBitmap perspectiveBitmap;
   2069     const SkBitmap* bitmap = &origBitmap;
   2070     SkBitmap tmpSubsetBitmap;
   2071 
   2072     // Rasterize the bitmap using perspective in a new bitmap.
   2073     if (origMatrix.hasPerspective()) {
   2074         if (fRasterDpi == 0) {
   2075             return;
   2076         }
   2077         SkBitmap* subsetBitmap;
   2078         if (srcRect) {
   2079             if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) {
   2080                return;
   2081             }
   2082             subsetBitmap = &tmpSubsetBitmap;
   2083         } else {
   2084             subsetBitmap = &tmpSubsetBitmap;
   2085             *subsetBitmap = origBitmap;
   2086         }
   2087         srcRect = NULL;
   2088 
   2089         // Transform the bitmap in the new space, without taking into
   2090         // account the initial transform.
   2091         SkPath perspectiveOutline;
   2092         perspectiveOutline.addRect(
   2093                 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()),
   2094                                SkIntToScalar(subsetBitmap->height())));
   2095         perspectiveOutline.transform(origMatrix);
   2096 
   2097         // TODO(edisonn): perf - use current clip too.
   2098         // Retrieve the bounds of the new shape.
   2099         SkRect bounds = perspectiveOutline.getBounds();
   2100 
   2101         // Transform the bitmap in the new space, taking into
   2102         // account the initial transform.
   2103         SkMatrix total = origMatrix;
   2104         total.postConcat(fInitialTransform);
   2105         total.postScale(SkIntToScalar(fRasterDpi) /
   2106                             SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE),
   2107                         SkIntToScalar(fRasterDpi) /
   2108                             SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE));
   2109         SkPath physicalPerspectiveOutline;
   2110         physicalPerspectiveOutline.addRect(
   2111                 SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()),
   2112                                SkIntToScalar(subsetBitmap->height())));
   2113         physicalPerspectiveOutline.transform(total);
   2114 
   2115         SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() /
   2116                               bounds.width();
   2117         SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() /
   2118                               bounds.height();
   2119 
   2120         // TODO(edisonn): A better approach would be to use a bitmap shader
   2121         // (in clamp mode) and draw a rect over the entire bounding box. Then
   2122         // intersect perspectiveOutline to the clip. That will avoid introducing
   2123         // alpha to the image while still giving good behavior at the edge of
   2124         // the image.  Avoiding alpha will reduce the pdf size and generation
   2125         // CPU time some.
   2126 
   2127         const int w = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().width());
   2128         const int h = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().height());
   2129         if (!perspectiveBitmap.tryAllocN32Pixels(w, h)) {
   2130             return;
   2131         }
   2132         perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT);
   2133 
   2134         SkCanvas canvas(perspectiveBitmap);
   2135 
   2136         SkScalar deltaX = bounds.left();
   2137         SkScalar deltaY = bounds.top();
   2138 
   2139         SkMatrix offsetMatrix = origMatrix;
   2140         offsetMatrix.postTranslate(-deltaX, -deltaY);
   2141         offsetMatrix.postScale(scaleX, scaleY);
   2142 
   2143         // Translate the draw in the new canvas, so we perfectly fit the
   2144         // shape in the bitmap.
   2145         canvas.setMatrix(offsetMatrix);
   2146 
   2147         canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0));
   2148 
   2149         // Make sure the final bits are in the bitmap.
   2150         canvas.flush();
   2151 
   2152         // In the new space, we use the identity matrix translated
   2153         // and scaled to reflect DPI.
   2154         matrix.setScale(1 / scaleX, 1 / scaleY);
   2155         matrix.postTranslate(deltaX, deltaY);
   2156 
   2157         perspectiveBounds.setRect(
   2158                 SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()),
   2159                                   SkScalarFloorToInt(bounds.y()),
   2160                                   SkScalarCeilToInt(bounds.width()),
   2161                                   SkScalarCeilToInt(bounds.height())));
   2162         clipRegion = &perspectiveBounds;
   2163         srcRect = NULL;
   2164         bitmap = &perspectiveBitmap;
   2165     }
   2166 
   2167     SkMatrix scaled;
   2168     // Adjust for origin flip.
   2169     scaled.setScale(SK_Scalar1, -SK_Scalar1);
   2170     scaled.postTranslate(0, SK_Scalar1);
   2171     // Scale the image up from 1x1 to WxH.
   2172     SkIRect subset = bitmap->bounds();
   2173     scaled.postScale(SkIntToScalar(subset.width()),
   2174                      SkIntToScalar(subset.height()));
   2175     scaled.postConcat(matrix);
   2176     ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint);
   2177     if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) {
   2178         return;
   2179     }
   2180     if (content.needShape()) {
   2181         SkPath shape;
   2182         shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()),
   2183                                      SkIntToScalar(subset.height())));
   2184         shape.transform(matrix);
   2185         content.setShape(shape);
   2186     }
   2187     if (!content.needSource()) {
   2188         return;
   2189     }
   2190 
   2191     SkBitmap subsetBitmap;
   2192     // Should extractSubset be done by the SkPDFDevice?
   2193     if (!bitmap->extractSubset(&subsetBitmap, subset)) {
   2194         return;
   2195     }
   2196     SkAutoTUnref<SkPDFObject> image(SkPDFBitmap::Create(fCanon, subsetBitmap));
   2197     if (!image) {
   2198         return;
   2199     }
   2200 
   2201     SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()),
   2202                                 &content.entry()->fContent);
   2203 }
   2204