1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkPDFDevice.h"
11
12#include "SkAnnotation.h"
13#include "SkColor.h"
14#include "SkClipStack.h"
15#include "SkData.h"
16#include "SkDraw.h"
17#include "SkFontHost.h"
18#include "SkGlyphCache.h"
19#include "SkPaint.h"
20#include "SkPath.h"
21#include "SkPDFFont.h"
22#include "SkPDFFormXObject.h"
23#include "SkPDFGraphicState.h"
24#include "SkPDFImage.h"
25#include "SkPDFShader.h"
26#include "SkPDFStream.h"
27#include "SkPDFTypes.h"
28#include "SkPDFUtils.h"
29#include "SkRect.h"
30#include "SkString.h"
31#include "SkTextFormatParams.h"
32#include "SkTemplates.h"
33#include "SkTypeface.h"
34#include "SkTypes.h"
35
36// Utility functions
37
38static void emit_pdf_color(SkColor color, SkWStream* result) {
39    SkASSERT(SkColorGetA(color) == 0xFF);  // We handle alpha elsewhere.
40    SkScalar colorMax = SkIntToScalar(0xFF);
41    SkPDFScalar::Append(
42            SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result);
43    result->writeText(" ");
44    SkPDFScalar::Append(
45            SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result);
46    result->writeText(" ");
47    SkPDFScalar::Append(
48            SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), result);
49    result->writeText(" ");
50}
51
52static SkPaint calculate_text_paint(const SkPaint& paint) {
53    SkPaint result = paint;
54    if (result.isFakeBoldText()) {
55        SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(),
56                                                    kStdFakeBoldInterpKeys,
57                                                    kStdFakeBoldInterpValues,
58                                                    kStdFakeBoldInterpLength);
59        SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale);
60        if (result.getStyle() == SkPaint::kFill_Style) {
61            result.setStyle(SkPaint::kStrokeAndFill_Style);
62        } else {
63            width += result.getStrokeWidth();
64        }
65        result.setStrokeWidth(width);
66    }
67    return result;
68}
69
70// Stolen from measure_text in SkDraw.cpp and then tweaked.
71static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
72                       const uint16_t* glyphs, size_t len,
73                       SkScalar* x, SkScalar* y) {
74    if (paint.getTextAlign() == SkPaint::kLeft_Align) {
75        return;
76    }
77
78    SkMatrix ident;
79    ident.reset();
80    SkAutoGlyphCache autoCache(paint, NULL, &ident);
81    SkGlyphCache* cache = autoCache.getCache();
82
83    const char* start = reinterpret_cast<const char*>(glyphs);
84    const char* stop = reinterpret_cast<const char*>(glyphs + len);
85    SkFixed xAdv = 0, yAdv = 0;
86
87    // TODO(vandebo): This probably needs to take kerning into account.
88    while (start < stop) {
89        const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0);
90        xAdv += glyph.fAdvanceX;
91        yAdv += glyph.fAdvanceY;
92    };
93    if (paint.getTextAlign() == SkPaint::kLeft_Align) {
94        return;
95    }
96
97    SkScalar xAdj = SkFixedToScalar(xAdv);
98    SkScalar yAdj = SkFixedToScalar(yAdv);
99    if (paint.getTextAlign() == SkPaint::kCenter_Align) {
100        xAdj = SkScalarHalf(xAdj);
101        yAdj = SkScalarHalf(yAdj);
102    }
103    *x = *x - xAdj;
104    *y = *y - yAdj;
105}
106
107static size_t max_glyphid_for_typeface(const SkTypeface* typeface) {
108    SkAdvancedTypefaceMetrics* metrics;
109    metrics = SkFontHost::GetAdvancedTypefaceMetrics(
110            SkTypeface::UniqueID(typeface),
111            SkAdvancedTypefaceMetrics::kNo_PerGlyphInfo,
112            NULL, 0);
113
114    int lastGlyphID = 0;
115    if (metrics) {
116        lastGlyphID = metrics->fLastGlyphID;
117        metrics->unref();
118    }
119    return lastGlyphID;
120}
121
122typedef SkAutoSTMalloc<128, uint16_t> SkGlyphStorage;
123
124static size_t force_glyph_encoding(const SkPaint& paint, const void* text,
125                                   size_t len, SkGlyphStorage* storage,
126                                   uint16_t** glyphIDs) {
127    // Make sure we have a glyph id encoding.
128    if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
129        size_t numGlyphs = paint.textToGlyphs(text, len, NULL);
130        storage->reset(numGlyphs);
131        paint.textToGlyphs(text, len, storage->get());
132        *glyphIDs = storage->get();
133        return numGlyphs;
134    }
135
136    // For user supplied glyph ids we need to validate them.
137    SkASSERT((len & 1) == 0);
138    size_t numGlyphs = len / 2;
139    const uint16_t* input =
140        reinterpret_cast<uint16_t*>(const_cast<void*>((text)));
141
142    int maxGlyphID = max_glyphid_for_typeface(paint.getTypeface());
143    size_t validated;
144    for (validated = 0; validated < numGlyphs; ++validated) {
145        if (input[validated] > maxGlyphID) {
146            break;
147        }
148    }
149    if (validated >= numGlyphs) {
150        *glyphIDs = reinterpret_cast<uint16_t*>(const_cast<void*>((text)));
151        return numGlyphs;
152    }
153
154    // Silently drop anything out of range.
155    storage->reset(numGlyphs);
156    if (validated > 0) {
157        memcpy(storage->get(), input, validated * sizeof(uint16_t));
158    }
159
160    for (size_t i = validated; i < numGlyphs; ++i) {
161        storage->get()[i] = input[i];
162        if (input[i] > maxGlyphID) {
163            storage->get()[i] = 0;
164        }
165    }
166    *glyphIDs = storage->get();
167    return numGlyphs;
168}
169
170static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX,
171                               SkWStream* content) {
172    // Flip the text about the x-axis to account for origin swap and include
173    // the passed parameters.
174    content->writeText("1 0 ");
175    SkPDFScalar::Append(0 - textSkewX, content);
176    content->writeText(" -1 ");
177    SkPDFScalar::Append(x, content);
178    content->writeText(" ");
179    SkPDFScalar::Append(y, content);
180    content->writeText(" Tm\n");
181}
182
183// It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
184// later being our representation of an object in the PDF file.
185struct GraphicStateEntry {
186    GraphicStateEntry();
187
188    // Compare the fields we care about when setting up a new content entry.
189    bool compareInitialState(const GraphicStateEntry& b);
190
191    SkMatrix fMatrix;
192    // We can't do set operations on Paths, though PDF natively supports
193    // intersect.  If the clip stack does anything other than intersect,
194    // we have to fall back to the region.  Treat fClipStack as authoritative.
195    // See http://code.google.com/p/skia/issues/detail?id=221
196    SkClipStack fClipStack;
197    SkRegion fClipRegion;
198
199    // When emitting the content entry, we will ensure the graphic state
200    // is set to these values first.
201    SkColor fColor;
202    SkScalar fTextScaleX;  // Zero means we don't care what the value is.
203    SkPaint::Style fTextFill;  // Only if TextScaleX is non-zero.
204    int fShaderIndex;
205    int fGraphicStateIndex;
206
207    // We may change the font (i.e. for Type1 support) within a
208    // ContentEntry.  This is the one currently in effect, or NULL if none.
209    SkPDFFont* fFont;
210    // In PDF, text size has no default value. It is only valid if fFont is
211    // not NULL.
212    SkScalar fTextSize;
213};
214
215GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK),
216                                         fTextScaleX(SK_Scalar1),
217                                         fTextFill(SkPaint::kFill_Style),
218                                         fShaderIndex(-1),
219                                         fGraphicStateIndex(-1),
220                                         fFont(NULL),
221                                         fTextSize(SK_ScalarNaN) {
222    fMatrix.reset();
223}
224
225bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& b) {
226    return fColor == b.fColor &&
227           fShaderIndex == b.fShaderIndex &&
228           fGraphicStateIndex == b.fGraphicStateIndex &&
229           fMatrix == b.fMatrix &&
230           fClipStack == b.fClipStack &&
231               (fTextScaleX == 0 ||
232                b.fTextScaleX == 0 ||
233                (fTextScaleX == b.fTextScaleX && fTextFill == b.fTextFill));
234}
235
236class GraphicStackState {
237public:
238    GraphicStackState(const SkClipStack& existingClipStack,
239                      const SkRegion& existingClipRegion,
240                      SkWStream* contentStream)
241            : fStackDepth(0),
242              fContentStream(contentStream) {
243        fEntries[0].fClipStack = existingClipStack;
244        fEntries[0].fClipRegion = existingClipRegion;
245    }
246
247    void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion,
248                    const SkPoint& translation);
249    void updateMatrix(const SkMatrix& matrix);
250    void updateDrawingState(const GraphicStateEntry& state);
251
252    void drainStack();
253
254private:
255    void push();
256    void pop();
257    GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; }
258
259    // Conservative limit on save depth, see impl. notes in PDF 1.4 spec.
260    static const int kMaxStackDepth = 12;
261    GraphicStateEntry fEntries[kMaxStackDepth + 1];
262    int fStackDepth;
263    SkWStream* fContentStream;
264};
265
266void GraphicStackState::drainStack() {
267    while (fStackDepth) {
268        pop();
269    }
270}
271
272void GraphicStackState::push() {
273    SkASSERT(fStackDepth < kMaxStackDepth);
274    fContentStream->writeText("q\n");
275    fStackDepth++;
276    fEntries[fStackDepth] = fEntries[fStackDepth - 1];
277}
278
279void GraphicStackState::pop() {
280    SkASSERT(fStackDepth > 0);
281    fContentStream->writeText("Q\n");
282    fStackDepth--;
283}
284
285// This function initializes iter to be an iterator on the "stack" argument
286// and then skips over the leading entries as specified in prefix.  It requires
287// and asserts that "prefix" will be a prefix to "stack."
288static void skip_clip_stack_prefix(const SkClipStack& prefix,
289                                   const SkClipStack& stack,
290                                   SkClipStack::Iter* iter) {
291    SkClipStack::B2TIter prefixIter(prefix);
292    iter->reset(stack, SkClipStack::Iter::kBottom_IterStart);
293
294    const SkClipStack::Element* prefixEntry;
295    const SkClipStack::Element* iterEntry;
296
297    for (prefixEntry = prefixIter.next(); prefixEntry;
298            prefixEntry = prefixIter.next()) {
299        iterEntry = iter->next();
300        SkASSERT(iterEntry);
301        // Because of SkClipStack does internal intersection, the last clip
302        // entry may differ.
303        if (*prefixEntry != *iterEntry) {
304            SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op);
305            SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op);
306            SkASSERT(iterEntry->getType() == prefixEntry->getType());
307            // back up the iterator by one
308            iter->prev();
309            prefixEntry = prefixIter.next();
310            break;
311        }
312    }
313
314    SkASSERT(prefixEntry == NULL);
315}
316
317static void emit_clip(SkPath* clipPath, SkRect* clipRect,
318                      SkWStream* contentStream) {
319    SkASSERT(clipPath || clipRect);
320
321    SkPath::FillType clipFill;
322    if (clipPath) {
323        SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream);
324        clipFill = clipPath->getFillType();
325    } else {
326        SkPDFUtils::AppendRectangle(*clipRect, contentStream);
327        clipFill = SkPath::kWinding_FillType;
328    }
329
330    NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false);
331    NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false);
332    if (clipFill == SkPath::kEvenOdd_FillType) {
333        contentStream->writeText("W* n\n");
334    } else {
335        contentStream->writeText("W n\n");
336    }
337}
338
339// TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF
340// graphic state stack, and the fact that we can know all the clips used
341// on the page to optimize this.
342void GraphicStackState::updateClip(const SkClipStack& clipStack,
343                                   const SkRegion& clipRegion,
344                                   const SkPoint& translation) {
345    if (clipStack == currentEntry()->fClipStack) {
346        return;
347    }
348
349    while (fStackDepth > 0) {
350        pop();
351        if (clipStack == currentEntry()->fClipStack) {
352            return;
353        }
354    }
355    push();
356
357    // gsState->initialEntry()->fClipStack/Region specifies the clip that has
358    // already been applied.  (If this is a top level device, then it specifies
359    // a clip to the content area.  If this is a layer, then it specifies
360    // the clip in effect when the layer was created.)  There's no need to
361    // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the
362    // initial clip on the parent layer.  (This means there's a bug if the user
363    // expands the clip and then uses any xfer mode that uses dst:
364    // http://code.google.com/p/skia/issues/detail?id=228 )
365    SkClipStack::Iter iter;
366    skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
367
368    // If the clip stack does anything other than intersect or if it uses
369    // an inverse fill type, we have to fall back to the clip region.
370    bool needRegion = false;
371    const SkClipStack::Element* clipEntry;
372    for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
373        if (clipEntry->getOp() != SkRegion::kIntersect_Op || clipEntry->isInverseFilled()) {
374            needRegion = true;
375            break;
376        }
377    }
378
379    if (needRegion) {
380        SkPath clipPath;
381        SkAssertResult(clipRegion.getBoundaryPath(&clipPath));
382        emit_clip(&clipPath, NULL, fContentStream);
383    } else {
384        skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
385        SkMatrix transform;
386        transform.setTranslate(translation.fX, translation.fY);
387        const SkClipStack::Element* clipEntry;
388        for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
389            SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op);
390            switch (clipEntry->getType()) {
391                case SkClipStack::Element::kRect_Type: {
392                    SkRect translatedClip;
393                    transform.mapRect(&translatedClip, clipEntry->getRect());
394                    emit_clip(NULL, &translatedClip, fContentStream);
395                    break;
396                }
397                case SkClipStack::Element::kPath_Type: {
398                    SkPath translatedPath;
399                    clipEntry->getPath().transform(transform, &translatedPath);
400                    emit_clip(&translatedPath, NULL, fContentStream);
401                    break;
402                }
403                default:
404                    SkASSERT(false);
405            }
406        }
407    }
408    currentEntry()->fClipStack = clipStack;
409    currentEntry()->fClipRegion = clipRegion;
410}
411
412void GraphicStackState::updateMatrix(const SkMatrix& matrix) {
413    if (matrix == currentEntry()->fMatrix) {
414        return;
415    }
416
417    if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) {
418        SkASSERT(fStackDepth > 0);
419        SkASSERT(fEntries[fStackDepth].fClipStack ==
420                 fEntries[fStackDepth -1].fClipStack);
421        pop();
422
423        SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask);
424    }
425    if (matrix.getType() == SkMatrix::kIdentity_Mask) {
426        return;
427    }
428
429    push();
430    SkPDFUtils::AppendTransform(matrix, fContentStream);
431    currentEntry()->fMatrix = matrix;
432}
433
434void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
435    // PDF treats a shader as a color, so we only set one or the other.
436    if (state.fShaderIndex >= 0) {
437        if (state.fShaderIndex != currentEntry()->fShaderIndex) {
438            fContentStream->writeText("/Pattern CS /Pattern cs /P");
439            fContentStream->writeDecAsText(state.fShaderIndex);
440            fContentStream->writeText(" SCN /P");
441            fContentStream->writeDecAsText(state.fShaderIndex);
442            fContentStream->writeText(" scn\n");
443            currentEntry()->fShaderIndex = state.fShaderIndex;
444        }
445    } else {
446        if (state.fColor != currentEntry()->fColor ||
447                currentEntry()->fShaderIndex >= 0) {
448            emit_pdf_color(state.fColor, fContentStream);
449            fContentStream->writeText("RG ");
450            emit_pdf_color(state.fColor, fContentStream);
451            fContentStream->writeText("rg\n");
452            currentEntry()->fColor = state.fColor;
453            currentEntry()->fShaderIndex = -1;
454        }
455    }
456
457    if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) {
458        SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream);
459        currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex;
460    }
461
462    if (state.fTextScaleX) {
463        if (state.fTextScaleX != currentEntry()->fTextScaleX) {
464            SkScalar pdfScale = SkScalarMul(state.fTextScaleX,
465                                            SkIntToScalar(100));
466            SkPDFScalar::Append(pdfScale, fContentStream);
467            fContentStream->writeText(" Tz\n");
468            currentEntry()->fTextScaleX = state.fTextScaleX;
469        }
470        if (state.fTextFill != currentEntry()->fTextFill) {
471            SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value);
472            SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1,
473                              enum_must_match_value);
474            SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2,
475                              enum_must_match_value);
476            fContentStream->writeDecAsText(state.fTextFill);
477            fContentStream->writeText(" Tr\n");
478            currentEntry()->fTextFill = state.fTextFill;
479        }
480    }
481}
482
483SkDevice* SkPDFDevice::onCreateCompatibleDevice(SkBitmap::Config config,
484                                                int width, int height,
485                                                bool isOpaque,
486                                                Usage usage) {
487    SkMatrix initialTransform;
488    initialTransform.reset();
489    SkISize size = SkISize::Make(width, height);
490    return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform));
491}
492
493
494struct ContentEntry {
495    GraphicStateEntry fState;
496    SkDynamicMemoryWStream fContent;
497    SkTScopedPtr<ContentEntry> fNext;
498};
499
500// A helper class to automatically finish a ContentEntry at the end of a
501// drawing method and maintain the state needed between set up and finish.
502class ScopedContentEntry {
503public:
504    ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw,
505                       const SkPaint& paint, bool hasText = false)
506        : fDevice(device),
507          fContentEntry(NULL),
508          fXfermode(SkXfermode::kSrcOver_Mode) {
509        init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText);
510    }
511    ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack,
512                       const SkRegion& clipRegion, const SkMatrix& matrix,
513                       const SkPaint& paint, bool hasText = false)
514        : fDevice(device),
515          fContentEntry(NULL),
516          fXfermode(SkXfermode::kSrcOver_Mode) {
517        init(clipStack, clipRegion, matrix, paint, hasText);
518    }
519
520    ~ScopedContentEntry() {
521        if (fContentEntry) {
522            fDevice->finishContentEntry(fXfermode, fDstFormXObject);
523        }
524        SkSafeUnref(fDstFormXObject);
525    }
526
527    ContentEntry* entry() { return fContentEntry; }
528private:
529    SkPDFDevice* fDevice;
530    ContentEntry* fContentEntry;
531    SkXfermode::Mode fXfermode;
532    SkPDFFormXObject* fDstFormXObject;
533
534    void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
535              const SkMatrix& matrix, const SkPaint& paint, bool hasText) {
536        fDstFormXObject = NULL;
537        if (paint.getXfermode()) {
538            paint.getXfermode()->asMode(&fXfermode);
539        }
540        fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion,
541                                                   matrix, paint, hasText,
542                                                   &fDstFormXObject);
543    }
544};
545
546////////////////////////////////////////////////////////////////////////////////
547
548static inline SkBitmap makeContentBitmap(const SkISize& contentSize,
549                                         const SkMatrix* initialTransform) {
550    SkBitmap bitmap;
551    if (initialTransform) {
552        // Compute the size of the drawing area.
553        SkVector drawingSize;
554        SkMatrix inverse;
555        drawingSize.set(SkIntToScalar(contentSize.fWidth),
556                        SkIntToScalar(contentSize.fHeight));
557        if (!initialTransform->invert(&inverse)) {
558            // This shouldn't happen, initial transform should be invertible.
559            SkASSERT(false);
560            inverse.reset();
561        }
562        inverse.mapVectors(&drawingSize, 1);
563        SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound();
564        bitmap.setConfig(SkBitmap::kNo_Config, abs(size.fWidth),
565                         abs(size.fHeight));
566    } else {
567        bitmap.setConfig(SkBitmap::kNo_Config, abs(contentSize.fWidth),
568                         abs(contentSize.fHeight));
569    }
570
571    return bitmap;
572}
573
574// TODO(vandebo) change pageSize to SkSize.
575SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
576                         const SkMatrix& initialTransform)
577    : SkDevice(makeContentBitmap(contentSize, &initialTransform)),
578      fPageSize(pageSize),
579      fContentSize(contentSize),
580      fLastContentEntry(NULL),
581      fLastMarginContentEntry(NULL),
582      fClipStack(NULL) {
583    // Skia generally uses the top left as the origin but PDF natively has the
584    // origin at the bottom left. This matrix corrects for that.  But that only
585    // needs to be done once, we don't do it when layering.
586    fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight));
587    fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1);
588    fInitialTransform.preConcat(initialTransform);
589
590    SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height());
591    fExistingClipRegion.setRect(existingClip);
592
593    this->init();
594}
595
596// TODO(vandebo) change layerSize to SkSize.
597SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
598                         const SkClipStack& existingClipStack,
599                         const SkRegion& existingClipRegion)
600    : SkDevice(makeContentBitmap(layerSize, NULL)),
601      fPageSize(layerSize),
602      fContentSize(layerSize),
603      fExistingClipStack(existingClipStack),
604      fExistingClipRegion(existingClipRegion),
605      fLastContentEntry(NULL),
606      fLastMarginContentEntry(NULL),
607      fClipStack(NULL) {
608    fInitialTransform.reset();
609    this->init();
610}
611
612SkPDFDevice::~SkPDFDevice() {
613    this->cleanUp(true);
614}
615
616void SkPDFDevice::init() {
617    fAnnotations = NULL;
618    fResourceDict = NULL;
619    fContentEntries.reset();
620    fLastContentEntry = NULL;
621    fMarginContentEntries.reset();
622    fLastMarginContentEntry = NULL;
623    fDrawingArea = kContent_DrawingArea;
624    if (fFontGlyphUsage == NULL) {
625        fFontGlyphUsage.reset(new SkPDFGlyphSetMap());
626    }
627}
628
629void SkPDFDevice::cleanUp(bool clearFontUsage) {
630    fGraphicStateResources.unrefAll();
631    fXObjectResources.unrefAll();
632    fFontResources.unrefAll();
633    fShaderResources.unrefAll();
634    SkSafeUnref(fAnnotations);
635    SkSafeUnref(fResourceDict);
636
637    if (clearFontUsage) {
638        fFontGlyphUsage->reset();
639    }
640}
641
642uint32_t SkPDFDevice::getDeviceCapabilities() {
643    return kVector_Capability;
644}
645
646void SkPDFDevice::clear(SkColor color) {
647    this->cleanUp(true);
648    this->init();
649
650    SkPaint paint;
651    paint.setColor(color);
652    paint.setStyle(SkPaint::kFill_Style);
653    SkMatrix identity;
654    identity.reset();
655    ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion,
656                               identity, paint);
657    internalDrawPaint(paint, content.entry());
658}
659
660void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
661    SkPaint newPaint = paint;
662    newPaint.setStyle(SkPaint::kFill_Style);
663    ScopedContentEntry content(this, d, newPaint);
664    internalDrawPaint(newPaint, content.entry());
665}
666
667void SkPDFDevice::internalDrawPaint(const SkPaint& paint,
668                                    ContentEntry* contentEntry) {
669    if (!contentEntry) {
670        return;
671    }
672    SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()),
673                                 SkIntToScalar(this->height()));
674    SkMatrix totalTransform = fInitialTransform;
675    totalTransform.preConcat(contentEntry->fState.fMatrix);
676    SkMatrix inverse;
677    if (!totalTransform.invert(&inverse)) {
678        return;
679    }
680    inverse.mapRect(&bbox);
681
682    SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent);
683    SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
684                          &contentEntry->fContent);
685}
686
687void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
688                             size_t count, const SkPoint* points,
689                             const SkPaint& passedPaint) {
690    if (count == 0) {
691        return;
692    }
693
694    // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath.
695    // We only use this when there's a path effect because of the overhead
696    // of multiple calls to setUpContentEntry it causes.
697    if (passedPaint.getPathEffect()) {
698        if (d.fClip->isEmpty()) {
699            return;
700        }
701        SkDraw pointDraw(d);
702        pointDraw.fDevice = this;
703        pointDraw.drawPoints(mode, count, points, passedPaint, true);
704        return;
705    }
706
707    const SkPaint* paint = &passedPaint;
708    SkPaint modifiedPaint;
709
710    if (mode == SkCanvas::kPoints_PointMode &&
711            paint->getStrokeCap() != SkPaint::kRound_Cap) {
712        modifiedPaint = *paint;
713        paint = &modifiedPaint;
714        if (paint->getStrokeWidth()) {
715            // PDF won't draw a single point with square/butt caps because the
716            // orientation is ambiguous.  Draw a rectangle instead.
717            modifiedPaint.setStyle(SkPaint::kFill_Style);
718            SkScalar strokeWidth = paint->getStrokeWidth();
719            SkScalar halfStroke = SkScalarHalf(strokeWidth);
720            for (size_t i = 0; i < count; i++) {
721                SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0);
722                r.inset(-halfStroke, -halfStroke);
723                drawRect(d, r, modifiedPaint);
724            }
725            return;
726        } else {
727            modifiedPaint.setStrokeCap(SkPaint::kRound_Cap);
728        }
729    }
730
731    ScopedContentEntry content(this, d, *paint);
732    if (!content.entry()) {
733        return;
734    }
735
736    switch (mode) {
737        case SkCanvas::kPolygon_PointMode:
738            SkPDFUtils::MoveTo(points[0].fX, points[0].fY,
739                               &content.entry()->fContent);
740            for (size_t i = 1; i < count; i++) {
741                SkPDFUtils::AppendLine(points[i].fX, points[i].fY,
742                                       &content.entry()->fContent);
743            }
744            SkPDFUtils::StrokePath(&content.entry()->fContent);
745            break;
746        case SkCanvas::kLines_PointMode:
747            for (size_t i = 0; i < count/2; i++) {
748                SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY,
749                                   &content.entry()->fContent);
750                SkPDFUtils::AppendLine(points[i * 2 + 1].fX,
751                                       points[i * 2 + 1].fY,
752                                       &content.entry()->fContent);
753                SkPDFUtils::StrokePath(&content.entry()->fContent);
754            }
755            break;
756        case SkCanvas::kPoints_PointMode:
757            SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap);
758            for (size_t i = 0; i < count; i++) {
759                SkPDFUtils::MoveTo(points[i].fX, points[i].fY,
760                                   &content.entry()->fContent);
761                SkPDFUtils::ClosePath(&content.entry()->fContent);
762                SkPDFUtils::StrokePath(&content.entry()->fContent);
763            }
764            break;
765        default:
766            SkASSERT(false);
767    }
768}
769
770void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r,
771                           const SkPaint& paint) {
772    if (paint.getPathEffect()) {
773        if (d.fClip->isEmpty()) {
774            return;
775        }
776        SkPath path;
777        path.addRect(r);
778        drawPath(d, path, paint, NULL, true);
779        return;
780    }
781
782    if (handleAnnotations(r, *d.fMatrix, paint)) {
783        return;
784    }
785
786    ScopedContentEntry content(this, d, paint);
787    if (!content.entry()) {
788        return;
789    }
790    SkPDFUtils::AppendRectangle(r, &content.entry()->fContent);
791    SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
792                          &content.entry()->fContent);
793}
794
795void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
796                           const SkPaint& paint, const SkMatrix* prePathMatrix,
797                           bool pathIsMutable) {
798    SkPath modifiedPath;
799    SkPath* pathPtr = const_cast<SkPath*>(&origPath);
800
801    SkMatrix matrix = *d.fMatrix;
802    if (prePathMatrix) {
803        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
804            if (!pathIsMutable) {
805                pathPtr = &modifiedPath;
806                pathIsMutable = true;
807            }
808            origPath.transform(*prePathMatrix, pathPtr);
809        } else {
810            if (!matrix.preConcat(*prePathMatrix)) {
811                return;
812            }
813        }
814    }
815
816    if (paint.getPathEffect()) {
817        if (d.fClip->isEmpty()) {
818            return;
819        }
820        if (!pathIsMutable) {
821            pathPtr = &modifiedPath;
822            pathIsMutable = true;
823        }
824        bool fill = paint.getFillPath(origPath, pathPtr);
825
826        SkPaint noEffectPaint(paint);
827        noEffectPaint.setPathEffect(NULL);
828        if (fill) {
829            noEffectPaint.setStyle(SkPaint::kFill_Style);
830        } else {
831            noEffectPaint.setStyle(SkPaint::kStroke_Style);
832            noEffectPaint.setStrokeWidth(0);
833        }
834        drawPath(d, *pathPtr, noEffectPaint, NULL, true);
835        return;
836    }
837
838    if (handleAnnotations(pathPtr->getBounds(), *d.fMatrix, paint)) {
839        return;
840    }
841
842    ScopedContentEntry content(this, d, paint);
843    if (!content.entry()) {
844        return;
845    }
846    SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(),
847                         &content.entry()->fContent);
848    SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
849                          &content.entry()->fContent);
850}
851
852void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
853                             const SkIRect* srcRect, const SkMatrix& matrix,
854                             const SkPaint& paint) {
855    if (d.fClip->isEmpty()) {
856        return;
857    }
858
859    SkMatrix transform = matrix;
860    transform.postConcat(*d.fMatrix);
861    internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, srcRect,
862                       paint);
863}
864
865void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap,
866                             int x, int y, const SkPaint& paint) {
867    if (d.fClip->isEmpty()) {
868        return;
869    }
870
871    SkMatrix matrix;
872    matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
873    internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL, paint);
874}
875
876void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
877                           SkScalar x, SkScalar y, const SkPaint& paint) {
878    SkPaint textPaint = calculate_text_paint(paint);
879    ScopedContentEntry content(this, d, textPaint, true);
880    if (!content.entry()) {
881        return;
882    }
883
884    SkGlyphStorage storage(0);
885    uint16_t* glyphIDs = NULL;
886    size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage,
887                                            &glyphIDs);
888    textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
889
890    SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
891    align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y);
892    content.entry()->fContent.writeText("BT\n");
893    set_text_transform(x, y, textPaint.getTextSkewX(),
894                       &content.entry()->fContent);
895    size_t consumedGlyphCount = 0;
896    while (numGlyphs > consumedGlyphCount) {
897        updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry());
898        SkPDFFont* font = content.entry()->fState.fFont;
899        size_t availableGlyphs =
900            font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount,
901                                          numGlyphs - consumedGlyphCount);
902        fFontGlyphUsage->noteGlyphUsage(font, glyphIDs + consumedGlyphCount,
903                                        availableGlyphs);
904        SkString encodedString =
905            SkPDFString::FormatString(glyphIDs + consumedGlyphCount,
906                                      availableGlyphs, font->multiByteGlyphs());
907        content.entry()->fContent.writeText(encodedString.c_str());
908        consumedGlyphCount += availableGlyphs;
909        content.entry()->fContent.writeText(" Tj\n");
910    }
911    content.entry()->fContent.writeText("ET\n");
912}
913
914void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
915                              const SkScalar pos[], SkScalar constY,
916                              int scalarsPerPos, const SkPaint& paint) {
917    SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
918    SkPaint textPaint = calculate_text_paint(paint);
919    ScopedContentEntry content(this, d, textPaint, true);
920    if (!content.entry()) {
921        return;
922    }
923
924    SkGlyphStorage storage(0);
925    uint16_t* glyphIDs = NULL;
926    size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage,
927                                            &glyphIDs);
928    textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
929
930    SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
931    content.entry()->fContent.writeText("BT\n");
932    updateFont(textPaint, glyphIDs[0], content.entry());
933    for (size_t i = 0; i < numGlyphs; i++) {
934        SkPDFFont* font = content.entry()->fState.fFont;
935        uint16_t encodedValue = glyphIDs[i];
936        if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
937            updateFont(textPaint, glyphIDs[i], content.entry());
938            i--;
939            continue;
940        }
941        fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1);
942        SkScalar x = pos[i * scalarsPerPos];
943        SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
944        align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y);
945        set_text_transform(x, y, textPaint.getTextSkewX(),
946                           &content.entry()->fContent);
947        SkString encodedString =
948            SkPDFString::FormatString(&encodedValue, 1,
949                                      font->multiByteGlyphs());
950        content.entry()->fContent.writeText(encodedString.c_str());
951        content.entry()->fContent.writeText(" Tj\n");
952    }
953    content.entry()->fContent.writeText("ET\n");
954}
955
956void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
957                                 const SkPath& path, const SkMatrix* matrix,
958                                 const SkPaint& paint) {
959    if (d.fClip->isEmpty()) {
960        return;
961    }
962    d.drawTextOnPath((const char*)text, len, path, matrix, paint);
963}
964
965void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode,
966                               int vertexCount, const SkPoint verts[],
967                               const SkPoint texs[], const SkColor colors[],
968                               SkXfermode* xmode, const uint16_t indices[],
969                               int indexCount, const SkPaint& paint) {
970    if (d.fClip->isEmpty()) {
971        return;
972    }
973    NOT_IMPLEMENTED("drawVerticies", true);
974}
975
976void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
977                             const SkPaint& paint) {
978    if ((device->getDeviceCapabilities() & kVector_Capability) == 0) {
979        // If we somehow get a raster device, do what our parent would do.
980        SkDevice::drawDevice(d, device, x, y, paint);
981        return;
982    }
983
984    // Assume that a vector capable device means that it's a PDF Device.
985    SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device);
986    if (pdfDevice->isContentEmpty()) {
987        return;
988    }
989
990    SkMatrix matrix;
991    matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
992    ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
993    if (!content.entry()) {
994        return;
995    }
996
997    SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
998    fXObjectResources.push(xobject);  // Transfer reference.
999    SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
1000                                &content.entry()->fContent);
1001
1002    // Merge glyph sets from the drawn device.
1003    fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage());
1004}
1005
1006void SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) {
1007    INHERITED::onAttachToCanvas(canvas);
1008
1009    // Canvas promises that this ptr is valid until onDetachFromCanvas is called
1010    fClipStack = canvas->getClipStack();
1011}
1012
1013void SkPDFDevice::onDetachFromCanvas() {
1014    INHERITED::onDetachFromCanvas();
1015
1016    fClipStack = NULL;
1017}
1018
1019ContentEntry* SkPDFDevice::getLastContentEntry() {
1020    if (fDrawingArea == kContent_DrawingArea) {
1021        return fLastContentEntry;
1022    } else {
1023        return fLastMarginContentEntry;
1024    }
1025}
1026
1027SkTScopedPtr<ContentEntry>* SkPDFDevice::getContentEntries() {
1028    if (fDrawingArea == kContent_DrawingArea) {
1029        return &fContentEntries;
1030    } else {
1031        return &fMarginContentEntries;
1032    }
1033}
1034
1035void SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) {
1036    if (fDrawingArea == kContent_DrawingArea) {
1037        fLastContentEntry = contentEntry;
1038    } else {
1039        fLastMarginContentEntry = contentEntry;
1040    }
1041}
1042
1043void SkPDFDevice::setDrawingArea(DrawingArea drawingArea) {
1044    // A ScopedContentEntry only exists during the course of a draw call, so
1045    // this can't be called while a ScopedContentEntry exists.
1046    fDrawingArea = drawingArea;
1047}
1048
1049SkPDFDict* SkPDFDevice::getResourceDict() {
1050    if (NULL == fResourceDict) {
1051        fResourceDict = SkNEW(SkPDFDict);
1052
1053        if (fGraphicStateResources.count()) {
1054            SkAutoTUnref<SkPDFDict> extGState(new SkPDFDict());
1055            for (int i = 0; i < fGraphicStateResources.count(); i++) {
1056                SkString nameString("G");
1057                nameString.appendS32(i);
1058                extGState->insert(
1059                        nameString.c_str(),
1060                        new SkPDFObjRef(fGraphicStateResources[i]))->unref();
1061            }
1062            fResourceDict->insert("ExtGState", extGState.get());
1063        }
1064
1065        if (fXObjectResources.count()) {
1066            SkAutoTUnref<SkPDFDict> xObjects(new SkPDFDict());
1067            for (int i = 0; i < fXObjectResources.count(); i++) {
1068                SkString nameString("X");
1069                nameString.appendS32(i);
1070                xObjects->insert(
1071                        nameString.c_str(),
1072                        new SkPDFObjRef(fXObjectResources[i]))->unref();
1073            }
1074            fResourceDict->insert("XObject", xObjects.get());
1075        }
1076
1077        if (fFontResources.count()) {
1078            SkAutoTUnref<SkPDFDict> fonts(new SkPDFDict());
1079            for (int i = 0; i < fFontResources.count(); i++) {
1080                SkString nameString("F");
1081                nameString.appendS32(i);
1082                fonts->insert(nameString.c_str(),
1083                              new SkPDFObjRef(fFontResources[i]))->unref();
1084            }
1085            fResourceDict->insert("Font", fonts.get());
1086        }
1087
1088        if (fShaderResources.count()) {
1089            SkAutoTUnref<SkPDFDict> patterns(new SkPDFDict());
1090            for (int i = 0; i < fShaderResources.count(); i++) {
1091                SkString nameString("P");
1092                nameString.appendS32(i);
1093                patterns->insert(nameString.c_str(),
1094                                 new SkPDFObjRef(fShaderResources[i]))->unref();
1095            }
1096            fResourceDict->insert("Pattern", patterns.get());
1097        }
1098
1099        // For compatibility, add all proc sets (only used for output to PS
1100        // devices).
1101        const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"};
1102        SkAutoTUnref<SkPDFArray> procSets(new SkPDFArray());
1103        procSets->reserve(SK_ARRAY_COUNT(procs));
1104        for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++)
1105            procSets->appendName(procs[i]);
1106        fResourceDict->insert("ProcSet", procSets.get());
1107    }
1108    return fResourceDict;
1109}
1110
1111void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList,
1112                               bool recursive) const {
1113    resourceList->setReserve(resourceList->count() +
1114                             fGraphicStateResources.count() +
1115                             fXObjectResources.count() +
1116                             fFontResources.count() +
1117                             fShaderResources.count());
1118    for (int i = 0; i < fGraphicStateResources.count(); i++) {
1119        resourceList->push(fGraphicStateResources[i]);
1120        fGraphicStateResources[i]->ref();
1121        if (recursive) {
1122            fGraphicStateResources[i]->getResources(resourceList);
1123        }
1124    }
1125    for (int i = 0; i < fXObjectResources.count(); i++) {
1126        resourceList->push(fXObjectResources[i]);
1127        fXObjectResources[i]->ref();
1128        if (recursive) {
1129            fXObjectResources[i]->getResources(resourceList);
1130        }
1131    }
1132    for (int i = 0; i < fFontResources.count(); i++) {
1133        resourceList->push(fFontResources[i]);
1134        fFontResources[i]->ref();
1135        if (recursive) {
1136            fFontResources[i]->getResources(resourceList);
1137        }
1138    }
1139    for (int i = 0; i < fShaderResources.count(); i++) {
1140        resourceList->push(fShaderResources[i]);
1141        fShaderResources[i]->ref();
1142        if (recursive) {
1143            fShaderResources[i]->getResources(resourceList);
1144        }
1145    }
1146}
1147
1148const SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const {
1149    return fFontResources;
1150}
1151
1152SkPDFArray* SkPDFDevice::copyMediaBox() const {
1153    // should this be a singleton?
1154    SkAutoTUnref<SkPDFInt> zero(SkNEW_ARGS(SkPDFInt, (0)));
1155
1156    SkPDFArray* mediaBox = SkNEW(SkPDFArray);
1157    mediaBox->reserve(4);
1158    mediaBox->append(zero.get());
1159    mediaBox->append(zero.get());
1160    mediaBox->appendInt(fPageSize.fWidth);
1161    mediaBox->appendInt(fPageSize.fHeight);
1162    return mediaBox;
1163}
1164
1165SkStream* SkPDFDevice::content() const {
1166    SkMemoryStream* result = new SkMemoryStream;
1167    result->setData(this->copyContentToData())->unref();
1168    return result;
1169}
1170
1171void SkPDFDevice::copyContentEntriesToData(ContentEntry* entry,
1172        SkWStream* data) const {
1173    // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the
1174    // right thing to pass here.
1175    GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data);
1176    while (entry != NULL) {
1177        SkPoint translation;
1178        translation.iset(this->getOrigin());
1179        translation.negate();
1180        gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
1181                           translation);
1182        gsState.updateMatrix(entry->fState.fMatrix);
1183        gsState.updateDrawingState(entry->fState);
1184
1185        SkAutoDataUnref copy(entry->fContent.copyToData());
1186        data->write(copy->data(), copy->size());
1187        entry = entry->fNext.get();
1188    }
1189    gsState.drainStack();
1190}
1191
1192SkData* SkPDFDevice::copyContentToData() const {
1193    SkDynamicMemoryWStream data;
1194    if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
1195        SkPDFUtils::AppendTransform(fInitialTransform, &data);
1196    }
1197
1198    // TODO(aayushkumar): Apply clip along the margins.  Currently, webkit
1199    // colors the contentArea white before it starts drawing into it and
1200    // that currently acts as our clip.
1201    // Also, think about adding a transform here (or assume that the values
1202    // sent across account for that)
1203    SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), &data);
1204
1205    // If the content area is the entire page, then we don't need to clip
1206    // the content area (PDF area clips to the page size).  Otherwise,
1207    // we have to clip to the content area; we've already applied the
1208    // initial transform, so just clip to the device size.
1209    if (fPageSize != fContentSize) {
1210        SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()),
1211                                  SkIntToScalar(this->height()));
1212        emit_clip(NULL, &r, &data);
1213    }
1214
1215    SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data);
1216
1217    // potentially we could cache this SkData, and only rebuild it if we
1218    // see that our state has changed.
1219    return data.copyToData();
1220}
1221
1222bool SkPDFDevice::handleAnnotations(const SkRect& r, const SkMatrix& matrix,
1223                                    const SkPaint& p) {
1224    SkAnnotation* annotationInfo = p.getAnnotation();
1225    if (!annotationInfo) {
1226        return false;
1227    }
1228    SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key());
1229    if (!urlData) {
1230        return false;
1231    }
1232
1233    SkString url(static_cast<const char *>(urlData->data()),
1234                 urlData->size() - 1);
1235    SkMatrix transform = matrix;
1236    transform.postConcat(fInitialTransform);
1237    SkRect translatedRect;
1238    transform.mapRect(&translatedRect, r);
1239
1240    if (NULL == fAnnotations) {
1241        fAnnotations = SkNEW(SkPDFArray);
1242    }
1243    SkAutoTUnref<SkPDFDict> annotation(new SkPDFDict("Annot"));
1244    annotation->insertName("Subtype", "Link");
1245    fAnnotations->append(annotation.get());
1246
1247    SkAutoTUnref<SkPDFArray> border(new SkPDFArray);
1248    border->reserve(3);
1249    border->appendInt(0);  // Horizontal corner radius.
1250    border->appendInt(0);  // Vertical corner radius.
1251    border->appendInt(0);  // Width, 0 = no border.
1252    annotation->insert("Border", border.get());
1253
1254    SkAutoTUnref<SkPDFArray> rect(new SkPDFArray);
1255    rect->reserve(4);
1256    rect->appendScalar(translatedRect.fLeft);
1257    rect->appendScalar(translatedRect.fTop);
1258    rect->appendScalar(translatedRect.fRight);
1259    rect->appendScalar(translatedRect.fBottom);
1260    annotation->insert("Rect", rect.get());
1261
1262    SkAutoTUnref<SkPDFDict> action(new SkPDFDict("Action"));
1263    action->insertName("S", "URI");
1264    action->insert("URI", new SkPDFString(url))->unref();
1265    annotation->insert("A", action.get());
1266
1267    return p.isNoDrawAnnotation();
1268}
1269
1270SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() {
1271    SkPDFFormXObject* xobject = SkNEW_ARGS(SkPDFFormXObject, (this));
1272    // We always draw the form xobjects that we create back into the device, so
1273    // we simply preserve the font usage instead of pulling it out and merging
1274    // it back in later.
1275    cleanUp(false);  // Reset this device to have no content.
1276    init();
1277    return xobject;
1278}
1279
1280void SkPDFDevice::clearClipFromContent(const SkClipStack* clipStack,
1281                                       const SkRegion& clipRegion) {
1282    if (clipRegion.isEmpty() || isContentEmpty()) {
1283        return;
1284    }
1285    SkAutoTUnref<SkPDFFormXObject> curContent(createFormXObjectFromDevice());
1286
1287    // Redraw what we already had, but with the clip as a mask.
1288    drawFormXObjectWithClip(curContent, clipStack, clipRegion, true);
1289}
1290
1291void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject,
1292                                          const SkClipStack* clipStack,
1293                                          const SkRegion& clipRegion,
1294                                          bool invertClip) {
1295    if (clipRegion.isEmpty() && !invertClip) {
1296        return;
1297    }
1298
1299    // Create the mask.
1300    SkMatrix identity;
1301    identity.reset();
1302    SkDraw draw;
1303    draw.fMatrix = &identity;
1304    draw.fClip = &clipRegion;
1305    draw.fClipStack = clipStack;
1306    SkPaint stockPaint;
1307    this->drawPaint(draw, stockPaint);
1308    SkAutoTUnref<SkPDFFormXObject> maskFormXObject(createFormXObjectFromDevice());
1309    SkAutoTUnref<SkPDFGraphicState> sMaskGS(
1310        SkPDFGraphicState::GetSMaskGraphicState(maskFormXObject, invertClip));
1311
1312    // Draw the xobject with the clip as a mask.
1313    ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion,
1314                                 identity, stockPaint);
1315    if (!content.entry()) {
1316        return;
1317    }
1318    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1319                                  &content.entry()->fContent);
1320    SkPDFUtils::DrawFormXObject(fXObjectResources.count(),
1321                                &content.entry()->fContent);
1322    fXObjectResources.push(xobject);
1323    xobject->ref();
1324
1325    sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState());
1326    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1327                                  &content.entry()->fContent);
1328}
1329
1330ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
1331                                             const SkRegion& clipRegion,
1332                                             const SkMatrix& matrix,
1333                                             const SkPaint& paint,
1334                                             bool hasText,
1335                                             SkPDFFormXObject** dst) {
1336    *dst = NULL;
1337    if (clipRegion.isEmpty()) {
1338        return NULL;
1339    }
1340
1341    // The clip stack can come from an SkDraw where it is technically optional.
1342    SkClipStack synthesizedClipStack;
1343    if (clipStack == NULL) {
1344        if (clipRegion == fExistingClipRegion) {
1345            clipStack = &fExistingClipStack;
1346        } else {
1347            // GraphicStackState::updateClip expects the clip stack to have
1348            // fExistingClip as a prefix, so start there, then set the clip
1349            // to the passed region.
1350            synthesizedClipStack = fExistingClipStack;
1351            SkPath clipPath;
1352            clipRegion.getBoundaryPath(&clipPath);
1353            synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op,
1354                                             false);
1355            clipStack = &synthesizedClipStack;
1356        }
1357    }
1358
1359    SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
1360    if (paint.getXfermode()) {
1361        paint.getXfermode()->asMode(&xfermode);
1362    }
1363
1364    if (xfermode == SkXfermode::kClear_Mode ||
1365            xfermode == SkXfermode::kSrc_Mode) {
1366        this->clearClipFromContent(clipStack, clipRegion);
1367    } else if (xfermode == SkXfermode::kSrcIn_Mode ||
1368               xfermode == SkXfermode::kDstIn_Mode ||
1369               xfermode == SkXfermode::kSrcOut_Mode ||
1370               xfermode == SkXfermode::kDstOut_Mode) {
1371        // For the following modes, we use both source and destination, but
1372        // we use one as a smask for the other, so we have to make form xobjects
1373        // out of both of them: SrcIn, DstIn, SrcOut, DstOut.
1374        if (isContentEmpty()) {
1375            return NULL;
1376        } else {
1377            *dst = createFormXObjectFromDevice();
1378        }
1379    }
1380    // TODO(vandebo): Figure out how/if we can handle the following modes:
1381    // SrcAtop, DestAtop, Xor, Plus.
1382
1383    // These xfer modes don't draw source at all.
1384    if (xfermode == SkXfermode::kClear_Mode ||
1385            xfermode == SkXfermode::kDst_Mode) {
1386        return NULL;
1387    }
1388
1389    ContentEntry* entry;
1390    SkTScopedPtr<ContentEntry> newEntry;
1391
1392    ContentEntry* lastContentEntry = getLastContentEntry();
1393    if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) {
1394        entry = lastContentEntry;
1395    } else {
1396        newEntry.reset(new ContentEntry);
1397        entry = newEntry.get();
1398    }
1399
1400    populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
1401                                       hasText, &entry->fState);
1402    if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
1403            entry->fState.compareInitialState(lastContentEntry->fState)) {
1404        return lastContentEntry;
1405    }
1406
1407    SkTScopedPtr<ContentEntry>* contentEntries = getContentEntries();
1408    if (!lastContentEntry) {
1409        contentEntries->reset(entry);
1410        setLastContentEntry(entry);
1411    } else if (xfermode == SkXfermode::kDstOver_Mode) {
1412        entry->fNext.reset(contentEntries->release());
1413        contentEntries->reset(entry);
1414    } else {
1415        lastContentEntry->fNext.reset(entry);
1416        setLastContentEntry(entry);
1417    }
1418    newEntry.release();
1419    return entry;
1420}
1421
1422void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
1423                                     SkPDFFormXObject* dst) {
1424    if (xfermode != SkXfermode::kSrcIn_Mode &&
1425            xfermode != SkXfermode::kDstIn_Mode &&
1426            xfermode != SkXfermode::kSrcOut_Mode &&
1427            xfermode != SkXfermode::kDstOut_Mode) {
1428        SkASSERT(!dst);
1429        return;
1430    }
1431
1432    ContentEntry* contentEntries = getContentEntries()->get();
1433    SkASSERT(dst);
1434    SkASSERT(!contentEntries->fNext.get());
1435    // We have to make a copy of these here because changing the current
1436    // content into a form xobject will destroy them.
1437    SkClipStack clipStack = contentEntries->fState.fClipStack;
1438    SkRegion clipRegion = contentEntries->fState.fClipRegion;
1439
1440    SkAutoTUnref<SkPDFFormXObject> srcFormXObject;
1441    if (!isContentEmpty()) {
1442        srcFormXObject.reset(createFormXObjectFromDevice());
1443    }
1444
1445    drawFormXObjectWithClip(dst, &clipStack, clipRegion, true);
1446
1447    // We've redrawn dst minus the clip area, if there's no src, we're done.
1448    if (!srcFormXObject.get()) {
1449        return;
1450    }
1451
1452    SkMatrix identity;
1453    identity.reset();
1454    SkPaint stockPaint;
1455    ScopedContentEntry inClipContentEntry(this, &fExistingClipStack,
1456                                          fExistingClipRegion, identity,
1457                                          stockPaint);
1458    if (!inClipContentEntry.entry()) {
1459        return;
1460    }
1461
1462    SkAutoTUnref<SkPDFGraphicState> sMaskGS;
1463    if (xfermode == SkXfermode::kSrcIn_Mode ||
1464            xfermode == SkXfermode::kSrcOut_Mode) {
1465        sMaskGS.reset(SkPDFGraphicState::GetSMaskGraphicState(
1466                dst, xfermode == SkXfermode::kSrcOut_Mode));
1467        fXObjectResources.push(srcFormXObject.get());
1468        srcFormXObject.get()->ref();
1469    } else {
1470        sMaskGS.reset(SkPDFGraphicState::GetSMaskGraphicState(
1471                srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode));
1472        // dst already added to fXObjectResources in drawFormXObjectWithClip.
1473    }
1474    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1475                                  &inClipContentEntry.entry()->fContent);
1476
1477    SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
1478                                &inClipContentEntry.entry()->fContent);
1479
1480    sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState());
1481    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1482                                  &inClipContentEntry.entry()->fContent);
1483}
1484
1485bool SkPDFDevice::isContentEmpty() {
1486    ContentEntry* contentEntries = getContentEntries()->get();
1487    if (!contentEntries || contentEntries->fContent.getOffset() == 0) {
1488        SkASSERT(!contentEntries || !contentEntries->fNext.get());
1489        return true;
1490    }
1491    return false;
1492}
1493
1494void SkPDFDevice::populateGraphicStateEntryFromPaint(
1495        const SkMatrix& matrix,
1496        const SkClipStack& clipStack,
1497        const SkRegion& clipRegion,
1498        const SkPaint& paint,
1499        bool hasText,
1500        GraphicStateEntry* entry) {
1501    SkASSERT(paint.getPathEffect() == NULL);
1502
1503    NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
1504    NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false);
1505
1506    entry->fMatrix = matrix;
1507    entry->fClipStack = clipStack;
1508    entry->fClipRegion = clipRegion;
1509    entry->fColor = SkColorSetA(paint.getColor(), 0xFF);
1510    entry->fShaderIndex = -1;
1511
1512    // PDF treats a shader as a color, so we only set one or the other.
1513    SkAutoTUnref<SkPDFObject> pdfShader;
1514    const SkShader* shader = paint.getShader();
1515    SkColor color = paint.getColor();
1516    if (shader) {
1517        // PDF positions patterns relative to the initial transform, so
1518        // we need to apply the current transform to the shader parameters.
1519        SkMatrix transform = matrix;
1520        transform.postConcat(fInitialTransform);
1521
1522        // PDF doesn't support kClamp_TileMode, so we simulate it by making
1523        // a pattern the size of the current clip.
1524        SkIRect bounds = clipRegion.getBounds();
1525
1526        // We need to apply the initial transform to bounds in order to get
1527        // bounds in a consistent coordinate system.
1528        SkRect boundsTemp;
1529        boundsTemp.set(bounds);
1530        fInitialTransform.mapRect(&boundsTemp);
1531        boundsTemp.roundOut(&bounds);
1532
1533        pdfShader.reset(SkPDFShader::GetPDFShader(*shader, transform, bounds));
1534
1535        if (pdfShader.get()) {
1536            // pdfShader has been canonicalized so we can directly compare
1537            // pointers.
1538            int resourceIndex = fShaderResources.find(pdfShader.get());
1539            if (resourceIndex < 0) {
1540                resourceIndex = fShaderResources.count();
1541                fShaderResources.push(pdfShader.get());
1542                pdfShader.get()->ref();
1543            }
1544            entry->fShaderIndex = resourceIndex;
1545        } else {
1546            // A color shader is treated as an invalid shader so we don't have
1547            // to set a shader just for a color.
1548            SkShader::GradientInfo gradientInfo;
1549            SkColor gradientColor;
1550            gradientInfo.fColors = &gradientColor;
1551            gradientInfo.fColorOffsets = NULL;
1552            gradientInfo.fColorCount = 1;
1553            if (shader->asAGradient(&gradientInfo) ==
1554                    SkShader::kColor_GradientType) {
1555                entry->fColor = SkColorSetA(gradientColor, 0xFF);
1556                color = gradientColor;
1557            }
1558        }
1559    }
1560
1561    SkAutoTUnref<SkPDFGraphicState> newGraphicState;
1562    if (color == paint.getColor()) {
1563        newGraphicState.reset(
1564                SkPDFGraphicState::GetGraphicStateForPaint(paint));
1565    } else {
1566        SkPaint newPaint = paint;
1567        newPaint.setColor(color);
1568        newGraphicState.reset(
1569                SkPDFGraphicState::GetGraphicStateForPaint(newPaint));
1570    }
1571    int resourceIndex = addGraphicStateResource(newGraphicState.get());
1572    entry->fGraphicStateIndex = resourceIndex;
1573
1574    if (hasText) {
1575        entry->fTextScaleX = paint.getTextScaleX();
1576        entry->fTextFill = paint.getStyle();
1577    } else {
1578        entry->fTextScaleX = 0;
1579    }
1580}
1581
1582int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) {
1583    // Assumes that gs has been canonicalized (so we can directly compare
1584    // pointers).
1585    int result = fGraphicStateResources.find(gs);
1586    if (result < 0) {
1587        result = fGraphicStateResources.count();
1588        fGraphicStateResources.push(gs);
1589        gs->ref();
1590    }
1591    return result;
1592}
1593
1594void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
1595                             ContentEntry* contentEntry) {
1596    SkTypeface* typeface = paint.getTypeface();
1597    if (contentEntry->fState.fFont == NULL ||
1598            contentEntry->fState.fTextSize != paint.getTextSize() ||
1599            !contentEntry->fState.fFont->hasGlyph(glyphID)) {
1600        int fontIndex = getFontResourceIndex(typeface, glyphID);
1601        contentEntry->fContent.writeText("/F");
1602        contentEntry->fContent.writeDecAsText(fontIndex);
1603        contentEntry->fContent.writeText(" ");
1604        SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent);
1605        contentEntry->fContent.writeText(" Tf\n");
1606        contentEntry->fState.fFont = fFontResources[fontIndex];
1607    }
1608}
1609
1610int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
1611    SkAutoTUnref<SkPDFFont> newFont(SkPDFFont::GetFontResource(typeface, glyphID));
1612    int resourceIndex = fFontResources.find(newFont.get());
1613    if (resourceIndex < 0) {
1614        resourceIndex = fFontResources.count();
1615        fFontResources.push(newFont.get());
1616        newFont.get()->ref();
1617    }
1618    return resourceIndex;
1619}
1620
1621void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
1622                                     const SkClipStack* clipStack,
1623                                     const SkRegion& clipRegion,
1624                                     const SkBitmap& bitmap,
1625                                     const SkIRect* srcRect,
1626                                     const SkPaint& paint) {
1627    SkMatrix scaled;
1628    // Adjust for origin flip.
1629    scaled.setScale(SK_Scalar1, -SK_Scalar1);
1630    scaled.postTranslate(0, SK_Scalar1);
1631    // Scale the image up from 1x1 to WxH.
1632    SkIRect subset = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1633    scaled.postScale(SkIntToScalar(subset.width()),
1634                     SkIntToScalar(subset.height()));
1635    scaled.postConcat(matrix);
1636    ScopedContentEntry content(this, clipStack, clipRegion, scaled, paint);
1637    if (!content.entry()) {
1638        return;
1639    }
1640
1641    if (srcRect && !subset.intersect(*srcRect)) {
1642        return;
1643    }
1644
1645    SkPDFImage* image = SkPDFImage::CreateImage(bitmap, subset, paint);
1646    if (!image) {
1647        return;
1648    }
1649
1650    fXObjectResources.push(image);  // Transfer reference.
1651    SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
1652                                &content.entry()->fContent);
1653}
1654
1655bool SkPDFDevice::onReadPixels(const SkBitmap& bitmap, int x, int y,
1656                               SkCanvas::Config8888) {
1657    return false;
1658}
1659
1660bool SkPDFDevice::allowImageFilter(SkImageFilter*) {
1661    return false;
1662}
1663