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