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