SkPDFDevice.cpp revision 13d14a9dbd2cf0a9654045cc967e92626690631a
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 2011 Google Inc.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License");
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * you may not use this file except in compliance with the License.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You may obtain a copy of the License at
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *      http://www.apache.org/licenses/LICENSE-2.0
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS,
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See the License for the specific language governing permissions and
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * limitations under the License.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFDevice.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkColor.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkClipStack.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkDraw.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkGlyphCache.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "SkPaint.h"
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "SkPath.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFFont.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFFormXObject.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFGraphicState.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFImage.h"
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkPDFShader.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFStream.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFTypes.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPDFUtils.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkRect.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkString.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkTextFormatParams.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkTypeface.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkTypes.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Utility functions
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void emit_pdf_color(SkColor color, SkWStream* result) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkASSERT(SkColorGetA(color) == 0xFF);  // We handle alpha elsewhere.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkScalar colorMax = SkIntToScalar(0xFF);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFScalar::Append(
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->writeText(" ");
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFScalar::Append(
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->writeText(" ");
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFScalar::Append(
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), result);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->writeText(" ");
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SkPaint calculate_text_paint(const SkPaint& paint) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPaint result = paint;
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (result.isFakeBoldText()) {
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    kStdFakeBoldInterpKeys,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    kStdFakeBoldInterpValues,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    kStdFakeBoldInterpLength);
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (result.getStyle() == SkPaint::kFill_Style)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            result.setStyle(SkPaint::kStrokeAndFill_Style);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            width += result.getStrokeWidth();
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        result.setStrokeWidth(width);
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return result;
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Stolen from measure_text in SkDraw.cpp and then tweaked.
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       const uint16_t* glyphs, size_t len, SkScalar* x,
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                       SkScalar* y, SkScalar* width) {
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (paint.getTextAlign() == SkPaint::kLeft_Align && width == NULL)
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return;
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    SkMatrix ident;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ident.reset();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkAutoGlyphCache autoCache(paint, &ident);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkGlyphCache* cache = autoCache.getCache();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* start = (char*)glyphs;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* stop = (char*)(glyphs + len);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkFixed xAdv = 0, yAdv = 0;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(vandebo) This probably needs to take kerning into account.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (start < stop) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        xAdv += glyph.fAdvanceX;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        yAdv += glyph.fAdvanceY;
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    };
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (width)
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        *width = SkFixedToScalar(xAdv);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (paint.getTextAlign() == SkPaint::kLeft_Align)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkScalar xAdj = SkFixedToScalar(xAdv);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkScalar yAdj = SkFixedToScalar(yAdv);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        xAdj = SkScalarHalf(xAdj);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        yAdj = SkScalarHalf(yAdj);
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    *x = *x - xAdj;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *y = *y - yAdj;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               SkWStream* content) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Flip the text about the x-axis to account for origin swap and include
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the passed parameters.
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    content->writeText("1 0 ");
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFScalar::Append(0 - textSkewX, content);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content->writeText(" -1 ");
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFScalar::Append(x, content);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content->writeText(" ");
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFScalar::Append(y, content);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content->writeText(" Tm\n");
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// later being our representation of an object in the PDF file.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct GraphicStateEntry {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GraphicStateEntry();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Compare the fields we care about when setting up a new content entry.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool compareInitialState(const GraphicStateEntry& b);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkMatrix fMatrix;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We can't do set operations on Paths, though PDF natively supports
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // intersect.  If the clip stack does anything other than intersect,
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // we have to fall back to the region.  Treat fClipStack as authoritative.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // See http://code.google.com/p/skia/issues/detail?id=221
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkClipStack fClipStack;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkRegion fClipRegion;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // When emitting the content entry, we will ensure the graphic state
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is set to these values first.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkColor fColor;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkScalar fTextScaleX;  // Zero means we don't care what the value is.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPaint::Style fTextFill;  // Only if TextScaleX is non-zero.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int fShaderIndex;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int fGraphicStateIndex;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We may change the font (i.e. for Type1 support) within a
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ContentEntry.  This is the one currently in effect, or NULL if none.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFFont* fFont;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // In PDF, text size has no default value. It is only valid if fFont is
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // not NULL.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkScalar fTextSize;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK),
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         fTextScaleX(SK_Scalar1),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         fTextFill(SkPaint::kFill_Style),
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         fShaderIndex(-1),
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         fGraphicStateIndex(-1),
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         fFont(NULL),
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         fTextSize(SK_ScalarNaN) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fMatrix.reset();
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GraphicStateEntry::compareInitialState(const GraphicStateEntry& b) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return fColor == b.fColor &&
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           fShaderIndex == b.fShaderIndex &&
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           fGraphicStateIndex == b.fGraphicStateIndex &&
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           fMatrix == b.fMatrix &&
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           fClipStack == b.fClipStack &&
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               (fTextScaleX == 0 ||
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                b.fTextScaleX == 0 ||
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                (fTextScaleX == b.fTextScaleX && fTextFill == b.fTextFill));
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GraphicStackState {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public:
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GraphicStackState(const SkClipStack& existingClipStack,
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      const SkRegion& existingClipRegion,
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      SkWStream* contentStream)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            : fStackDepth(0),
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              fContentStream(contentStream) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fEntries[0].fClipStack = existingClipStack;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fEntries[0].fClipRegion = existingClipRegion;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    const SkIPoint& translation);
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void updateMatrix(const SkMatrix& matrix);
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void updateDrawingState(const GraphicStateEntry& state);
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void drainStack();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private:
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void push();
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void pop();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Conservative limit on save depth, see impl. notes in PDF 1.4 spec.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const int kMaxStackDepth = 12;
200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    GraphicStateEntry fEntries[kMaxStackDepth + 1];
201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int fStackDepth;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkWStream* fContentStream;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::drainStack() {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (fStackDepth) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pop();
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::push() {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkASSERT(fStackDepth < kMaxStackDepth);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fContentStream->writeText("q\n");
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fStackDepth++;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fEntries[fStackDepth] = fEntries[fStackDepth - 1];
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::pop() {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkASSERT(fStackDepth > 0);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fContentStream->writeText("Q\n");
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    fStackDepth--;
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This function initializes iter to be an interator on the "stack" argument
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// and then skips over the leading entries as specified in prefix.  It requires
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and asserts that "prefix" will be a prefix to "stack."
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void skip_clip_stack_prefix(const SkClipStack& prefix,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const SkClipStack& stack,
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                   SkClipStack::B2FIter* iter) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkClipStack::B2FIter prefixIter(prefix);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iter->reset(stack);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SkClipStack::B2FIter::Clip* prefixEntry;
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const SkClipStack::B2FIter::Clip* iterEntry;
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (prefixEntry = prefixIter.next(); prefixEntry;
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            prefixEntry = prefixIter.next()) {
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        iterEntry = iter->next();
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        SkASSERT(iterEntry);
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        SkASSERT(*prefixEntry == *iterEntry);
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SkASSERT(prefixEntry == NULL);
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void emit_clip(SkPath* clipPath, SkRect* clipRect,
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      SkWStream* contentStream) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkASSERT(clipPath || clipRect);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPath::FillType clipFill;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (clipPath) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkPDFUtils::EmitPath(*clipPath, contentStream);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        clipFill = clipPath->getFillType();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (clipRect) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkPDFUtils::AppendRectangle(*clipRect, contentStream);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        clipFill = SkPath::kWinding_FillType;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (clipFill == SkPath::kEvenOdd_FillType) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contentStream->writeText("W* n\n");
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contentStream->writeText("W n\n");
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(vandebo) Take advantage of SkClipStack::getSaveCount(), the PDF
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// graphic state stack, and the fact that we can know all the clips used
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on the page to optimize this.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::updateClip(const SkClipStack& clipStack,
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const SkRegion& clipRegion,
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const SkIPoint& translation) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (clipStack == currentEntry()->fClipStack) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (fStackDepth > 0) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pop();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (clipStack == currentEntry()->fClipStack) {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    push();
285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // gsState->initialEntry()->fClipStack/Region specifies the clip that has
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // already been applied.  (If this is a top level device, then it specifies
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    // a clip to the content area.  If this is a layer, then it specifies
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the clip in effect when the layer was created.)  There's no need to
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // initial clip on the parent layer.  (This means there's a bug if the user
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // expands the clip and then uses any xfer mode that uses dst:
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // http://code.google.com/p/skia/issues/detail?id=228 )
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkClipStack::B2FIter iter;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the clip stack does anything other than intersect or if it uses
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // an inverse fill type, we have to fall back to the clip region.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool needRegion = false;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SkClipStack::B2FIter::Clip* clipEntry;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (clipEntry->fOp != SkRegion::kIntersect_Op ||
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                (clipEntry->fPath && clipEntry->fPath->isInverseFillType())) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            needRegion = true;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            break;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (needRegion) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkPath clipPath;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkAssertResult(clipRegion.getBoundaryPath(&clipPath));
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        emit_clip(&clipPath, NULL, fContentStream);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkMatrix transform;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        transform.setTranslate(translation.fX, translation.fY);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const SkClipStack::B2FIter::Clip* clipEntry;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SkASSERT(clipEntry->fOp == SkRegion::kIntersect_Op);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (clipEntry->fRect) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                SkRect translatedClip;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                transform.mapRect(&translatedClip, *clipEntry->fRect);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                emit_clip(NULL, &translatedClip, fContentStream);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            } else if (clipEntry->fPath) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                SkPath translatedPath;
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                clipEntry->fPath->transform(transform, &translatedPath);
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                emit_clip(&translatedPath, NULL, fContentStream);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            } else {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                SkASSERT(false);
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            }
33123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        }
33223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    }
33323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    currentEntry()->fClipStack = clipStack;
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    currentEntry()->fClipRegion = clipRegion;
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GraphicStackState::updateMatrix(const SkMatrix& matrix) {
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (matrix == currentEntry()->fMatrix) {
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return;
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) {
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        SkASSERT(fStackDepth > 0);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkASSERT(fEntries[fStackDepth].fClipStack ==
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 fEntries[fStackDepth -1].fClipStack);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pop();
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (matrix.getType() == SkMatrix::kIdentity_Mask) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    push();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFUtils::AppendTransform(matrix, fContentStream);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    currentEntry()->fMatrix = matrix;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // PDF treats a shader as a color, so we only set one or the other.
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (state.fShaderIndex >= 0) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (state.fShaderIndex != currentEntry()->fShaderIndex) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeText("/Pattern CS /Pattern cs /P");
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeDecAsText(state.fShaderIndex);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeText(" SCN /P");
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeDecAsText(state.fShaderIndex);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeText(" scn\n");
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            currentEntry()->fShaderIndex = state.fShaderIndex;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (state.fColor != currentEntry()->fColor ||
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                currentEntry()->fShaderIndex >= 0) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            emit_pdf_color(state.fColor, fContentStream);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeText("RG ");
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            emit_pdf_color(state.fColor, fContentStream);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeText("rg\n");
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            currentEntry()->fColor = state.fColor;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            currentEntry()->fShaderIndex = -1;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream);
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (state.fTextScaleX) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (state.fTextScaleX != currentEntry()->fTextScaleX) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SkScalar pdfScale = SkScalarMul(state.fTextScaleX,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            SkIntToScalar(100));
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SkPDFScalar::Append(pdfScale, fContentStream);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeText(" Tz\n");
393010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            currentEntry()->fTextScaleX = state.fTextScaleX;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (state.fTextFill != currentEntry()->fTextFill) {
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value);
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1,
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              enum_must_match_value);
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              enum_must_match_value);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeDecAsText(state.fTextFill);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fContentStream->writeText(" Tr\n");
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            currentEntry()->fTextFill = state.fTextFill;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)struct ContentEntry {
409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    GraphicStateEntry fState;
410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SkDynamicMemoryWStream fContent;
411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SkTScopedPtr<ContentEntry> fNext;
412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
414a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// A helper class to automatically finish a ContentEntry at the end of a
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// drawing method and maintain the state needed between set up and finish.
416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class ScopedContentEntry {
417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)public:
418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw,
419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                       const SkPaint& paint, bool hasText = false)
420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        : fDevice(device),
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          fContentEntry(NULL),
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          fXfermode(SkXfermode::kSrcOver_Mode) {
423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText);
424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack,
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const SkRegion& clipRegion, const SkMatrix& matrix,
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const SkPaint& paint, bool hasText = false)
428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        : fDevice(device),
429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          fContentEntry(NULL),
430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          fXfermode(SkXfermode::kSrcOver_Mode) {
431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        init(clipStack, clipRegion, matrix, paint, hasText);
432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
434a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ~ScopedContentEntry() {
435a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (fContentEntry) {
436a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            fDevice->finishContentEntry(fXfermode, fDstFormXObject.get());
437a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        }
438a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
439a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
440a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ContentEntry* entry() { return fContentEntry; }
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private:
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFDevice* fDevice;
443a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ContentEntry* fContentEntry;
444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SkXfermode::Mode fXfermode;
445a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SkRefPtr<SkPDFFormXObject> fDstFormXObject;
446a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)              const SkMatrix& matrix, const SkPaint& paint, bool hasText) {
449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (paint.getXfermode()) {
450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            paint.getXfermode()->asMode(&fXfermode);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion,
453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                   matrix, paint, hasText,
454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                   &fDstFormXObject);
455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
458a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
459a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
460a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)SkDevice* SkPDFDeviceFactory::newDevice(SkCanvas* c, SkBitmap::Config config,
461a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                        int width, int height, bool isOpaque,
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        bool isForLayer) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkMatrix initialTransform;
464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    initialTransform.reset();
465a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SkISize size = SkISize::Make(width, height);
466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (isForLayer) {
467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return SkNEW_ARGS(SkPDFDevice, (size, c->getTotalClipStack(),
468a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                        c->getTotalClip()));
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform));
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static inline SkBitmap makeContentBitmap(const SkISize& contentSize,
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const SkMatrix* initialTransform) {
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkBitmap bitmap;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (initialTransform) {
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Compute the size of the drawing area.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkVector drawingSize;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkMatrix inverse;
481cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        drawingSize.set(contentSize.fWidth, contentSize.fHeight);
482cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        initialTransform->invert(&inverse);
483cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        inverse.mapVectors(&drawingSize, 1);
484cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound();
485cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        bitmap.setConfig(SkBitmap::kNo_Config, abs(size.fWidth),
486cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         abs(size.fHeight));
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bitmap.setConfig(SkBitmap::kNo_Config, abs(contentSize.fWidth),
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         abs(contentSize.fHeight));
490cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
491cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
492cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return bitmap;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
494cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
495cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const SkMatrix& initialTransform)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : SkDevice(NULL, makeContentBitmap(contentSize, &initialTransform), false),
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fPageSize(pageSize),
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fContentSize(contentSize),
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fLastContentEntry(NULL) {
501cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Skia generally uses the top left as the origin but PDF natively has the
502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // origin at the bottom left. This matrix corrects for that.  But that only
503cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // needs to be done once, we don't do it when layering.
504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fInitialTransform.setTranslate(0, pageSize.fHeight);
505cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fInitialTransform.preScale(1, -1);
506cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fInitialTransform.preConcat(initialTransform);
507cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
508cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    SkIRect existingClip = SkIRect::MakeWH(this->width(), this->height());
509cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fExistingClipStack.clipDevRect(existingClip);
510cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fExistingClipRegion.setRect(existingClip);
511cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this->init();
513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
516cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         const SkClipStack& existingClipStack,
517cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         const SkRegion& existingClipRegion)
518cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : SkDevice(NULL, makeContentBitmap(layerSize, NULL), false),
519cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      fPageSize(layerSize),
520cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      fContentSize(layerSize),
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fExistingClipStack(existingClipStack),
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fExistingClipRegion(existingClipRegion),
523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      fLastContentEntry(NULL) {
524cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fInitialTransform.reset();
525cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this->init();
526cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
527cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkPDFDevice::~SkPDFDevice() {
529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    this->cleanUp();
530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
532cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SkPDFDevice::init() {
533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fResourceDict = NULL;
534cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fContentEntries.reset();
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fLastContentEntry = NULL;
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkDeviceFactory* SkPDFDevice::onNewDeviceFactory() {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SkNEW(SkPDFDeviceFactory);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SkPDFDevice::cleanUp() {
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fGraphicStateResources.unrefAll();
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fXObjectResources.unrefAll();
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fFontResources.unrefAll();
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fShaderResources.unrefAll();
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SkPDFDevice::clear(SkColor color) {
550010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    this->cleanUp();
551010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    this->init();
552010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPaint paint;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint.setColor(color);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    paint.setStyle(SkPaint::kFill_Style);
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SkMatrix identity;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    identity.reset();
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion,
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               identity, paint);
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internalDrawPaint(paint, content.entry());
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
564cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    SkPaint newPaint = paint;
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    newPaint.setStyle(SkPaint::kFill_Style);
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedContentEntry content(this, d, newPaint);
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    internalDrawPaint(newPaint, content.entry());
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkPDFDevice::internalDrawPaint(const SkPaint& paint,
5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    ContentEntry* contentEntry) {
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!contentEntry) {
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()),
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 SkIntToScalar(this->height()));
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkMatrix totalTransform = fInitialTransform;
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    totalTransform.preConcat(contentEntry->fState.fMatrix);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkMatrix inverse;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inverse.reset();
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    totalTransform.invert(&inverse);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inverse.mapRect(&bbox);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &contentEntry->fContent);
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             size_t count, const SkPoint* points,
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             const SkPaint& passedPaint) {
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (count == 0) {
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return;
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath.
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We only use this when there's a path effect because of the overhead
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // of multiple calls to setUpContentEntry it causes.
599cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (passedPaint.getPathEffect()) {
600cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (d.fClip->isEmpty()) {
601cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            return;
602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
603cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        SkDraw pointDraw(d);
604cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pointDraw.fDevice = this;
605cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pointDraw.drawPoints(mode, count, points, passedPaint, true);
606cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        return;
607cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
608cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
609cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const SkPaint* paint = &passedPaint;
610cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    SkPaint modifiedPaint;
611cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
612cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (mode == SkCanvas::kPoints_PointMode &&
613cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            paint->getStrokeCap() != SkPaint::kRound_Cap) {
614cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        modifiedPaint = *paint;
615cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        paint = &modifiedPaint;
616cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        if (paint->getStrokeWidth()) {
617cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            // PDF won't draw a single point with square/butt caps because the
618cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            // orientation is ambiguous.  Draw a rectangle instead.
619cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            modifiedPaint.setStyle(SkPaint::kFill_Style);
620cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            SkScalar strokeWidth = paint->getStrokeWidth();
621cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            SkScalar halfStroke = SkScalarHalf(strokeWidth);
622cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            for (size_t i = 0; i < count; i++) {
623cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0);
624cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                r.inset(-halfStroke, -halfStroke);
625cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                drawRect(d, r, modifiedPaint);
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
627            return;
628        } else {
629            modifiedPaint.setStrokeCap(SkPaint::kRound_Cap);
630        }
631    }
632
633    ScopedContentEntry content(this, d, *paint);
634    if (!content.entry()) {
635        return;
636    }
637
638    switch (mode) {
639        case SkCanvas::kPolygon_PointMode:
640            SkPDFUtils::MoveTo(points[0].fX, points[0].fY,
641                               &content.entry()->fContent);
642            for (size_t i = 1; i < count; i++) {
643                SkPDFUtils::AppendLine(points[i].fX, points[i].fY,
644                                       &content.entry()->fContent);
645            }
646            SkPDFUtils::StrokePath(&content.entry()->fContent);
647            break;
648        case SkCanvas::kLines_PointMode:
649            for (size_t i = 0; i < count/2; i++) {
650                SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY,
651                                   &content.entry()->fContent);
652                SkPDFUtils::AppendLine(points[i * 2 + 1].fX,
653                                       points[i * 2 + 1].fY,
654                                       &content.entry()->fContent);
655                SkPDFUtils::StrokePath(&content.entry()->fContent);
656            }
657            break;
658        case SkCanvas::kPoints_PointMode:
659            SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap);
660            for (size_t i = 0; i < count; i++) {
661                SkPDFUtils::MoveTo(points[i].fX, points[i].fY,
662                                   &content.entry()->fContent);
663                SkPDFUtils::ClosePath(&content.entry()->fContent);
664                SkPDFUtils::StrokePath(&content.entry()->fContent);
665            }
666            break;
667        default:
668            SkASSERT(false);
669    }
670}
671
672void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r,
673                           const SkPaint& paint) {
674    if (paint.getPathEffect()) {
675        if (d.fClip->isEmpty()) {
676            return;
677        }
678        SkPath path;
679        path.addRect(r);
680        drawPath(d, path, paint, NULL, true);
681        return;
682    }
683
684    ScopedContentEntry content(this, d, paint);
685    if (!content.entry()) {
686        return;
687    }
688    SkPDFUtils::AppendRectangle(r, &content.entry()->fContent);
689    SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
690                          &content.entry()->fContent);
691}
692
693void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
694                           const SkPaint& paint, const SkMatrix* prePathMatrix,
695                           bool pathIsMutable) {
696    SkPath modifiedPath;
697    SkPath* pathPtr = const_cast<SkPath*>(&origPath);
698
699    SkMatrix matrix = *d.fMatrix;
700    if (prePathMatrix) {
701        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
702            if (!pathIsMutable) {
703                pathPtr = &modifiedPath;
704                pathIsMutable = true;
705            }
706            origPath.transform(*prePathMatrix, pathPtr);
707        } else {
708            if (!matrix.preConcat(*prePathMatrix)) {
709                return;
710            }
711        }
712    }
713
714    if (paint.getPathEffect()) {
715        if (d.fClip->isEmpty()) {
716            return;
717        }
718        if (!pathIsMutable) {
719            pathPtr = &modifiedPath;
720            pathIsMutable = true;
721        }
722        bool fill = paint.getFillPath(origPath, pathPtr);
723
724        SkPaint noEffectPaint(paint);
725        noEffectPaint.setPathEffect(NULL);
726        if (fill) {
727            noEffectPaint.setStyle(SkPaint::kFill_Style);
728        } else {
729            noEffectPaint.setStyle(SkPaint::kStroke_Style);
730            noEffectPaint.setStrokeWidth(0);
731        }
732        drawPath(d, *pathPtr, noEffectPaint, NULL, true);
733        return;
734    }
735
736    ScopedContentEntry content(this, d, paint);
737    if (!content.entry()) {
738        return;
739    }
740    SkPDFUtils::EmitPath(*pathPtr, &content.entry()->fContent);
741    SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
742                          &content.entry()->fContent);
743}
744
745void SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
746                             const SkIRect* srcRect, const SkMatrix& matrix,
747                             const SkPaint& paint) {
748    if (d.fClip->isEmpty()) {
749        return;
750    }
751
752    SkMatrix transform = matrix;
753    transform.postConcat(*d.fMatrix);
754    internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, srcRect,
755                       paint);
756}
757
758void SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap,
759                             int x, int y, const SkPaint& paint) {
760    if (d.fClip->isEmpty()) {
761        return;
762    }
763
764    SkMatrix matrix;
765    matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
766    internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL, paint);
767}
768
769void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
770                           SkScalar x, SkScalar y, const SkPaint& paint) {
771    SkPaint textPaint = calculate_text_paint(paint);
772    ScopedContentEntry content(this, d, textPaint, true);
773    if (!content.entry()) {
774        return;
775    }
776
777    // We want the text in glyph id encoding and a writable buffer, so we end
778    // up making a copy either way.
779    size_t numGlyphs = paint.textToGlyphs(text, len, NULL);
780    uint16_t* glyphIDs =
781        (uint16_t*)sk_malloc_flags(numGlyphs * 2,
782                                   SK_MALLOC_TEMP | SK_MALLOC_THROW);
783    SkAutoFree autoFreeGlyphIDs(glyphIDs);
784    if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
785        paint.textToGlyphs(text, len, glyphIDs);
786        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
787    } else {
788        SkASSERT((len & 1) == 0);
789        SkASSERT(len / 2 == numGlyphs);
790        memcpy(glyphIDs, text, len);
791    }
792
793    SkScalar width;
794    SkScalar* widthPtr = NULL;
795    if (textPaint.isUnderlineText() || textPaint.isStrikeThruText())
796        widthPtr = &width;
797
798    SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
799    align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y,
800               widthPtr);
801    content.entry()->fContent.writeText("BT\n");
802    set_text_transform(x, y, textPaint.getTextSkewX(),
803                       &content.entry()->fContent);
804    size_t consumedGlyphCount = 0;
805    while (numGlyphs > consumedGlyphCount) {
806        updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry());
807        SkPDFFont* font = content.entry()->fState.fFont;
808        size_t availableGlyphs =
809            font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount,
810                                          numGlyphs - consumedGlyphCount);
811        SkString encodedString =
812            SkPDFString::formatString(glyphIDs + consumedGlyphCount,
813                                      availableGlyphs, font->multiByteGlyphs());
814        content.entry()->fContent.writeText(encodedString.c_str());
815        consumedGlyphCount += availableGlyphs;
816        content.entry()->fContent.writeText(" Tj\n");
817    }
818    content.entry()->fContent.writeText("ET\n");
819
820    // Draw underline and/or strikethrough if the paint has them.
821    // drawPosText() and drawTextOnPath() don't draw underline or strikethrough
822    // because the raster versions don't.  Use paint instead of textPaint
823    // because we may have changed strokeWidth to do fakeBold text.
824    if (paint.isUnderlineText() || paint.isStrikeThruText()) {
825        SkScalar textSize = paint.getTextSize();
826        SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
827
828        if (paint.isUnderlineText()) {
829            SkScalar top = SkScalarMulAdd(textSize, kStdUnderline_Offset, y);
830            SkRect r = SkRect::MakeXYWH(x, top - height, width, height);
831            drawRect(d, r, paint);
832        }
833        if (paint.isStrikeThruText()) {
834            SkScalar top = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, y);
835            SkRect r = SkRect::MakeXYWH(x, top - height, width, height);
836            drawRect(d, r, paint);
837        }
838    }
839}
840
841void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
842                              const SkScalar pos[], SkScalar constY,
843                              int scalarsPerPos, const SkPaint& paint) {
844    SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
845    SkPaint textPaint = calculate_text_paint(paint);
846    ScopedContentEntry content(this, d, textPaint, true);
847    if (!content.entry()) {
848        return;
849    }
850
851    // Make sure we have a glyph id encoding.
852    SkAutoFree glyphStorage;
853    uint16_t* glyphIDs;
854    size_t numGlyphs;
855    if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
856        numGlyphs = paint.textToGlyphs(text, len, NULL);
857        glyphIDs = (uint16_t*)sk_malloc_flags(numGlyphs * 2,
858                                              SK_MALLOC_TEMP | SK_MALLOC_THROW);
859        glyphStorage.set(glyphIDs);
860        paint.textToGlyphs(text, len, glyphIDs);
861        textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
862    } else {
863        SkASSERT((len & 1) == 0);
864        numGlyphs = len / 2;
865        glyphIDs = (uint16_t*)text;
866    }
867
868    SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
869    content.entry()->fContent.writeText("BT\n");
870    updateFont(textPaint, glyphIDs[0], content.entry());
871    for (size_t i = 0; i < numGlyphs; i++) {
872        SkPDFFont* font = content.entry()->fState.fFont;
873        uint16_t encodedValue = glyphIDs[i];
874        if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
875            updateFont(textPaint, glyphIDs[i], content.entry());
876            i--;
877            continue;
878        }
879        SkScalar x = pos[i * scalarsPerPos];
880        SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
881        align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL);
882        set_text_transform(x, y, textPaint.getTextSkewX(),
883                           &content.entry()->fContent);
884        SkString encodedString =
885            SkPDFString::formatString(&encodedValue, 1,
886                                      font->multiByteGlyphs());
887        content.entry()->fContent.writeText(encodedString.c_str());
888        content.entry()->fContent.writeText(" Tj\n");
889    }
890    content.entry()->fContent.writeText("ET\n");
891}
892
893void SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
894                                 const SkPath& path, const SkMatrix* matrix,
895                                 const SkPaint& paint) {
896    if (d.fClip->isEmpty()) {
897        return;
898    }
899    NOT_IMPLEMENTED("drawTextOnPath", true);
900}
901
902void SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode,
903                               int vertexCount, const SkPoint verts[],
904                               const SkPoint texs[], const SkColor colors[],
905                               SkXfermode* xmode, const uint16_t indices[],
906                               int indexCount, const SkPaint& paint) {
907    if (d.fClip->isEmpty()) {
908        return;
909    }
910    NOT_IMPLEMENTED("drawVerticies", true);
911}
912
913void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
914                             const SkPaint& paint) {
915    if ((device->getDeviceCapabilities() & kVector_Capability) == 0) {
916        // If we somehow get a raster device, do what our parent would do.
917        SkDevice::drawDevice(d, device, x, y, paint);
918        return;
919    }
920
921    // Assume that a vector capable device means that it's a PDF Device.
922    SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device);
923    if (pdfDevice->isContentEmpty()) {
924        return;
925    }
926
927    SkMatrix matrix;
928    matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
929    ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
930    if (!content.entry()) {
931        return;
932    }
933
934    SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
935    fXObjectResources.push(xobject);  // Transfer reference.
936    SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
937                                &content.entry()->fContent);
938}
939
940const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
941    if (fResourceDict.get() == NULL) {
942        fResourceDict = new SkPDFDict;
943        fResourceDict->unref();  // SkRefPtr and new both took a reference.
944
945        if (fGraphicStateResources.count()) {
946            SkRefPtr<SkPDFDict> extGState = new SkPDFDict();
947            extGState->unref();  // SkRefPtr and new both took a reference.
948            for (int i = 0; i < fGraphicStateResources.count(); i++) {
949                SkString nameString("G");
950                nameString.appendS32(i);
951                extGState->insert(
952                        nameString.c_str(),
953                        new SkPDFObjRef(fGraphicStateResources[i]))->unref();
954            }
955            fResourceDict->insert("ExtGState", extGState.get());
956        }
957
958        if (fXObjectResources.count()) {
959            SkRefPtr<SkPDFDict> xObjects = new SkPDFDict();
960            xObjects->unref();  // SkRefPtr and new both took a reference.
961            for (int i = 0; i < fXObjectResources.count(); i++) {
962                SkString nameString("X");
963                nameString.appendS32(i);
964                xObjects->insert(
965                        nameString.c_str(),
966                        new SkPDFObjRef(fXObjectResources[i]))->unref();
967            }
968            fResourceDict->insert("XObject", xObjects.get());
969        }
970
971        if (fFontResources.count()) {
972            SkRefPtr<SkPDFDict> fonts = new SkPDFDict();
973            fonts->unref();  // SkRefPtr and new both took a reference.
974            for (int i = 0; i < fFontResources.count(); i++) {
975                SkString nameString("F");
976                nameString.appendS32(i);
977                fonts->insert(nameString.c_str(),
978                              new SkPDFObjRef(fFontResources[i]))->unref();
979            }
980            fResourceDict->insert("Font", fonts.get());
981        }
982
983        if (fShaderResources.count()) {
984            SkRefPtr<SkPDFDict> patterns = new SkPDFDict();
985            patterns->unref();  // SkRefPtr and new both took a reference.
986            for (int i = 0; i < fShaderResources.count(); i++) {
987                SkString nameString("P");
988                nameString.appendS32(i);
989                patterns->insert(nameString.c_str(),
990                                 new SkPDFObjRef(fShaderResources[i]))->unref();
991            }
992            fResourceDict->insert("Pattern", patterns.get());
993        }
994
995        // For compatibility, add all proc sets (only used for output to PS
996        // devices).
997        const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"};
998        SkRefPtr<SkPDFArray> procSets = new SkPDFArray();
999        procSets->unref();  // SkRefPtr and new both took a reference.
1000        procSets->reserve(SK_ARRAY_COUNT(procs));
1001        for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++)
1002            procSets->append(new SkPDFName(procs[i]))->unref();
1003        fResourceDict->insert("ProcSet", procSets.get());
1004    }
1005    return fResourceDict;
1006}
1007
1008void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList) const {
1009    resourceList->setReserve(resourceList->count() +
1010                             fGraphicStateResources.count() +
1011                             fXObjectResources.count() +
1012                             fFontResources.count() +
1013                             fShaderResources.count());
1014    for (int i = 0; i < fGraphicStateResources.count(); i++) {
1015        resourceList->push(fGraphicStateResources[i]);
1016        fGraphicStateResources[i]->ref();
1017        fGraphicStateResources[i]->getResources(resourceList);
1018    }
1019    for (int i = 0; i < fXObjectResources.count(); i++) {
1020        resourceList->push(fXObjectResources[i]);
1021        fXObjectResources[i]->ref();
1022        fXObjectResources[i]->getResources(resourceList);
1023    }
1024    for (int i = 0; i < fFontResources.count(); i++) {
1025        resourceList->push(fFontResources[i]);
1026        fFontResources[i]->ref();
1027        fFontResources[i]->getResources(resourceList);
1028    }
1029    for (int i = 0; i < fShaderResources.count(); i++) {
1030        resourceList->push(fShaderResources[i]);
1031        fShaderResources[i]->ref();
1032        fShaderResources[i]->getResources(resourceList);
1033    }
1034}
1035
1036SkRefPtr<SkPDFArray> SkPDFDevice::getMediaBox() const {
1037    SkRefPtr<SkPDFInt> zero = new SkPDFInt(0);
1038    zero->unref();  // SkRefPtr and new both took a reference.
1039
1040    SkRefPtr<SkPDFArray> mediaBox = new SkPDFArray();
1041    mediaBox->unref();  // SkRefPtr and new both took a reference.
1042    mediaBox->reserve(4);
1043    mediaBox->append(zero.get());
1044    mediaBox->append(zero.get());
1045    mediaBox->append(new SkPDFInt(fPageSize.fWidth))->unref();
1046    mediaBox->append(new SkPDFInt(fPageSize.fHeight))->unref();
1047    return mediaBox;
1048}
1049
1050SkStream* SkPDFDevice::content() const {
1051    SkDynamicMemoryWStream data;
1052    if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
1053        SkPDFUtils::AppendTransform(fInitialTransform, &data);
1054    }
1055    // If the content area is the entire page, then we don't need to clip
1056    // the content area (PDF area clips to the page size).  Otherwise,
1057    // we have to clip to the content area; we've already applied the
1058    // initial transform, so just clip to the device size.
1059    if (fPageSize != fContentSize) {
1060        SkRect r = SkRect::MakeWH(this->width(), this->height());
1061        emit_clip(NULL, &r, &data);
1062    }
1063
1064    GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, &data);
1065    for (ContentEntry* entry = fContentEntries.get();
1066            entry != NULL;
1067            entry = entry->fNext.get()) {
1068        SkIPoint translation = this->getOrigin();
1069        translation.negate();
1070        gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
1071                           translation);
1072        gsState.updateMatrix(entry->fState.fMatrix);
1073        gsState.updateDrawingState(entry->fState);
1074        data.write(entry->fContent.getStream(), entry->fContent.getOffset());
1075    }
1076    gsState.drainStack();
1077
1078    SkMemoryStream* result = new SkMemoryStream;
1079    result->setMemoryOwned(data.detach(), data.getOffset());
1080    return result;
1081}
1082
1083void SkPDFDevice::createFormXObjectFromDevice(
1084        SkRefPtr<SkPDFFormXObject>* xobject) {
1085    *xobject = new SkPDFFormXObject(this);
1086    (*xobject)->unref();  // SkRefPtr and new both took a reference.
1087    cleanUp();  // Reset this device to have no content.
1088    init();
1089}
1090
1091void SkPDFDevice::clearClipFromContent(const SkClipStack* clipStack,
1092                                       const SkRegion& clipRegion) {
1093    if (clipRegion.isEmpty() || isContentEmpty()) {
1094        return;
1095    }
1096    SkRefPtr<SkPDFFormXObject> curContent;
1097    createFormXObjectFromDevice(&curContent);
1098
1099    // Redraw what we already had, but with the clip as a mask.
1100    drawFormXObjectWithClip(curContent.get(), clipStack, clipRegion, true);
1101}
1102
1103void SkPDFDevice::drawFormXObjectWithClip(SkPDFFormXObject* xobject,
1104                                          const SkClipStack* clipStack,
1105                                          const SkRegion& clipRegion,
1106                                          bool invertClip) {
1107    if (clipRegion.isEmpty() && !invertClip) {
1108        return;
1109    }
1110
1111    // Create the mask.
1112    SkMatrix identity;
1113    identity.reset();
1114    SkDraw draw;
1115    draw.fMatrix = &identity;
1116    draw.fClip = &clipRegion;
1117    draw.fClipStack = clipStack;
1118    SkPaint stockPaint;
1119    this->drawPaint(draw, stockPaint);
1120    SkRefPtr<SkPDFFormXObject> maskFormXObject;
1121    createFormXObjectFromDevice(&maskFormXObject);
1122    SkRefPtr<SkPDFGraphicState> sMaskGS =
1123        SkPDFGraphicState::getSMaskGraphicState(maskFormXObject.get(),
1124                                                invertClip);
1125    sMaskGS->unref();  // SkRefPtr and getSMaskGraphicState both took a ref.
1126
1127    // Draw the xobject with the clip as a mask.
1128    ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion,
1129                                 identity, stockPaint);
1130    if (!content.entry()) {
1131        return;
1132    }
1133    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1134                                  &content.entry()->fContent);
1135    SkPDFUtils::DrawFormXObject(fXObjectResources.count(),
1136                                &content.entry()->fContent);
1137    fXObjectResources.push(xobject);
1138    xobject->ref();
1139
1140    sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
1141    sMaskGS->unref();  // SkRefPtr and getSMaskGraphicState both took a ref.
1142    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1143                                  &content.entry()->fContent);
1144}
1145
1146ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
1147                                             const SkRegion& clipRegion,
1148                                             const SkMatrix& matrix,
1149                                             const SkPaint& paint,
1150                                             bool hasText,
1151                                             SkRefPtr<SkPDFFormXObject>* dst) {
1152    if (clipRegion.isEmpty()) {
1153        return NULL;
1154    }
1155
1156    // The clip stack can come from an SkDraw where it is technically optional.
1157    SkClipStack synthesizedClipStack;
1158    if (clipStack == NULL) {
1159        if (clipRegion == fExistingClipRegion) {
1160            clipStack = &fExistingClipStack;
1161        } else {
1162            // GraphicStackState::updateClip expects the clip stack to have
1163            // fExistingClip as a prefix, so start there, then set the clip
1164            // to the passed region.
1165            synthesizedClipStack = fExistingClipStack;
1166            SkPath clipPath;
1167            clipRegion.getBoundaryPath(&clipPath);
1168            synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op);
1169            clipStack = &synthesizedClipStack;
1170        }
1171    }
1172
1173    SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
1174    if (paint.getXfermode()) {
1175        paint.getXfermode()->asMode(&xfermode);
1176    }
1177
1178    if (xfermode == SkXfermode::kClear_Mode ||
1179            xfermode == SkXfermode::kSrc_Mode) {
1180        this->clearClipFromContent(clipStack, clipRegion);
1181    } else if (xfermode == SkXfermode::kSrcIn_Mode ||
1182               xfermode == SkXfermode::kDstIn_Mode ||
1183               xfermode == SkXfermode::kSrcOut_Mode ||
1184               xfermode == SkXfermode::kDstOut_Mode) {
1185        // For the following modes, we use both source and destination, but
1186        // we use one as a smask for the other, so we have to make form xobjects
1187        // out of both of them: SrcIn, DstIn, SrcOut, DstOut.
1188        if (isContentEmpty()) {
1189            return NULL;
1190        } else {
1191            createFormXObjectFromDevice(dst);
1192        }
1193    }
1194    // TODO(vandebo) Figure out how/if we can handle the following modes:
1195    // SrcAtop, DestAtop, Xor, Plus.
1196
1197    // These xfer modes don't draw source at all.
1198    if (xfermode == SkXfermode::kClear_Mode ||
1199            xfermode == SkXfermode::kDst_Mode) {
1200        return NULL;
1201    }
1202
1203    ContentEntry* entry;
1204    SkTScopedPtr<ContentEntry> newEntry;
1205    if (fLastContentEntry && fLastContentEntry->fContent.getOffset() == 0) {
1206        entry = fLastContentEntry;
1207    } else {
1208        newEntry.reset(new ContentEntry);
1209        entry = newEntry.get();
1210    }
1211
1212    populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
1213                                       hasText, &entry->fState);
1214    if (fLastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
1215            entry->fState.compareInitialState(fLastContentEntry->fState)) {
1216        return fLastContentEntry;
1217    }
1218
1219    if (!fLastContentEntry) {
1220        fContentEntries.reset(entry);
1221        fLastContentEntry = entry;
1222    } else if (xfermode == SkXfermode::kDstOver_Mode) {
1223        entry->fNext.reset(fContentEntries.release());
1224        fContentEntries.reset(entry);
1225    } else {
1226        fLastContentEntry->fNext.reset(entry);
1227        fLastContentEntry = entry;
1228    }
1229    newEntry.release();
1230    return entry;
1231}
1232
1233void SkPDFDevice::finishContentEntry(const SkXfermode::Mode xfermode,
1234                                     SkPDFFormXObject* dst) {
1235    if (xfermode != SkXfermode::kSrcIn_Mode &&
1236            xfermode != SkXfermode::kDstIn_Mode &&
1237            xfermode != SkXfermode::kSrcOut_Mode &&
1238            xfermode != SkXfermode::kDstOut_Mode) {
1239        SkASSERT(!dst);
1240        return;
1241    }
1242    SkASSERT(dst);
1243    SkASSERT(!fContentEntries->fNext.get());
1244
1245    // We have to make a copy of these here because changing the current
1246    // content into a form xobject will destroy them.
1247    SkClipStack clipStack = fContentEntries->fState.fClipStack;
1248    SkRegion clipRegion = fContentEntries->fState.fClipRegion;
1249
1250    SkRefPtr<SkPDFFormXObject> srcFormXObject;
1251    if (!isContentEmpty()) {
1252        createFormXObjectFromDevice(&srcFormXObject);
1253    }
1254
1255    drawFormXObjectWithClip(dst, &clipStack, clipRegion, true);
1256
1257    // We've redrawn dst minus the clip area, if there's no src, we're done.
1258    if (!srcFormXObject.get()) {
1259        return;
1260    }
1261
1262    SkMatrix identity;
1263    identity.reset();
1264    SkPaint stockPaint;
1265    ScopedContentEntry inClipContentEntry(this, &fExistingClipStack,
1266                                          fExistingClipRegion, identity,
1267                                          stockPaint);
1268    if (!inClipContentEntry.entry()) {
1269        return;
1270    }
1271
1272    SkRefPtr<SkPDFGraphicState> sMaskGS;
1273    if (xfermode == SkXfermode::kSrcIn_Mode ||
1274            xfermode == SkXfermode::kSrcOut_Mode) {
1275        sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
1276                dst, xfermode == SkXfermode::kSrcOut_Mode);
1277        fXObjectResources.push(srcFormXObject.get());
1278        srcFormXObject->ref();
1279    } else {
1280        sMaskGS = SkPDFGraphicState::getSMaskGraphicState(
1281                srcFormXObject.get(), xfermode == SkXfermode::kDstOut_Mode);
1282        // dst already added to fXObjectResources in drawFormXObjectWithClip.
1283    }
1284    sMaskGS->unref();  // SkRefPtr and getSMaskGraphicState both took a ref.
1285    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1286                                  &inClipContentEntry.entry()->fContent);
1287
1288    SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
1289                                &inClipContentEntry.entry()->fContent);
1290
1291    sMaskGS = SkPDFGraphicState::getNoSMaskGraphicState();
1292    sMaskGS->unref();  // SkRefPtr and getSMaskGraphicState both took a ref.
1293    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1294                                  &inClipContentEntry.entry()->fContent);
1295}
1296
1297bool SkPDFDevice::isContentEmpty() {
1298    if (!fContentEntries.get() || fContentEntries->fContent.getOffset() == 0) {
1299        SkASSERT(!fContentEntries.get() || !fContentEntries->fNext.get());
1300        return true;
1301    }
1302    return false;
1303}
1304
1305
1306void SkPDFDevice::populateGraphicStateEntryFromPaint(
1307        const SkMatrix& matrix,
1308        const SkClipStack& clipStack,
1309        const SkRegion& clipRegion,
1310        const SkPaint& paint,
1311        bool hasText,
1312        GraphicStateEntry* entry) {
1313    SkASSERT(paint.getPathEffect() == NULL);
1314
1315    NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
1316    NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false);
1317
1318    entry->fMatrix = matrix;
1319    entry->fClipStack = clipStack;
1320    entry->fClipRegion = clipRegion;
1321
1322    // PDF treats a shader as a color, so we only set one or the other.
1323    SkRefPtr<SkPDFShader> pdfShader;
1324    const SkShader* shader = paint.getShader();
1325    SkColor color = paint.getColor();
1326    if (shader) {
1327        // PDF positions patterns relative to the initial transform, so
1328        // we need to apply the current transform to the shader parameters.
1329        SkMatrix transform = matrix;
1330        transform.postConcat(fInitialTransform);
1331
1332        // PDF doesn't support kClamp_TileMode, so we simulate it by making
1333        // a pattern the size of the current clip.
1334        SkIRect bounds = clipRegion.getBounds();
1335        pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds);
1336        SkSafeUnref(pdfShader.get());  // getShader and SkRefPtr both took a ref
1337
1338        // A color shader is treated as an invalid shader so we don't have
1339        // to set a shader just for a color.
1340        if (pdfShader.get() == NULL) {
1341            entry->fColor = 0;
1342            color = 0;
1343
1344            // Check for a color shader.
1345            SkShader::GradientInfo gradientInfo;
1346            SkColor gradientColor;
1347            gradientInfo.fColors = &gradientColor;
1348            gradientInfo.fColorOffsets = NULL;
1349            gradientInfo.fColorCount = 1;
1350            if (shader->asAGradient(&gradientInfo) ==
1351                    SkShader::kColor_GradientType) {
1352                entry->fColor = SkColorSetA(gradientColor, 0xFF);
1353                color = gradientColor;
1354            }
1355        }
1356    }
1357
1358    if (pdfShader) {
1359        // pdfShader has been canonicalized so we can directly compare
1360        // pointers.
1361        int resourceIndex = fShaderResources.find(pdfShader.get());
1362        if (resourceIndex < 0) {
1363            resourceIndex = fShaderResources.count();
1364            fShaderResources.push(pdfShader.get());
1365            pdfShader->ref();
1366        }
1367        entry->fShaderIndex = resourceIndex;
1368    } else {
1369        entry->fShaderIndex = -1;
1370        entry->fColor = SkColorSetA(paint.getColor(), 0xFF);
1371        color = paint.getColor();
1372    }
1373
1374    SkRefPtr<SkPDFGraphicState> newGraphicState;
1375    if (color == paint.getColor()) {
1376        newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(paint);
1377    } else {
1378        SkPaint newPaint = paint;
1379        newPaint.setColor(color);
1380        newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(newPaint);
1381    }
1382    newGraphicState->unref();  // getGraphicState and SkRefPtr both took a ref.
1383    int resourceIndex = addGraphicStateResource(newGraphicState.get());
1384    entry->fGraphicStateIndex = resourceIndex;
1385
1386    if (hasText) {
1387        entry->fTextScaleX = paint.getTextScaleX();
1388        entry->fTextFill = paint.getStyle();
1389    } else {
1390        entry->fTextScaleX = 0;
1391    }
1392}
1393
1394int SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) {
1395    // Assumes that gs has been canonicalized (so we can directly compare
1396    // pointers).
1397    int result = fGraphicStateResources.find(gs);
1398    if (result < 0) {
1399        result = fGraphicStateResources.count();
1400        fGraphicStateResources.push(gs);
1401        gs->ref();
1402    }
1403    return result;
1404}
1405
1406void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
1407                             ContentEntry* contentEntry) {
1408    SkTypeface* typeface = paint.getTypeface();
1409    if (contentEntry->fState.fFont == NULL ||
1410            contentEntry->fState.fTextSize != paint.getTextSize() ||
1411            !contentEntry->fState.fFont->hasGlyph(glyphID)) {
1412        int fontIndex = getFontResourceIndex(typeface, glyphID);
1413        contentEntry->fContent.writeText("/F");
1414        contentEntry->fContent.writeDecAsText(fontIndex);
1415        contentEntry->fContent.writeText(" ");
1416        SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent);
1417        contentEntry->fContent.writeText(" Tf\n");
1418        contentEntry->fState.fFont = fFontResources[fontIndex];
1419    }
1420}
1421
1422int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
1423    SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResource(typeface, glyphID);
1424    newFont->unref();  // getFontResource and SkRefPtr both took a ref.
1425    int resourceIndex = fFontResources.find(newFont.get());
1426    if (resourceIndex < 0) {
1427        resourceIndex = fFontResources.count();
1428        fFontResources.push(newFont.get());
1429        newFont->ref();
1430    }
1431    return resourceIndex;
1432}
1433
1434void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
1435                                     const SkClipStack* clipStack,
1436                                     const SkRegion& clipRegion,
1437                                     const SkBitmap& bitmap,
1438                                     const SkIRect* srcRect,
1439                                     const SkPaint& paint) {
1440    SkMatrix scaled;
1441    // Adjust for origin flip.
1442    scaled.setScale(1, -1);
1443    scaled.postTranslate(0, 1);
1444    // Scale the image up from 1x1 to WxH.
1445    SkIRect subset = SkIRect::MakeWH(bitmap.width(), bitmap.height());
1446    scaled.postScale(SkIntToScalar(subset.width()),
1447                     SkIntToScalar(subset.height()));
1448    scaled.postConcat(matrix);
1449    ScopedContentEntry content(this, clipStack, clipRegion, scaled, paint);
1450    if (!content.entry()) {
1451        return;
1452    }
1453
1454    if (srcRect && !subset.intersect(*srcRect)) {
1455        return;
1456    }
1457
1458    SkPDFImage* image = SkPDFImage::CreateImage(bitmap, subset, paint);
1459    if (!image) {
1460        return;
1461    }
1462
1463    fXObjectResources.push(image);  // Transfer reference.
1464    SkPDFUtils::DrawFormXObject(fXObjectResources.count() - 1,
1465                                &content.entry()->fContent);
1466}
1467