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