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