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