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