19b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
39b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
69b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org */
79b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
89b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org#include "SkPDFDevice.h"
99b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
10238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org#include "SkAnnotation.h"
11c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White#include "SkBitmapDevice.h"
129b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org#include "SkColor.h"
139fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org#include "SkClipStack.h"
148a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com#include "SkData.h"
15fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org#include "SkDraw.h"
164e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org#include "SkFontHost.h"
1728be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org#include "SkGlyphCache.h"
189b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org#include "SkPaint.h"
19a518086928494319b8968abc09808eff492c194fvandebo@chromium.org#include "SkPath.h"
2092ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org#include "SkPathOps.h"
2128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org#include "SkPDFFont.h"
22eb6c7596af1a1fc7860e27ff2f678a33b2576c0fvandebo@chromium.org#include "SkPDFFormXObject.h"
2377bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org#include "SkPDFGraphicState.h"
2477bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org#include "SkPDFImage.h"
2547401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org#include "SkPDFResourceDict.h"
26da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFShader.h"
279b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org#include "SkPDFStream.h"
2877bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org#include "SkPDFTypes.h"
299db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.org#include "SkPDFUtils.h"
309b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org#include "SkRect.h"
31a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com#include "SkRRect.h"
329b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org#include "SkString.h"
3389443aba5bfa2b040dc9fd24938b7d0b3decd737reed#include "SkSurface.h"
3428be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org#include "SkTextFormatParams.h"
354e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org#include "SkTemplates.h"
36fed86bdb8b9f037439bbfa7cdbd53a581dbc5985reed@google.com#include "SkTypefacePriv.h"
376addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com#include "SkTSet.h"
389b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
3973a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com#define DPI_FOR_RASTER_SCALE_ONE 72
4073a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com
419b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org// Utility functions
429b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
439fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgstatic void emit_pdf_color(SkColor color, SkWStream* result) {
449b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    SkASSERT(SkColorGetA(color) == 0xFF);  // We handle alpha elsewhere.
459b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    SkScalar colorMax = SkIntToScalar(0xFF);
46094316bd284372c2a3d8ef02eec589901e503c59vandebo@chromium.org    SkPDFScalar::Append(
47cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org            SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result);
48cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org    result->writeText(" ");
49094316bd284372c2a3d8ef02eec589901e503c59vandebo@chromium.org    SkPDFScalar::Append(
50cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org            SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result);
51cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org    result->writeText(" ");
52094316bd284372c2a3d8ef02eec589901e503c59vandebo@chromium.org    SkPDFScalar::Append(
53cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org            SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), result);
54cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org    result->writeText(" ");
559b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
569b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
579fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgstatic SkPaint calculate_text_paint(const SkPaint& paint) {
5828be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkPaint result = paint;
5928be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    if (result.isFakeBoldText()) {
6028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(),
6128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org                                                    kStdFakeBoldInterpKeys,
6228be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org                                                    kStdFakeBoldInterpValues,
6328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org                                                    kStdFakeBoldInterpLength);
6428be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale);
65769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org        if (result.getStyle() == SkPaint::kFill_Style) {
6628be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org            result.setStyle(SkPaint::kStrokeAndFill_Style);
67769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org        } else {
6828be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org            width += result.getStrokeWidth();
69769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org        }
7028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        result.setStrokeWidth(width);
7128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    }
7228be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    return result;
7328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org}
7428be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
7528be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org// Stolen from measure_text in SkDraw.cpp and then tweaked.
769fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgstatic void align_text(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
779a87cee904e2d8f0ea6a0e7e3ca864262a8cb7c4bungeman@google.com                       const uint16_t* glyphs, size_t len,
789a87cee904e2d8f0ea6a0e7e3ca864262a8cb7c4bungeman@google.com                       SkScalar* x, SkScalar* y) {
799a87cee904e2d8f0ea6a0e7e3ca864262a8cb7c4bungeman@google.com    if (paint.getTextAlign() == SkPaint::kLeft_Align) {
8028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        return;
81769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    }
8228be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
8328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkMatrix ident;
8428be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    ident.reset();
85532470f34dbe9fc0b8b71e3917eca8894feaf336bungeman@google.com    SkAutoGlyphCache autoCache(paint, NULL, &ident);
8628be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkGlyphCache* cache = autoCache.getCache();
8728be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
889510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    const char* start = reinterpret_cast<const char*>(glyphs);
899510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    const char* stop = reinterpret_cast<const char*>(glyphs + len);
9028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkFixed xAdv = 0, yAdv = 0;
9128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
92769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    // TODO(vandebo): This probably needs to take kerning into account.
9328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    while (start < stop) {
9428be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0);
9528be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        xAdv += glyph.fAdvanceX;
9628be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        yAdv += glyph.fAdvanceY;
9728be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    };
98769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    if (paint.getTextAlign() == SkPaint::kLeft_Align) {
9928be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        return;
100769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    }
10128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
10228be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkScalar xAdj = SkFixedToScalar(xAdv);
10328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkScalar yAdj = SkFixedToScalar(yAdv);
10428be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    if (paint.getTextAlign() == SkPaint::kCenter_Align) {
10528be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        xAdj = SkScalarHalf(xAdj);
10628be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        yAdj = SkScalarHalf(yAdj);
10728be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    }
10828be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    *x = *x - xAdj;
10928be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    *y = *y - yAdj;
11028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org}
11128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
112a4662865e37a2ca95b5e3379072f6a274acc8ac8robertphillips@google.comstatic int max_glyphid_for_typeface(SkTypeface* typeface) {
113fed86bdb8b9f037439bbfa7cdbd53a581dbc5985reed@google.com    SkAutoResolveDefaultTypeface autoResolve(typeface);
114fed86bdb8b9f037439bbfa7cdbd53a581dbc5985reed@google.com    typeface = autoResolve.get();
1156a4ba5b20590e377d42d3488a32cd5dd94355107commit-bot@chromium.org    return typeface->countGlyphs() - 1;
1164e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org}
1174e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org
1184e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.orgtypedef SkAutoSTMalloc<128, uint16_t> SkGlyphStorage;
1194e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org
120aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.comstatic int force_glyph_encoding(const SkPaint& paint, const void* text,
121aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.com                                size_t len, SkGlyphStorage* storage,
122139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman                                const uint16_t** glyphIDs) {
1234e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    // Make sure we have a glyph id encoding.
1244e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) {
125aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.com        int numGlyphs = paint.textToGlyphs(text, len, NULL);
1264e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        storage->reset(numGlyphs);
1274e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        paint.textToGlyphs(text, len, storage->get());
1284e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        *glyphIDs = storage->get();
1294e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        return numGlyphs;
1304e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    }
1314e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org
1324e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    // For user supplied glyph ids we need to validate them.
1334e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    SkASSERT((len & 1) == 0);
134aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.com    int numGlyphs = SkToInt(len / 2);
135139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman    const uint16_t* input = static_cast<const uint16_t*>(text);
1364e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org
1374e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    int maxGlyphID = max_glyphid_for_typeface(paint.getTypeface());
138aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.com    int validated;
1394e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    for (validated = 0; validated < numGlyphs; ++validated) {
1404e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        if (input[validated] > maxGlyphID) {
1414e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org            break;
1424e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        }
1434e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    }
1444e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    if (validated >= numGlyphs) {
145139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman        *glyphIDs = static_cast<const uint16_t*>(text);
1464e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        return numGlyphs;
1474e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    }
1484e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org
1494e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    // Silently drop anything out of range.
1504e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    storage->reset(numGlyphs);
1514e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    if (validated > 0) {
1524e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        memcpy(storage->get(), input, validated * sizeof(uint16_t));
1534e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    }
1544e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org
155aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.com    for (int i = validated; i < numGlyphs; ++i) {
1564e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        storage->get()[i] = input[i];
1574e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        if (input[i] > maxGlyphID) {
1584e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org            storage->get()[i] = 0;
1594e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org        }
1604e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    }
1614e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    *glyphIDs = storage->get();
1624e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    return numGlyphs;
1634e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org}
1644e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org
165b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.orgstatic void set_text_transform(SkScalar x, SkScalar y, SkScalar textSkewX,
166b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                               SkWStream* content) {
167b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    // Flip the text about the x-axis to account for origin swap and include
168b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    // the passed parameters.
169b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    content->writeText("1 0 ");
170b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkPDFScalar::Append(0 - textSkewX, content);
171b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    content->writeText(" -1 ");
172b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkPDFScalar::Append(x, content);
173b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    content->writeText(" ");
174b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkPDFScalar::Append(y, content);
175b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    content->writeText(" Tm\n");
176b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org}
177b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org
1789fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org// It is important to not confuse GraphicStateEntry with SkPDFGraphicState, the
1799fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org// later being our representation of an object in the PDF file.
1809fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgstruct GraphicStateEntry {
1819fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    GraphicStateEntry();
1829fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
1839fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // Compare the fields we care about when setting up a new content entry.
1849fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    bool compareInitialState(const GraphicStateEntry& b);
1859fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
1869fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkMatrix fMatrix;
1879fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // We can't do set operations on Paths, though PDF natively supports
1889fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // intersect.  If the clip stack does anything other than intersect,
1899fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // we have to fall back to the region.  Treat fClipStack as authoritative.
1909fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // See http://code.google.com/p/skia/issues/detail?id=221
1919fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkClipStack fClipStack;
1929fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkRegion fClipRegion;
1939fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
1949fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // When emitting the content entry, we will ensure the graphic state
1959fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // is set to these values first.
1969fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkColor fColor;
1979fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkScalar fTextScaleX;  // Zero means we don't care what the value is.
1989fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkPaint::Style fTextFill;  // Only if TextScaleX is non-zero.
1999fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    int fShaderIndex;
2009fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    int fGraphicStateIndex;
2019fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2029fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // We may change the font (i.e. for Type1 support) within a
2039fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // ContentEntry.  This is the one currently in effect, or NULL if none.
2049fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkPDFFont* fFont;
2059fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // In PDF, text size has no default value. It is only valid if fFont is
2069fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // not NULL.
2079fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkScalar fTextSize;
2089fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org};
2099fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2109fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgGraphicStateEntry::GraphicStateEntry() : fColor(SK_ColorBLACK),
2119fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                         fTextScaleX(SK_Scalar1),
2129fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                         fTextFill(SkPaint::kFill_Style),
2139fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                         fShaderIndex(-1),
2149fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                         fGraphicStateIndex(-1),
2159fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                         fFont(NULL),
2169fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                         fTextSize(SK_ScalarNaN) {
2179fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    fMatrix.reset();
2189fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
2199fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
220b000d76af4de735a233e64b7be68cee8a5a8f8dccommit-bot@chromium.orgbool GraphicStateEntry::compareInitialState(const GraphicStateEntry& cur) {
221b000d76af4de735a233e64b7be68cee8a5a8f8dccommit-bot@chromium.org    return fColor == cur.fColor &&
222b000d76af4de735a233e64b7be68cee8a5a8f8dccommit-bot@chromium.org           fShaderIndex == cur.fShaderIndex &&
223b000d76af4de735a233e64b7be68cee8a5a8f8dccommit-bot@chromium.org           fGraphicStateIndex == cur.fGraphicStateIndex &&
224b000d76af4de735a233e64b7be68cee8a5a8f8dccommit-bot@chromium.org           fMatrix == cur.fMatrix &&
225b000d76af4de735a233e64b7be68cee8a5a8f8dccommit-bot@chromium.org           fClipStack == cur.fClipStack &&
226b000d76af4de735a233e64b7be68cee8a5a8f8dccommit-bot@chromium.org           (fTextScaleX == 0 ||
227b000d76af4de735a233e64b7be68cee8a5a8f8dccommit-bot@chromium.org               (fTextScaleX == cur.fTextScaleX && fTextFill == cur.fTextFill));
2289fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
2299fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2309fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgclass GraphicStackState {
2319fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgpublic:
2329fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    GraphicStackState(const SkClipStack& existingClipStack,
2339fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                      const SkRegion& existingClipRegion,
2349fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                      SkWStream* contentStream)
2359fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            : fStackDepth(0),
2369fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org              fContentStream(contentStream) {
2379fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        fEntries[0].fClipStack = existingClipStack;
2389fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        fEntries[0].fClipRegion = existingClipRegion;
2399fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
2409fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2419fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    void updateClip(const SkClipStack& clipStack, const SkRegion& clipRegion,
242663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org                    const SkPoint& translation);
2439fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    void updateMatrix(const SkMatrix& matrix);
2449fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    void updateDrawingState(const GraphicStateEntry& state);
2459fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2469fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    void drainStack();
2479fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2489fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgprivate:
2499fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    void push();
2509fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    void pop();
2519fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    GraphicStateEntry* currentEntry() { return &fEntries[fStackDepth]; }
2529fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2539fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // Conservative limit on save depth, see impl. notes in PDF 1.4 spec.
2549fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    static const int kMaxStackDepth = 12;
2559fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    GraphicStateEntry fEntries[kMaxStackDepth + 1];
2569fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    int fStackDepth;
2579fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkWStream* fContentStream;
2589fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org};
2599fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2609fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgvoid GraphicStackState::drainStack() {
2619fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    while (fStackDepth) {
2629fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        pop();
2639fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
2649fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
2659fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2669fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgvoid GraphicStackState::push() {
2679fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkASSERT(fStackDepth < kMaxStackDepth);
2689fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    fContentStream->writeText("q\n");
2699fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    fStackDepth++;
2709fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    fEntries[fStackDepth] = fEntries[fStackDepth - 1];
2719fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
2729fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2739fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgvoid GraphicStackState::pop() {
2749fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkASSERT(fStackDepth > 0);
2759fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    fContentStream->writeText("Q\n");
2769fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    fStackDepth--;
2779fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
2789fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
27980214e26c57c5fea954006400852e8999e201923robertphillips@google.com// This function initializes iter to be an iterator on the "stack" argument
2809fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org// and then skips over the leading entries as specified in prefix.  It requires
2819fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org// and asserts that "prefix" will be a prefix to "stack."
2829fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgstatic void skip_clip_stack_prefix(const SkClipStack& prefix,
2839fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                   const SkClipStack& stack,
284c029062a0312fb747fb6c2677983aba51795c580robertphillips@google.com                                   SkClipStack::Iter* iter) {
28580214e26c57c5fea954006400852e8999e201923robertphillips@google.com    SkClipStack::B2TIter prefixIter(prefix);
28680214e26c57c5fea954006400852e8999e201923robertphillips@google.com    iter->reset(stack, SkClipStack::Iter::kBottom_IterStart);
2879fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2888182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    const SkClipStack::Element* prefixEntry;
2898182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    const SkClipStack::Element* iterEntry;
2909fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
2919fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    for (prefixEntry = prefixIter.next(); prefixEntry;
292c029062a0312fb747fb6c2677983aba51795c580robertphillips@google.com            prefixEntry = prefixIter.next()) {
2939fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        iterEntry = iter->next();
2949fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkASSERT(iterEntry);
2958887ede82465687355c7a1c51e4553e99b2fb15avandebo@chromium.org        // Because of SkClipStack does internal intersection, the last clip
2968887ede82465687355c7a1c51e4553e99b2fb15avandebo@chromium.org        // entry may differ.
2979510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org        if (*prefixEntry != *iterEntry) {
2988182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op);
2998182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op);
3008182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            SkASSERT(iterEntry->getType() == prefixEntry->getType());
301c029062a0312fb747fb6c2677983aba51795c580robertphillips@google.com            // back up the iterator by one
302c029062a0312fb747fb6c2677983aba51795c580robertphillips@google.com            iter->prev();
3038887ede82465687355c7a1c51e4553e99b2fb15avandebo@chromium.org            prefixEntry = prefixIter.next();
3048887ede82465687355c7a1c51e4553e99b2fb15avandebo@chromium.org            break;
3058887ede82465687355c7a1c51e4553e99b2fb15avandebo@chromium.org        }
3069fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
3079fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
3089fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkASSERT(prefixEntry == NULL);
3099fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
3109fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
3119fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgstatic void emit_clip(SkPath* clipPath, SkRect* clipRect,
3129fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                      SkWStream* contentStream) {
3139fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkASSERT(clipPath || clipRect);
3149fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
3159fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkPath::FillType clipFill;
3169fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (clipPath) {
317683001ce0de70c859ea5e5353245b18cadbefc45vandebo@chromium.org        SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream);
3189fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        clipFill = clipPath->getFillType();
3193e7b280b720ae202db6561f31d862990a7be32d9vandebo@chromium.org    } else {
3209fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkPDFUtils::AppendRectangle(*clipRect, contentStream);
3219fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        clipFill = SkPath::kWinding_FillType;
3229fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
3239fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
3249fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false);
3259fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false);
3269fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (clipFill == SkPath::kEvenOdd_FillType) {
3279fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        contentStream->writeText("W* n\n");
3289fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    } else {
3299fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        contentStream->writeText("W n\n");
3309fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
3319fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
3329fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
333d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org#ifdef SK_PDF_USE_PATHOPS
334d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org/* Calculate an inverted path's equivalent non-inverted path, given the
335d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org * canvas bounds.
336d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org * outPath may alias with invPath (since this is supported by PathOps).
337d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org */
338d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.orgstatic bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath,
339d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                                   SkPath* outPath) {
340d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    SkASSERT(invPath.isInverseFillType());
341d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
342d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    SkPath clipPath;
343d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    clipPath.addRect(bounds);
344d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
345d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    return Op(clipPath, invPath, kIntersect_PathOp, outPath);
346d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org}
347d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
348d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org// Sanity check the numerical values of the SkRegion ops and PathOps ops
349d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org// enums so region_op_to_pathops_op can do a straight passthrough cast.
350d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org// If these are failing, it may be necessary to make region_op_to_pathops_op
351d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org// do more.
352d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.orgSK_COMPILE_ASSERT(SkRegion::kDifference_Op == (int)kDifference_PathOp,
353d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                  region_pathop_mismatch);
354d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.orgSK_COMPILE_ASSERT(SkRegion::kIntersect_Op == (int)kIntersect_PathOp,
355d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                  region_pathop_mismatch);
356d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.orgSK_COMPILE_ASSERT(SkRegion::kUnion_Op == (int)kUnion_PathOp,
357d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                  region_pathop_mismatch);
358d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.orgSK_COMPILE_ASSERT(SkRegion::kXOR_Op == (int)kXOR_PathOp,
359d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                  region_pathop_mismatch);
360d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.orgSK_COMPILE_ASSERT(SkRegion::kReverseDifference_Op ==
361d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                  (int)kReverseDifference_PathOp,
362d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                  region_pathop_mismatch);
363d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
364d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.orgstatic SkPathOp region_op_to_pathops_op(SkRegion::Op op) {
365d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    SkASSERT(op >= 0);
366d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    SkASSERT(op <= SkRegion::kReverseDifference_Op);
367d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    return (SkPathOp)op;
368d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org}
369d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
370d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org/* Uses Path Ops to calculate a vector SkPath clip from a clip stack.
371d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org * Returns true if successful, or false if not successful.
372d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org * If successful, the resulting clip is stored in outClipPath.
373d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org * If not successful, outClipPath is undefined, and a fallback method
374d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org * should be used.
375d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org */
376d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.orgstatic bool get_clip_stack_path(const SkMatrix& transform,
377d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                                const SkClipStack& clipStack,
378d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                                const SkRegion& clipRegion,
379d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                                SkPath* outClipPath) {
380d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    outClipPath->reset();
381d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    outClipPath->setFillType(SkPath::kInverseWinding_FillType);
382d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
383d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    const SkClipStack::Element* clipEntry;
384d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    SkClipStack::Iter iter;
385d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart);
386d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
387d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        SkPath entryPath;
388d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        if (SkClipStack::Element::kEmpty_Type == clipEntry->getType()) {
389d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org            outClipPath->reset();
390d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org            outClipPath->setFillType(SkPath::kInverseWinding_FillType);
391d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org            continue;
392e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org        } else {
393e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org            clipEntry->asPath(&entryPath);
394d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        }
395d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        entryPath.transform(transform);
396d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
397d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        if (SkRegion::kReplace_Op == clipEntry->getOp()) {
398d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org            *outClipPath = entryPath;
399d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        } else {
400d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org            SkPathOp op = region_op_to_pathops_op(clipEntry->getOp());
401d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org            if (!Op(*outClipPath, entryPath, op, outClipPath)) {
402d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org                return false;
403d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org            }
404d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        }
405d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    }
406d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
407d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    if (outClipPath->isInverseFillType()) {
408d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        // The bounds are slightly outset to ensure this is correct in the
409d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        // face of floating-point accuracy and possible SkRegion bitmap
410d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        // approximations.
411d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        SkRect clipBounds = SkRect::Make(clipRegion.getBounds());
412d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        clipBounds.outset(SK_Scalar1, SK_Scalar1);
413d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        if (!calculate_inverse_path(clipBounds, *outClipPath, outClipPath)) {
414d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org            return false;
415d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        }
416d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    }
417d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    return true;
418d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org}
419d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org#endif
420d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
421769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org// TODO(vandebo): Take advantage of SkClipStack::getSaveCount(), the PDF
4229fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org// graphic state stack, and the fact that we can know all the clips used
4239fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org// on the page to optimize this.
4249fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgvoid GraphicStackState::updateClip(const SkClipStack& clipStack,
4259fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                   const SkRegion& clipRegion,
426663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org                                   const SkPoint& translation) {
4279fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (clipStack == currentEntry()->fClipStack) {
4289fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        return;
4299fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
4309fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
4319fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    while (fStackDepth > 0) {
4329fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        pop();
4339fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        if (clipStack == currentEntry()->fClipStack) {
4349fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            return;
4359fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        }
4369fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
4379fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    push();
4389fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
439d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    currentEntry()->fClipStack = clipStack;
440d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    currentEntry()->fClipRegion = clipRegion;
441d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
442d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    SkMatrix transform;
443d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    transform.setTranslate(translation.fX, translation.fY);
444d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org
445d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org#ifdef SK_PDF_USE_PATHOPS
446d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    SkPath clipPath;
447d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) {
448d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        emit_clip(&clipPath, NULL, fContentStream);
449d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org        return;
450d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org    }
451d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org#endif
4529fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // gsState->initialEntry()->fClipStack/Region specifies the clip that has
4539fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // already been applied.  (If this is a top level device, then it specifies
4549fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // a clip to the content area.  If this is a layer, then it specifies
4559fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // the clip in effect when the layer was created.)  There's no need to
4569fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the
4579fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // initial clip on the parent layer.  (This means there's a bug if the user
4589fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // expands the clip and then uses any xfer mode that uses dst:
4599fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // http://code.google.com/p/skia/issues/detail?id=228 )
460c029062a0312fb747fb6c2677983aba51795c580robertphillips@google.com    SkClipStack::Iter iter;
4619fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
4629fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
4639fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // If the clip stack does anything other than intersect or if it uses
4649fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // an inverse fill type, we have to fall back to the clip region.
4659fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    bool needRegion = false;
4668182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    const SkClipStack::Element* clipEntry;
4679fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
4683b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        if (clipEntry->getOp() != SkRegion::kIntersect_Op ||
4693b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                clipEntry->isInverseFilled()) {
4709fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            needRegion = true;
4719fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            break;
4729fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        }
4739fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
4749fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
4759fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (needRegion) {
4769fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkPath clipPath;
4779fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkAssertResult(clipRegion.getBoundaryPath(&clipPath));
4789fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        emit_clip(&clipPath, NULL, fContentStream);
4799fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    } else {
4809fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter);
4818182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const SkClipStack::Element* clipEntry;
4829fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
4838182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op);
4848182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            switch (clipEntry->getType()) {
4858182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                case SkClipStack::Element::kRect_Type: {
4868182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    SkRect translatedClip;
4878182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    transform.mapRect(&translatedClip, clipEntry->getRect());
4888182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    emit_clip(NULL, &translatedClip, fContentStream);
4898182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    break;
4908182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                }
4915a346a85027fc8aae5d836d951e455a22b3272d0commit-bot@chromium.org                default: {
4928182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    SkPath translatedPath;
4935a346a85027fc8aae5d836d951e455a22b3272d0commit-bot@chromium.org                    clipEntry->asPath(&translatedPath);
4945a346a85027fc8aae5d836d951e455a22b3272d0commit-bot@chromium.org                    translatedPath.transform(transform, &translatedPath);
4958182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    emit_clip(&translatedPath, NULL, fContentStream);
4968182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                    break;
4978182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                }
4989fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            }
4999fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        }
5009fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
5019fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
5029fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
5039fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgvoid GraphicStackState::updateMatrix(const SkMatrix& matrix) {
5049fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (matrix == currentEntry()->fMatrix) {
5059fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        return;
5069fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
5079fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
5089fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) {
5099fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkASSERT(fStackDepth > 0);
5109fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkASSERT(fEntries[fStackDepth].fClipStack ==
5119fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                 fEntries[fStackDepth -1].fClipStack);
5129fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        pop();
5139fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
5149fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkASSERT(currentEntry()->fMatrix.getType() == SkMatrix::kIdentity_Mask);
5159fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
5169fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (matrix.getType() == SkMatrix::kIdentity_Mask) {
5179fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        return;
5189fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
5199fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
5209fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    push();
5219fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkPDFUtils::AppendTransform(matrix, fContentStream);
5229fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    currentEntry()->fMatrix = matrix;
5239fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
5249fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
5259fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgvoid GraphicStackState::updateDrawingState(const GraphicStateEntry& state) {
5269fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // PDF treats a shader as a color, so we only set one or the other.
5279fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (state.fShaderIndex >= 0) {
5289fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        if (state.fShaderIndex != currentEntry()->fShaderIndex) {
52993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org            SkPDFUtils::ApplyPattern(state.fShaderIndex, fContentStream);
5309fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            currentEntry()->fShaderIndex = state.fShaderIndex;
5319fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        }
5329fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    } else {
5339fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        if (state.fColor != currentEntry()->fColor ||
5349fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                currentEntry()->fShaderIndex >= 0) {
5359fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            emit_pdf_color(state.fColor, fContentStream);
5369fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            fContentStream->writeText("RG ");
5379fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            emit_pdf_color(state.fColor, fContentStream);
5389fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            fContentStream->writeText("rg\n");
5399fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            currentEntry()->fColor = state.fColor;
5409fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            currentEntry()->fShaderIndex = -1;
5419fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        }
5429fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
5439fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
5449fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (state.fGraphicStateIndex != currentEntry()->fGraphicStateIndex) {
5456112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        SkPDFUtils::ApplyGraphicState(state.fGraphicStateIndex, fContentStream);
5469fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        currentEntry()->fGraphicStateIndex = state.fGraphicStateIndex;
5479fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
5489fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
5499fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (state.fTextScaleX) {
5509fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        if (state.fTextScaleX != currentEntry()->fTextScaleX) {
5519fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            SkScalar pdfScale = SkScalarMul(state.fTextScaleX,
5529fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                            SkIntToScalar(100));
5539fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            SkPDFScalar::Append(pdfScale, fContentStream);
5549fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            fContentStream->writeText(" Tz\n");
5559fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            currentEntry()->fTextScaleX = state.fTextScaleX;
5569fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        }
5579fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        if (state.fTextFill != currentEntry()->fTextFill) {
5589fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value);
5599fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1,
5609fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                              enum_must_match_value);
5619fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2,
5629fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                              enum_must_match_value);
5639fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            fContentStream->writeDecAsText(state.fTextFill);
5649fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            fContentStream->writeText(" Tr\n");
5659fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            currentEntry()->fTextFill = state.fTextFill;
5669fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        }
5679fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
5689fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
5699b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
57015a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.orgSkBaseDevice* SkPDFDevice::onCreateDevice(const SkImageInfo& info, Usage usage) {
571c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White    // PDF does not support image filters, so render them on CPU.
572c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White    // Note that this rendering is done at "screen" resolution (100dpi), not
573c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White    // printer resolution.
574c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White    // FIXME: It may be possible to express some filters natively using PDF
575c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White    // to improve quality and file size (http://skbug.com/3043)
576c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White    if (kImageFilter_Usage == usage) {
577c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White        return SkBitmapDevice::Create(info);
578c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White    }
579c38dee4f2c4cac24fa926a51069f04df272b1516Stephen White
580e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    SkMatrix initialTransform;
581e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    initialTransform.reset();
58215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkISize size = SkISize::Make(info.width(), info.height());
583e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com    return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform));
584e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com}
585e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com
586e97f0856a8044866b12527819d14cdfbcdfd96f2bsalomon@google.com
587b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.orgstruct ContentEntry {
588b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    GraphicStateEntry fState;
589b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkDynamicMemoryWStream fContent;
590e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org    SkAutoTDelete<ContentEntry> fNext;
5912e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com
5922e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com    // If the stack is too deep we could get Stack Overflow.
5932e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com    // So we manually destruct the object.
5942e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com    ~ContentEntry() {
595e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org        ContentEntry* val = fNext.detach();
5962e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com        while (val != NULL) {
597e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org            ContentEntry* valNext = val->fNext.detach();
5982e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com            // When the destructor is called, fNext is NULL and exits.
5992e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com            delete val;
6002e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com            val = valNext;
6012e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com        }
6022e6a69b7a23e88e54d8b4a9ee3f4f9e4cc0695a7edisonn@google.com    }
603b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org};
604b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org
605b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org// A helper class to automatically finish a ContentEntry at the end of a
606b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org// drawing method and maintain the state needed between set up and finish.
60713d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.orgclass ScopedContentEntry {
608b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.orgpublic:
60913d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry(SkPDFDevice* device, const SkDraw& draw,
61013d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org                       const SkPaint& paint, bool hasText = false)
611b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        : fDevice(device),
612b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org          fContentEntry(NULL),
6133b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org          fXfermode(SkXfermode::kSrcOver_Mode),
6143b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org          fDstFormXObject(NULL) {
615b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        init(draw.fClipStack, *draw.fClip, *draw.fMatrix, paint, hasText);
616b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    }
61713d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry(SkPDFDevice* device, const SkClipStack* clipStack,
61813d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org                       const SkRegion& clipRegion, const SkMatrix& matrix,
61913d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org                       const SkPaint& paint, bool hasText = false)
620b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        : fDevice(device),
621b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org          fContentEntry(NULL),
6223b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org          fXfermode(SkXfermode::kSrcOver_Mode),
6233b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org          fDstFormXObject(NULL) {
624b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        init(clipStack, clipRegion, matrix, paint, hasText);
625b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    }
626b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org
62713d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ~ScopedContentEntry() {
628b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        if (fContentEntry) {
6293b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            SkPath* shape = &fShape;
6303b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            if (shape->isEmpty()) {
6313b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                shape = NULL;
6323b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            }
6333b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            fDevice->finishContentEntry(fXfermode, fDstFormXObject, shape);
634b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        }
635fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com        SkSafeUnref(fDstFormXObject);
636b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    }
637b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org
638b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    ContentEntry* entry() { return fContentEntry; }
6393b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org
6403b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    /* Returns true when we explicitly need the shape of the drawing. */
6413b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    bool needShape() {
6423b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        switch (fXfermode) {
6433b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kClear_Mode:
6443b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kSrc_Mode:
6453b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kSrcIn_Mode:
6463b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kSrcOut_Mode:
6473b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kDstIn_Mode:
6483b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kDstOut_Mode:
6493b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kSrcATop_Mode:
6503b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kDstATop_Mode:
6513b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            case SkXfermode::kModulate_Mode:
6523b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                return true;
6533b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            default:
6543b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                return false;
6553b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        }
6563b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
6573b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org
6583b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    /* Returns true unless we only need the shape of the drawing. */
6593b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    bool needSource() {
6603b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        if (fXfermode == SkXfermode::kClear_Mode) {
6613b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            return false;
6623b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        }
6633b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        return true;
6643b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
6653b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org
6663b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    /* If the shape is different than the alpha component of the content, then
6673b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org     * setShape should be called with the shape.  In particular, images and
6683b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org     * devices have rectangular shape.
6693b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org     */
6703b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    void setShape(const SkPath& shape) {
6713b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        fShape = shape;
6723b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
6733b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org
674b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.orgprivate:
675b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkPDFDevice* fDevice;
676b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    ContentEntry* fContentEntry;
677b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkXfermode::Mode fXfermode;
678fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com    SkPDFFormXObject* fDstFormXObject;
6793b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkPath fShape;
680b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org
681b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    void init(const SkClipStack* clipStack, const SkRegion& clipRegion,
682b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org              const SkMatrix& matrix, const SkPaint& paint, bool hasText) {
68383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com        // Shape has to be flatten before we get here.
68483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com        if (matrix.hasPerspective()) {
68583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com            NOT_IMPLEMENTED(!matrix.hasPerspective(), false);
686dc37e20647b92528ba9e6a4074cb0f8cc7fbe6b5vandebo@chromium.org            return;
687dc37e20647b92528ba9e6a4074cb0f8cc7fbe6b5vandebo@chromium.org        }
688b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        if (paint.getXfermode()) {
689b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org            paint.getXfermode()->asMode(&fXfermode);
690b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        }
691b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        fContentEntry = fDevice->setUpContentEntry(clipStack, clipRegion,
692b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                                   matrix, paint, hasText,
693b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                                   &fDstFormXObject);
694b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    }
695b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org};
696b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org
6979b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org////////////////////////////////////////////////////////////////////////////////
6989b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
69989443aba5bfa2b040dc9fd24938b7d0b3decd737reedstatic inline SkImageInfo make_content_info(const SkISize& contentSize,
70089443aba5bfa2b040dc9fd24938b7d0b3decd737reed                                            const SkMatrix* initialTransform) {
701900ecf2f1579d42c9d2959831787af0346320f86reed@google.com    SkImageInfo info;
702a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org    if (initialTransform) {
703a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org        // Compute the size of the drawing area.
704a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org        SkVector drawingSize;
705a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org        SkMatrix inverse;
706663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org        drawingSize.set(SkIntToScalar(contentSize.fWidth),
707663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org                        SkIntToScalar(contentSize.fHeight));
708b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org        if (!initialTransform->invert(&inverse)) {
709386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org            // This shouldn't happen, initial transform should be invertible.
710386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org            SkASSERT(false);
711b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org            inverse.reset();
712b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org        }
713a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org        inverse.mapVectors(&drawingSize, 1);
714a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org        SkISize size = SkSize::Make(drawingSize.fX, drawingSize.fY).toRound();
715900ecf2f1579d42c9d2959831787af0346320f86reed@google.com        info = SkImageInfo::MakeUnknown(abs(size.fWidth), abs(size.fHeight));
716a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org    } else {
717900ecf2f1579d42c9d2959831787af0346320f86reed@google.com        info = SkImageInfo::MakeUnknown(abs(contentSize.fWidth),
718900ecf2f1579d42c9d2959831787af0346320f86reed@google.com                                        abs(contentSize.fHeight));
719a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org    }
72089443aba5bfa2b040dc9fd24938b7d0b3decd737reed    return info;
721f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com}
722f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
723663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org// TODO(vandebo) change pageSize to SkSize.
724152612938020fa46999f33668027d5bc0f7afd18ctguil@chromium.orgSkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
72575f97e452e8f2ee55cd2b283df7d7734f48bc2bfvandebo@chromium.org                         const SkMatrix& initialTransform)
72689443aba5bfa2b040dc9fd24938b7d0b3decd737reed    : fPageSize(pageSize)
72789443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fContentSize(contentSize)
72889443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fLastContentEntry(NULL)
72989443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fLastMarginContentEntry(NULL)
73089443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fClipStack(NULL)
73189443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fEncoder(NULL)
73289443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fRasterDpi(72.0f)
73389443aba5bfa2b040dc9fd24938b7d0b3decd737reed{
73489443aba5bfa2b040dc9fd24938b7d0b3decd737reed    const SkImageInfo info = make_content_info(contentSize, &initialTransform);
73589443aba5bfa2b040dc9fd24938b7d0b3decd737reed
73683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com    // Just report that PDF does not supports perspective in the
73783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com    // initial transform.
738aa6c4d2587cf155eb8d74ac29225c9bcac13cd9bedisonn@google.com    NOT_IMPLEMENTED(initialTransform.hasPerspective(), true);
739aa6c4d2587cf155eb8d74ac29225c9bcac13cd9bedisonn@google.com
74077bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    // Skia generally uses the top left as the origin but PDF natively has the
741a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org    // origin at the bottom left. This matrix corrects for that.  But that only
742a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org    // needs to be done once, we don't do it when layering.
743663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org    fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight));
744663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org    fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1);
74577bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    fInitialTransform.preConcat(initialTransform);
74689443aba5bfa2b040dc9fd24938b7d0b3decd737reed    fLegacyBitmap.setInfo(info);
74777bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org
74889443aba5bfa2b040dc9fd24938b7d0b3decd737reed    SkIRect existingClip = SkIRect::MakeWH(info.width(), info.height());
749a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org    fExistingClipRegion.setRect(existingClip);
750a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org    this->init();
751a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org}
752a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org
753663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org// TODO(vandebo) change layerSize to SkSize.
754a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.orgSkPDFDevice::SkPDFDevice(const SkISize& layerSize,
755a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org                         const SkClipStack& existingClipStack,
756a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org                         const SkRegion& existingClipRegion)
75789443aba5bfa2b040dc9fd24938b7d0b3decd737reed    : fPageSize(layerSize)
75889443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fContentSize(layerSize)
75989443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fExistingClipStack(existingClipStack)
76089443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fExistingClipRegion(existingClipRegion)
76189443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fLastContentEntry(NULL)
76289443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fLastMarginContentEntry(NULL)
76389443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fClipStack(NULL)
76489443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fEncoder(NULL)
76589443aba5bfa2b040dc9fd24938b7d0b3decd737reed    , fRasterDpi(72.0f)
76689443aba5bfa2b040dc9fd24938b7d0b3decd737reed{
767a0c7edbb0804144ab320951db5c741eea247fc0fvandebo@chromium.org    fInitialTransform.reset();
76889443aba5bfa2b040dc9fd24938b7d0b3decd737reed    fLegacyBitmap.setInfo(make_content_info(layerSize, NULL));
76989443aba5bfa2b040dc9fd24938b7d0b3decd737reed
77077bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    this->init();
77177bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org}
77277bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org
77377bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.orgSkPDFDevice::~SkPDFDevice() {
7749859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    this->cleanUp(true);
77577bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org}
77677bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org
77777bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.orgvoid SkPDFDevice::init() {
7782a006c112743e07ce258ca223631fc19233f5ddcreed@google.com    fAnnotations = NULL;
77977bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    fResourceDict = NULL;
780e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org    fContentEntries.free();
781b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    fLastContentEntry = NULL;
782e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org    fMarginContentEntries.free();
7838dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    fLastMarginContentEntry = NULL;
7849859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    fDrawingArea = kContent_DrawingArea;
785e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org    if (fFontGlyphUsage.get() == NULL) {
7869859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org        fFontGlyphUsage.reset(new SkPDFGlyphSetMap());
7879859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    }
7889b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
7899b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
7909859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.orgvoid SkPDFDevice::cleanUp(bool clearFontUsage) {
7919b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    fGraphicStateResources.unrefAll();
7929b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    fXObjectResources.unrefAll();
79328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    fFontResources.unrefAll();
794da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org    fShaderResources.unrefAll();
7952a006c112743e07ce258ca223631fc19233f5ddcreed@google.com    SkSafeUnref(fAnnotations);
796fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com    SkSafeUnref(fResourceDict);
797b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    fNamedDestinations.deleteAll();
7982a006c112743e07ce258ca223631fc19233f5ddcreed@google.com
7999859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    if (clearFontUsage) {
8009859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org        fFontGlyphUsage->reset();
8019859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    }
8029b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
8039b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
8049fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgvoid SkPDFDevice::clear(SkColor color) {
8059859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    this->cleanUp(true);
80677bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    this->init();
80777bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org
80877bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    SkPaint paint;
80977bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    paint.setColor(color);
81077bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    paint.setStyle(SkPaint::kFill_Style);
8119fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkMatrix identity;
8129fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    identity.reset();
81313d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry content(this, &fExistingClipStack, fExistingClipRegion,
81413d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org                               identity, paint);
815b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    internalDrawPaint(paint, content.entry());
8169b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
8179b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
8189b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.orgvoid SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
8199b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    SkPaint newPaint = paint;
8209b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    newPaint.setStyle(SkPaint::kFill_Style);
82113d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry content(this, d, newPaint);
822b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    internalDrawPaint(newPaint, content.entry());
82377bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org}
82477bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org
825b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.orgvoid SkPDFDevice::internalDrawPaint(const SkPaint& paint,
826b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                    ContentEntry* contentEntry) {
827b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (!contentEntry) {
828b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        return;
829b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    }
83077bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    SkRect bbox = SkRect::MakeWH(SkIntToScalar(this->width()),
83177bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org                                 SkIntToScalar(this->height()));
83277bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    SkMatrix inverse;
833d2cfa7422e2b0928970b3b0fa1abe1d73113fc1dcommit-bot@chromium.org    if (!contentEntry->fState.fMatrix.invert(&inverse)) {
834386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org        return;
835b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org    }
83677bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org    inverse.mapRect(&bbox);
83777bcaa324a574584331322d98768582d9232f7fcvandebo@chromium.org
838b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkPDFUtils::AppendRectangle(bbox, &contentEntry->fContent);
8399fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
840b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                          &contentEntry->fContent);
8419b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
8429b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
8439b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.orgvoid SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
8449b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                             size_t count, const SkPoint* points,
84525adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org                             const SkPaint& passedPaint) {
84625adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    if (count == 0) {
84725adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        return;
84825adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
84925adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org
850b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    if (handlePointAnnotation(points, count, *d.fMatrix, passedPaint)) {
851b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        return;
852b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    }
853b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
854ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath.
855ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    // We only use this when there's a path effect because of the overhead
856ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    // of multiple calls to setUpContentEntry it causes.
857ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    if (passedPaint.getPathEffect()) {
858ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        if (d.fClip->isEmpty()) {
859ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            return;
860ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        }
861ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        SkDraw pointDraw(d);
862ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        pointDraw.fDevice = this;
863ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        pointDraw.drawPoints(mode, count, points, passedPaint, true);
864ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        return;
865ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    }
866ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org
86725adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    const SkPaint* paint = &passedPaint;
86825adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    SkPaint modifiedPaint;
86925adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org
87025adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    if (mode == SkCanvas::kPoints_PointMode &&
87125adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            paint->getStrokeCap() != SkPaint::kRound_Cap) {
87225adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        modifiedPaint = *paint;
87325adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        paint = &modifiedPaint;
87425adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        if (paint->getStrokeWidth()) {
87525adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            // PDF won't draw a single point with square/butt caps because the
87625adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            // orientation is ambiguous.  Draw a rectangle instead.
87725adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            modifiedPaint.setStyle(SkPaint::kFill_Style);
87825adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            SkScalar strokeWidth = paint->getStrokeWidth();
87925adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            SkScalar halfStroke = SkScalarHalf(strokeWidth);
88025adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            for (size_t i = 0; i < count; i++) {
88125adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org                SkRect r = SkRect::MakeXYWH(points[i].fX, points[i].fY, 0, 0);
88225adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org                r.inset(-halfStroke, -halfStroke);
88325adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org                drawRect(d, r, modifiedPaint);
88425adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            }
88525adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            return;
88625adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        } else {
88725adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            modifiedPaint.setStrokeCap(SkPaint::kRound_Cap);
88825adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        }
88925adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
89025adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org
89113d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry content(this, d, *paint);
892b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (!content.entry()) {
8939b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        return;
894fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    }
8959b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
8969b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    switch (mode) {
8979b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        case SkCanvas::kPolygon_PointMode:
8989fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org            SkPDFUtils::MoveTo(points[0].fX, points[0].fY,
899b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                               &content.entry()->fContent);
9009db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.org            for (size_t i = 1; i < count; i++) {
9019fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                SkPDFUtils::AppendLine(points[i].fX, points[i].fY,
902b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                       &content.entry()->fContent);
9039db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.org            }
904b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org            SkPDFUtils::StrokePath(&content.entry()->fContent);
9059b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            break;
9069b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        case SkCanvas::kLines_PointMode:
9079b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            for (size_t i = 0; i < count/2; i++) {
9089db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.org                SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY,
909b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                   &content.entry()->fContent);
9109db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.org                SkPDFUtils::AppendLine(points[i * 2 + 1].fX,
9119fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                       points[i * 2 + 1].fY,
912b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                       &content.entry()->fContent);
913b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                SkPDFUtils::StrokePath(&content.entry()->fContent);
9149b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            }
9159b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            break;
9169b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        case SkCanvas::kPoints_PointMode:
91725adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            SkASSERT(paint->getStrokeCap() == SkPaint::kRound_Cap);
91825adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            for (size_t i = 0; i < count; i++) {
91925adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org                SkPDFUtils::MoveTo(points[i].fX, points[i].fY,
920b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                   &content.entry()->fContent);
921b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                SkPDFUtils::ClosePath(&content.entry()->fContent);
922b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                SkPDFUtils::StrokePath(&content.entry()->fContent);
9239b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            }
9249b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            break;
9259b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        default:
9269b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            SkASSERT(false);
9279b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    }
9289b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
9299b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
930969fd6afc45df247377c35d9a273dce752af04aacommit-bot@chromium.orgvoid SkPDFDevice::drawRect(const SkDraw& d, const SkRect& rect,
9319b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                           const SkPaint& paint) {
932969fd6afc45df247377c35d9a273dce752af04aacommit-bot@chromium.org    SkRect r = rect;
933969fd6afc45df247377c35d9a273dce752af04aacommit-bot@chromium.org    r.sort();
934969fd6afc45df247377c35d9a273dce752af04aacommit-bot@chromium.org
9359b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    if (paint.getPathEffect()) {
93625adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        if (d.fClip->isEmpty()) {
93725adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            return;
93825adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        }
9399b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        SkPath path;
9409b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        path.addRect(r);
941ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        drawPath(d, path, paint, NULL, true);
9429b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        return;
9439b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    }
944b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org
945b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    if (handleRectAnnotation(r, *d.fMatrix, paint)) {
946238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org        return;
947238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    }
948238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
94913d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry content(this, d, paint);
950b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (!content.entry()) {
95125adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        return;
95225adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
953b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkPDFUtils::AppendRectangle(r, &content.entry()->fContent);
9549db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.org    SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType,
955b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                          &content.entry()->fContent);
9569b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
9579b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
95889443aba5bfa2b040dc9fd24938b7d0b3decd737reedvoid SkPDFDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
959a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    SkPath  path;
960a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    path.addRRect(rrect);
961a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com    this->drawPath(draw, path, paint, NULL, true);
962a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com}
963a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com
96489443aba5bfa2b040dc9fd24938b7d0b3decd737reedvoid SkPDFDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
96589443aba5bfa2b040dc9fd24938b7d0b3decd737reed    SkPath  path;
96689443aba5bfa2b040dc9fd24938b7d0b3decd737reed    path.addOval(oval);
96789443aba5bfa2b040dc9fd24938b7d0b3decd737reed    this->drawPath(draw, path, paint, NULL, true);
96889443aba5bfa2b040dc9fd24938b7d0b3decd737reed}
96989443aba5bfa2b040dc9fd24938b7d0b3decd737reed
970ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.orgvoid SkPDFDevice::drawPath(const SkDraw& d, const SkPath& origPath,
97102cc5aa736086320649d8a932515691ae18a0dd5vandebo@chromium.org                           const SkPaint& paint, const SkMatrix* prePathMatrix,
97202cc5aa736086320649d8a932515691ae18a0dd5vandebo@chromium.org                           bool pathIsMutable) {
973ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    SkPath modifiedPath;
974ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    SkPath* pathPtr = const_cast<SkPath*>(&origPath);
975ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org
976ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    SkMatrix matrix = *d.fMatrix;
977ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    if (prePathMatrix) {
978ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
979ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            if (!pathIsMutable) {
980ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org                pathPtr = &modifiedPath;
981ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org                pathIsMutable = true;
982ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            }
983ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            origPath.transform(*prePathMatrix, pathPtr);
984ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        } else {
98592362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org            matrix.preConcat(*prePathMatrix);
986ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        }
987ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    }
98802cc5aa736086320649d8a932515691ae18a0dd5vandebo@chromium.org
9897d71f7f655cab6b6194f6c765ca33c1a6d512f5evandebo@chromium.org    if (paint.getPathEffect()) {
99025adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        if (d.fClip->isEmpty()) {
99125adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org            return;
99225adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        }
993ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        if (!pathIsMutable) {
994ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            pathPtr = &modifiedPath;
995ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            pathIsMutable = true;
996ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        }
997ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        bool fill = paint.getFillPath(origPath, pathPtr);
9987d71f7f655cab6b6194f6c765ca33c1a6d512f5evandebo@chromium.org
9997e2ff7cf7da604b29378978ef5d4655499485368vandebo@chromium.org        SkPaint noEffectPaint(paint);
1000ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        noEffectPaint.setPathEffect(NULL);
1001ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        if (fill) {
1002ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            noEffectPaint.setStyle(SkPaint::kFill_Style);
1003ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        } else {
1004ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            noEffectPaint.setStyle(SkPaint::kStroke_Style);
1005ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org            noEffectPaint.setStrokeWidth(0);
1006ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        }
1007ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org        drawPath(d, *pathPtr, noEffectPaint, NULL, true);
10087d71f7f655cab6b6194f6c765ca33c1a6d512f5evandebo@chromium.org        return;
10097d71f7f655cab6b6194f6c765ca33c1a6d512f5evandebo@chromium.org    }
1010ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org
101192ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org#ifdef SK_PDF_USE_PATHOPS
1012a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com    if (handleInversePath(d, origPath, paint, pathIsMutable, prePathMatrix)) {
101392ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        return;
101492ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    }
101592ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org#endif
101692ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
1017a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com    if (handleRectAnnotation(pathPtr->getBounds(), matrix, paint)) {
1018238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org        return;
1019238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    }
1020238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
1021a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com    ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
1022b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (!content.entry()) {
102325adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        return;
102425adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
1025683001ce0de70c859ea5e5353245b18cadbefc45vandebo@chromium.org    SkPDFUtils::EmitPath(*pathPtr, paint.getStyle(),
1026683001ce0de70c859ea5e5353245b18cadbefc45vandebo@chromium.org                         &content.entry()->fContent);
1027ff3903202e5bce39016bac896ba6a417dc707d52vandebo@chromium.org    SkPDFUtils::PaintPath(paint.getStyle(), pathPtr->getFillType(),
1028b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                          &content.entry()->fContent);
10299b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
10309b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
10312ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.comvoid SkPDFDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
10322ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com                                 const SkRect* src, const SkRect& dst,
1033eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org                                 const SkPaint& paint,
1034eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org                                 SkCanvas::DrawBitmapRectFlags flags) {
1035eed779d866e1e239bfb9ebc6a225b7345a41adf9commit-bot@chromium.org    // TODO: this code path must be updated to respect the flags parameter
10362ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    SkMatrix    matrix;
10372ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    SkRect      bitmapBounds, tmpSrc, tmpDst;
10382ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    SkBitmap    tmpBitmap;
10392ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com
10402ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    bitmapBounds.isetWH(bitmap.width(), bitmap.height());
10412ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com
10422ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    // Compute matrix from the two rectangles
10432ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    if (src) {
10442ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        tmpSrc = *src;
10452ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    } else {
10462ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        tmpSrc = bitmapBounds;
10472ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    }
10482ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
10492ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com
10502ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    const SkBitmap* bitmapPtr = &bitmap;
10512ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com
10522ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if
10532ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    // needed (if the src was clipped). No check needed if src==null.
10542ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    if (src) {
10552ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        if (!bitmapBounds.contains(*src)) {
10562ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com            if (!tmpSrc.intersect(bitmapBounds)) {
10572ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com                return; // nothing to draw
10582ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com            }
10592ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com            // recompute dst, based on the smaller tmpSrc
10602ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com            matrix.mapRect(&tmpDst, tmpSrc);
10612ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        }
10622ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com
10632ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        // since we may need to clamp to the borders of the src rect within
10642ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        // the bitmap, we extract a subset.
10652ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        // TODO: make sure this is handled in drawBitmap and remove from here.
10662ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        SkIRect srcIR;
10672ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        tmpSrc.roundOut(&srcIR);
10682ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        if (!bitmap.extractSubset(&tmpBitmap, srcIR)) {
10692ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com            return;
10702ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        }
10712ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        bitmapPtr = &tmpBitmap;
10722ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com
10732ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        // Since we did an extract, we need to adjust the matrix accordingly
10742ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        SkScalar dx = 0, dy = 0;
10752ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        if (srcIR.fLeft > 0) {
10762ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com            dx = SkIntToScalar(srcIR.fLeft);
10772ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        }
10782ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        if (srcIR.fTop > 0) {
10792ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com            dy = SkIntToScalar(srcIR.fTop);
10802ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        }
10812ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        if (dx || dy) {
10822ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com            matrix.preTranslate(dx, dy);
10832ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com        }
10842ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com    }
10859bf380ce7f848dfb5886dd52b82746521454b739robertphillips@google.com    this->drawBitmap(draw, *bitmapPtr, matrix, paint);
10862ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com}
10872ae67e70cd06be3f64c6290be7724af8ce6bc853edisonn@google.com
1088fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.orgvoid SkPDFDevice::drawBitmap(const SkDraw& d, const SkBitmap& bitmap,
10899bf380ce7f848dfb5886dd52b82746521454b739robertphillips@google.com                             const SkMatrix& matrix, const SkPaint& paint) {
1090fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    if (d.fClip->isEmpty()) {
1091fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org        return;
1092fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    }
1093fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org
10947e2ff7cf7da604b29378978ef5d4655499485368vandebo@chromium.org    SkMatrix transform = matrix;
10959fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    transform.postConcat(*d.fMatrix);
10963b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    this->internalDrawBitmap(transform, d.fClipStack, *d.fClip, bitmap, NULL,
10973b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                             paint);
10989b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
10999b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1100fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.orgvoid SkPDFDevice::drawSprite(const SkDraw& d, const SkBitmap& bitmap,
11019b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                             int x, int y, const SkPaint& paint) {
1102fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    if (d.fClip->isEmpty()) {
1103fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org        return;
1104fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    }
1105fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org
11067e2ff7cf7da604b29378978ef5d4655499485368vandebo@chromium.org    SkMatrix matrix;
1107a6d59f60aab59fb6556841b063ead5d49b46ba8dreed@google.com    matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
11083b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    this->internalDrawBitmap(matrix, d.fClipStack, *d.fClip, bitmap, NULL,
11093b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                             paint);
11109b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
11119b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
111228be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.orgvoid SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
11139b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                           SkScalar x, SkScalar y, const SkPaint& paint) {
1114b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com    NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
1115b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com    if (paint.getMaskFilter() != NULL) {
1116b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com        // Don't pretend we support drawing MaskFilters, it makes for artifacts
1117b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com        // making text unreadable (e.g. same text twice when using CSS shadows).
1118b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com        return;
1119b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com    }
112025adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    SkPaint textPaint = calculate_text_paint(paint);
112113d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry content(this, d, textPaint, true);
1122b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (!content.entry()) {
1123fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org        return;
1124fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    }
1125fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org
11264e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    SkGlyphStorage storage(0);
1127139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman    const uint16_t* glyphIDs = NULL;
1128aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.com    int numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs);
11294e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
113028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
113128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
11329a87cee904e2d8f0ea6a0e7e3ca864262a8cb7c4bungeman@google.com    align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y);
1133b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    content.entry()->fContent.writeText("BT\n");
1134b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    set_text_transform(x, y, textPaint.getTextSkewX(),
1135b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                       &content.entry()->fContent);
1136aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.com    int consumedGlyphCount = 0;
11372a22e10ab2946c5590cd2a258427ce3ccfca9bfavandebo@chromium.org    while (numGlyphs > consumedGlyphCount) {
1138b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry());
1139b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        SkPDFFont* font = content.entry()->fState.fFont;
1140139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman        //TODO: the const_cast here is a bug if the encoding started out as glyph encoding.
1141aec406650cbfa4ef65d83db5ff4f82572e8e098freed@google.com        int availableGlyphs =
1142139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman            font->glyphsToPDFFontEncoding(const_cast<uint16_t*>(glyphIDs) + consumedGlyphCount,
11430129410fbe4b88a0632fb7aa5185610b30e69852vandebo@chromium.org                                          numGlyphs - consumedGlyphCount);
11449859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org        fFontGlyphUsage->noteGlyphUsage(font, glyphIDs + consumedGlyphCount,
11459859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org                                        availableGlyphs);
1146cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org        SkString encodedString =
1147f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com            SkPDFString::FormatString(glyphIDs + consumedGlyphCount,
1148cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org                                      availableGlyphs, font->multiByteGlyphs());
1149b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        content.entry()->fContent.writeText(encodedString.c_str());
11500129410fbe4b88a0632fb7aa5185610b30e69852vandebo@chromium.org        consumedGlyphCount += availableGlyphs;
1151b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        content.entry()->fContent.writeText(" Tj\n");
11522a22e10ab2946c5590cd2a258427ce3ccfca9bfavandebo@chromium.org    }
1153b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    content.entry()->fContent.writeText("ET\n");
11549b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
11559b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1156fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.orgvoid SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len,
11579b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                              const SkScalar pos[], SkScalar constY,
11589b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                              int scalarsPerPos, const SkPaint& paint) {
1159b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com    NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
1160b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com    if (paint.getMaskFilter() != NULL) {
1161b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com        // Don't pretend we support drawing MaskFilters, it makes for artifacts
1162b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com        // making text unreadable (e.g. same text twice when using CSS shadows).
1163b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com        return;
1164b62f93fdbcdea16329847e30a351ee35a0552e83edisonn@google.com    }
116528be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
11669fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkPaint textPaint = calculate_text_paint(paint);
116713d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry content(this, d, textPaint, true);
1168b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (!content.entry()) {
116925adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        return;
117025adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
117128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
11724e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    SkGlyphStorage storage(0);
1173139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman    const uint16_t* glyphIDs = NULL;
1174139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman    size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphIDs);
11754e1cc6ac450903510b96c1b12f6ee6f420044a66vandebo@chromium.org    textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
117628be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
117728be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
1178b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    content.entry()->fContent.writeText("BT\n");
1179b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    updateFont(textPaint, glyphIDs[0], content.entry());
11802a22e10ab2946c5590cd2a258427ce3ccfca9bfavandebo@chromium.org    for (size_t i = 0; i < numGlyphs; i++) {
1181b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        SkPDFFont* font = content.entry()->fState.fFont;
11820129410fbe4b88a0632fb7aa5185610b30e69852vandebo@chromium.org        uint16_t encodedValue = glyphIDs[i];
11830129410fbe4b88a0632fb7aa5185610b30e69852vandebo@chromium.org        if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
1184139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman            // The current pdf font cannot encode the current glyph.
1185139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman            // Try to get a pdf font which can encode the current glyph.
1186b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org            updateFont(textPaint, glyphIDs[i], content.entry());
1187139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman            font = content.entry()->fState.fFont;
1188139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman            if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) {
1189139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman                SkDEBUGFAIL("PDF could not encode glyph.");
1190139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman                continue;
1191139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman            }
11922a22e10ab2946c5590cd2a258427ce3ccfca9bfavandebo@chromium.org        }
1193139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman
11949859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org        fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1);
119528be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        SkScalar x = pos[i * scalarsPerPos];
119628be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
11979a87cee904e2d8f0ea6a0e7e3ca864262a8cb7c4bungeman@google.com        align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y);
1198139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman        set_text_transform(x, y, textPaint.getTextSkewX(), &content.entry()->fContent);
1199cae5fba82e687d674b076b10cdc8aba46e1ac3b3vandebo@chromium.org        SkString encodedString =
1200139c136944f3af0cba3a25ac65c642c05fe46ac8bungeman            SkPDFString::FormatString(&encodedValue, 1, font->multiByteGlyphs());
1201b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        content.entry()->fContent.writeText(encodedString.c_str());
1202b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        content.entry()->fContent.writeText(" Tj\n");
120328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    }
1204b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    content.entry()->fContent.writeText("ET\n");
12059b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
12069b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1207fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.orgvoid SkPDFDevice::drawTextOnPath(const SkDraw& d, const void* text, size_t len,
12089b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                                 const SkPath& path, const SkMatrix* matrix,
12099b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                                 const SkPaint& paint) {
1210fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    if (d.fClip->isEmpty()) {
1211fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org        return;
1212fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    }
1213290e3bbcf4c8b33c161d7b6a3edb12168e0e6910vandebo@chromium.org    d.drawTextOnPath((const char*)text, len, path, matrix, paint);
12149b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
12159b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1216fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.orgvoid SkPDFDevice::drawVertices(const SkDraw& d, SkCanvas::VertexMode,
12179b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                               int vertexCount, const SkPoint verts[],
12189b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                               const SkPoint texs[], const SkColor colors[],
12199b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                               SkXfermode* xmode, const uint16_t indices[],
12209b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                               int indexCount, const SkPaint& paint) {
1221fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    if (d.fClip->isEmpty()) {
1222fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org        return;
1223fb0b0edd86d71bb423fa921eaac1e2071602115cvandebo@chromium.org    }
122485e143c33c214e54187aa28146aa7666961a0d17reed@google.com    // TODO: implement drawVertices
12259b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
12269b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
12273b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.orgvoid SkPDFDevice::drawDevice(const SkDraw& d, SkBaseDevice* device,
12283b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                             int x, int y, const SkPaint& paint) {
12293da3b621c34810514a6d415a1dc782bd21648c3ccommit-bot@chromium.org    // our onCreateDevice() always creates SkPDFDevice subclasses.
1230ee7a9569f2745b949dbafa15927d70a4e08c92aevandebo@chromium.org    SkPDFDevice* pdfDevice = static_cast<SkPDFDevice*>(device);
1231f4ff39ca4854d64fce9189745af615bb9bc37faactguil@chromium.org    if (pdfDevice->isContentEmpty()) {
1232ee7a9569f2745b949dbafa15927d70a4e08c92aevandebo@chromium.org        return;
1233ee7a9569f2745b949dbafa15927d70a4e08c92aevandebo@chromium.org    }
1234ee7a9569f2745b949dbafa15927d70a4e08c92aevandebo@chromium.org
1235eb6c7596af1a1fc7860e27ff2f678a33b2576c0fvandebo@chromium.org    SkMatrix matrix;
1236a6d59f60aab59fb6556841b063ead5d49b46ba8dreed@google.com    matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
123713d14a9dbd2cf0a9654045cc967e92626690631avandebo@chromium.org    ScopedContentEntry content(this, d.fClipStack, *d.fClip, matrix, paint);
1238b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (!content.entry()) {
123925adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        return;
124025adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
12413b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (content.needShape()) {
12423b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        SkPath shape;
12433b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        shape.addRect(SkRect::MakeXYWH(SkIntToScalar(x), SkIntToScalar(y),
1244fd3c8c243ab190604e134910a1d6c1326d21e374vandebo@chromium.org                                       SkIntToScalar(device->width()),
1245fd3c8c243ab190604e134910a1d6c1326d21e374vandebo@chromium.org                                       SkIntToScalar(device->height())));
12463b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        content.setShape(shape);
12473b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
12483b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (!content.needSource()) {
12493b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        return;
12503b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
1251eb6c7596af1a1fc7860e27ff2f678a33b2576c0fvandebo@chromium.org
12523b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkAutoTUnref<SkPDFFormXObject> xObject(new SkPDFFormXObject(pdfDevice));
12533b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()),
1254b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                &content.entry()->fContent);
12559859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org
12569859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    // Merge glyph sets from the drawn device.
12579859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage());
12589b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
12599b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
126089443aba5bfa2b040dc9fd24938b7d0b3decd737reedSkImageInfo SkPDFDevice::imageInfo() const {
126189443aba5bfa2b040dc9fd24938b7d0b3decd737reed    return fLegacyBitmap.info();
126289443aba5bfa2b040dc9fd24938b7d0b3decd737reed}
126389443aba5bfa2b040dc9fd24938b7d0b3decd737reed
126440a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.comvoid SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) {
126540a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com    INHERITED::onAttachToCanvas(canvas);
126640a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com
126740a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com    // Canvas promises that this ptr is valid until onDetachFromCanvas is called
126840a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com    fClipStack = canvas->getClipStack();
126940a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com}
127040a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com
127140a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.comvoid SkPDFDevice::onDetachFromCanvas() {
127240a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com    INHERITED::onDetachFromCanvas();
127340a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com
127440a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com    fClipStack = NULL;
127540a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com}
127640a1ae4df28810aa5aa5cf2627d8387b2dfb867arobertphillips@google.com
12774a8126e7f81384526629b1e21bf89b632ea13cd9reedSkSurface* SkPDFDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) {
12784a8126e7f81384526629b1e21bf89b632ea13cd9reed    return SkSurface::NewRaster(info, &props);
127989443aba5bfa2b040dc9fd24938b7d0b3decd737reed}
128089443aba5bfa2b040dc9fd24938b7d0b3decd737reed
12818dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.orgContentEntry* SkPDFDevice::getLastContentEntry() {
12828dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    if (fDrawingArea == kContent_DrawingArea) {
12838dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        return fLastContentEntry;
12848dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    } else {
12858dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        return fLastMarginContentEntry;
12868dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    }
12878dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org}
12888dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org
1289e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.orgSkAutoTDelete<ContentEntry>* SkPDFDevice::getContentEntries() {
12908dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    if (fDrawingArea == kContent_DrawingArea) {
12919510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org        return &fContentEntries;
12928dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    } else {
12939510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org        return &fMarginContentEntries;
12948dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    }
12958dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org}
12968dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org
12978dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.orgvoid SkPDFDevice::setLastContentEntry(ContentEntry* contentEntry) {
12988dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    if (fDrawingArea == kContent_DrawingArea) {
12998dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        fLastContentEntry = contentEntry;
13008dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    } else {
13018dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        fLastMarginContentEntry = contentEntry;
13028dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    }
13038dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org}
13048dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org
13058dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.orgvoid SkPDFDevice::setDrawingArea(DrawingArea drawingArea) {
13069510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    // A ScopedContentEntry only exists during the course of a draw call, so
13079510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    // this can't be called while a ScopedContentEntry exists.
13088dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    fDrawingArea = drawingArea;
13098dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org}
13108dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org
131147401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.orgSkPDFResourceDict* SkPDFDevice::getResourceDict() {
1312fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com    if (NULL == fResourceDict) {
131347401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org        fResourceDict = SkNEW(SkPDFResourceDict);
13149b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
13159b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        if (fGraphicStateResources.count()) {
13169b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            for (int i = 0; i < fGraphicStateResources.count(); i++) {
131747401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                fResourceDict->insertResourceAsReference(
131847401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                        SkPDFResourceDict::kExtGState_ResourceType,
131947401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                        i, fGraphicStateResources[i]);
13209b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            }
13219b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        }
13229b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
13239b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        if (fXObjectResources.count()) {
13249b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            for (int i = 0; i < fXObjectResources.count(); i++) {
132547401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                fResourceDict->insertResourceAsReference(
132647401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                        SkPDFResourceDict::kXObject_ResourceType,
132747401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                        i, fXObjectResources[i]);
13289b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org            }
13299b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        }
133028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
133128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        if (fFontResources.count()) {
133228be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org            for (int i = 0; i < fFontResources.count(); i++) {
133347401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                fResourceDict->insertResourceAsReference(
133447401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                        SkPDFResourceDict::kFont_ResourceType,
133547401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                        i, fFontResources[i]);
133628be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org            }
133728be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        }
133828be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
1339da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org        if (fShaderResources.count()) {
1340d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org            SkAutoTUnref<SkPDFDict> patterns(new SkPDFDict());
1341da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            for (int i = 0; i < fShaderResources.count(); i++) {
134247401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                fResourceDict->insertResourceAsReference(
134347401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                        SkPDFResourceDict::kPattern_ResourceType,
134447401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                        i, fShaderResources[i]);
1345da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            }
1346da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org        }
13479b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    }
1348fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com    return fResourceDict;
13499b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
13509b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1351f0ec2666d9a3f0f1662f0d63b5147628c49648aavandebo@chromium.orgconst SkTDArray<SkPDFFont*>& SkPDFDevice::getFontResources() const {
1352f0ec2666d9a3f0f1662f0d63b5147628c49648aavandebo@chromium.org    return fFontResources;
1353f0ec2666d9a3f0f1662f0d63b5147628c49648aavandebo@chromium.org}
1354f0ec2666d9a3f0f1662f0d63b5147628c49648aavandebo@chromium.org
13552a006c112743e07ce258ca223631fc19233f5ddcreed@google.comSkPDFArray* SkPDFDevice::copyMediaBox() const {
13562a006c112743e07ce258ca223631fc19233f5ddcreed@google.com    // should this be a singleton?
13572a006c112743e07ce258ca223631fc19233f5ddcreed@google.com    SkAutoTUnref<SkPDFInt> zero(SkNEW_ARGS(SkPDFInt, (0)));
1358f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org
13592a006c112743e07ce258ca223631fc19233f5ddcreed@google.com    SkPDFArray* mediaBox = SkNEW(SkPDFArray);
13609b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    mediaBox->reserve(4);
13619b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    mediaBox->append(zero.get());
13629b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    mediaBox->append(zero.get());
1363c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com    mediaBox->appendInt(fPageSize.fWidth);
1364c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com    mediaBox->appendInt(fPageSize.fHeight);
13659b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    return mediaBox;
13669b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
13679b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1368c2a9b7fe5640af8f0c371561f1ac71b045d6d8ecvandebo@chromium.orgSkStream* SkPDFDevice::content() const {
13695667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.com    SkMemoryStream* result = new SkMemoryStream;
13705667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.com    result->setData(this->copyContentToData())->unref();
13715667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.com    return result;
13725667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.com}
13735667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.com
13748dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.orgvoid SkPDFDevice::copyContentEntriesToData(ContentEntry* entry,
13758dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        SkWStream* data) const {
13769510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    // TODO(ctguil): For margins, I'm not sure fExistingClipStack/Region is the
13779510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    // right thing to pass here.
13788dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    GraphicStackState gsState(fExistingClipStack, fExistingClipRegion, data);
13799510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    while (entry != NULL) {
1380663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org        SkPoint translation;
1381663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org        translation.iset(this->getOrigin());
13828dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        translation.negate();
13838dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        gsState.updateClip(entry->fState.fClipStack, entry->fState.fClipRegion,
13848dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org                           translation);
13858dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        gsState.updateMatrix(entry->fState.fMatrix);
13868dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        gsState.updateDrawingState(entry->fState);
13879510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org
13888dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        SkAutoDataUnref copy(entry->fContent.copyToData());
138959f46b81f8bdd1b524f5cc43bc27603f9604c71arobertphillips@google.com        data->write(copy->data(), copy->size());
13908dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        entry = entry->fNext.get();
13918dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    }
13928dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    gsState.drainStack();
13938dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org}
13948dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org
13955667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.comSkData* SkPDFDevice::copyContentToData() const {
13969fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkDynamicMemoryWStream data;
13979fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (fInitialTransform.getType() != SkMatrix::kIdentity_Mask) {
13989fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkPDFUtils::AppendTransform(fInitialTransform, &data);
1399c2a9b7fe5640af8f0c371561f1ac71b045d6d8ecvandebo@chromium.org    }
14009510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org
14018dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    // TODO(aayushkumar): Apply clip along the margins.  Currently, webkit
14028dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    // colors the contentArea white before it starts drawing into it and
14038dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    // that currently acts as our clip.
14048dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    // Also, think about adding a transform here (or assume that the values
14058dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    // sent across account for that)
14068dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    SkPDFDevice::copyContentEntriesToData(fMarginContentEntries.get(), &data);
14079510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org
14089fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // If the content area is the entire page, then we don't need to clip
14099fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // the content area (PDF area clips to the page size).  Otherwise,
14109fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // we have to clip to the content area; we've already applied the
14119fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    // initial transform, so just clip to the device size.
14129fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (fPageSize != fContentSize) {
14138637a365518a82901d313d61eecd83a0c5102fe9robertphillips@google.com        SkRect r = SkRect::MakeWH(SkIntToScalar(this->width()),
14148637a365518a82901d313d61eecd83a0c5102fe9robertphillips@google.com                                  SkIntToScalar(this->height()));
14159fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        emit_clip(NULL, &r, &data);
14169fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
14179859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org
14188dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    SkPDFDevice::copyContentEntriesToData(fContentEntries.get(), &data);
14199fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
14205667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.com    // potentially we could cache this SkData, and only rebuild it if we
14215667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.com    // see that our state has changed.
14225667afc5cb4a8cd15a27667f222b6d9c94d61c38reed@google.com    return data.copyToData();
14239b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
14249b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1425d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org#ifdef SK_PDF_USE_PATHOPS
142692ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org/* Draws an inverse filled path by using Path Ops to compute the positive
142792ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org * inverse using the current clip as the inverse bounds.
142892ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org * Return true if this was an inverse path and was properly handled,
142992ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org * otherwise returns false and the normal drawing routine should continue,
143092ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org * either as a (incorrect) fallback or because the path was not inverse
143192ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org * in the first place.
143292ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org */
143392ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.orgbool SkPDFDevice::handleInversePath(const SkDraw& d, const SkPath& origPath,
1434a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com                                    const SkPaint& paint, bool pathIsMutable,
1435a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com                                    const SkMatrix* prePathMatrix) {
143692ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    if (!origPath.isInverseFillType()) {
143792ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        return false;
143892ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    }
143992ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
144092ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    if (d.fClip->isEmpty()) {
144192ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        return false;
144292ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    }
144392ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
144492ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    SkPath modifiedPath;
144592ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    SkPath* pathPtr = const_cast<SkPath*>(&origPath);
144692ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    SkPaint noInversePaint(paint);
144792ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
144892ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    // Merge stroking operations into final path.
144992ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    if (SkPaint::kStroke_Style == paint.getStyle() ||
145092ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        SkPaint::kStrokeAndFill_Style == paint.getStyle()) {
145192ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        bool doFillPath = paint.getFillPath(origPath, &modifiedPath);
145292ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        if (doFillPath) {
145392ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org            noInversePaint.setStyle(SkPaint::kFill_Style);
145492ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org            noInversePaint.setStrokeWidth(0);
145592ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org            pathPtr = &modifiedPath;
145692ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        } else {
145792ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org            // To be consistent with the raster output, hairline strokes
145892ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org            // are rendered as non-inverted.
145992ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org            modifiedPath.toggleInverseFillType();
146092ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org            drawPath(d, modifiedPath, paint, NULL, true);
146192ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org            return true;
146292ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        }
146392ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    }
146492ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
146592ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    // Get bounds of clip in current transform space
146692ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    // (clip bounds are given in device space).
146792ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    SkRect bounds;
146892ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    SkMatrix transformInverse;
1469a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com    SkMatrix totalMatrix = *d.fMatrix;
1470a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com    if (prePathMatrix) {
1471a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com        totalMatrix.preConcat(*prePathMatrix);
1472a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com    }
1473a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com    if (!totalMatrix.invert(&transformInverse)) {
147492ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        return false;
147592ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    }
147692ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    bounds.set(d.fClip->getBounds());
147792ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    transformInverse.mapRect(&bounds);
147892ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
147992ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    // Extend the bounds by the line width (plus some padding)
148092ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    // so the edge doesn't cause a visible stroke.
148192ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    bounds.outset(paint.getStrokeWidth() + SK_Scalar1,
148292ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org                  paint.getStrokeWidth() + SK_Scalar1);
148392ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
148492ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    if (!calculate_inverse_path(bounds, *pathPtr, &modifiedPath)) {
148592ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org        return false;
148692ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    }
148792ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
1488a9ebd161a7c08515f0c4bd885e61c4b52688ececedisonn@google.com    drawPath(d, modifiedPath, noInversePaint, prePathMatrix, true);
148992ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org    return true;
149092ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org}
1491d2623a1a0bcd23801c86a7d3f352b5e1f1c2e195commit-bot@chromium.org#endif
149292ffe7d10ef5db05f1f4ffef0cfe898169ba13bfcommit-bot@chromium.org
1493b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.combool SkPDFDevice::handleRectAnnotation(const SkRect& r, const SkMatrix& matrix,
1494b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com                                       const SkPaint& p) {
1495238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    SkAnnotation* annotationInfo = p.getAnnotation();
1496238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    if (!annotationInfo) {
1497238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org        return false;
1498238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    }
1499238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    SkData* urlData = annotationInfo->find(SkAnnotationKeys::URL_Key());
1500b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    if (urlData) {
1501b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        handleLinkToURL(urlData, r, matrix);
15024469938e92d779dff05e745559e67907bbf21e78reed@google.com        return p.getAnnotation() != NULL;
1503b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    }
15043b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkData* linkToName = annotationInfo->find(
15053b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            SkAnnotationKeys::Link_Named_Dest_Key());
1506b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    if (linkToName) {
1507b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        handleLinkToNamedDest(linkToName, r, matrix);
15084469938e92d779dff05e745559e67907bbf21e78reed@google.com        return p.getAnnotation() != NULL;
1509b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    }
1510b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    return false;
1511b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com}
1512b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
1513b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.combool SkPDFDevice::handlePointAnnotation(const SkPoint* points, size_t count,
1514b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com                                        const SkMatrix& matrix,
1515b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com                                        const SkPaint& paint) {
1516b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkAnnotation* annotationInfo = paint.getAnnotation();
1517b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    if (!annotationInfo) {
1518238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org        return false;
1519238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    }
15203b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkData* nameData = annotationInfo->find(
15213b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            SkAnnotationKeys::Define_Named_Dest_Key());
1522b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    if (nameData) {
1523b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        for (size_t i = 0; i < count; i++) {
1524b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com            defineNamedDestination(nameData, points[i], matrix);
1525b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        }
15264469938e92d779dff05e745559e67907bbf21e78reed@google.com        return paint.getAnnotation() != NULL;
1527b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    }
1528b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    return false;
1529b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com}
1530238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
15313b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.orgSkPDFDict* SkPDFDevice::createLinkAnnotation(const SkRect& r,
15323b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                             const SkMatrix& matrix) {
1533238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    SkMatrix transform = matrix;
1534238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    transform.postConcat(fInitialTransform);
1535238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    SkRect translatedRect;
1536238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    transform.mapRect(&translatedRect, r);
1537238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
15382a006c112743e07ce258ca223631fc19233f5ddcreed@google.com    if (NULL == fAnnotations) {
15392a006c112743e07ce258ca223631fc19233f5ddcreed@google.com        fAnnotations = SkNEW(SkPDFArray);
1540238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    }
1541b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkPDFDict* annotation(SkNEW_ARGS(SkPDFDict, ("Annot")));
1542238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    annotation->insertName("Subtype", "Link");
1543b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    fAnnotations->append(annotation);
1544238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
1545b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkAutoTUnref<SkPDFArray> border(SkNEW(SkPDFArray));
1546238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    border->reserve(3);
1547238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    border->appendInt(0);  // Horizontal corner radius.
1548238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    border->appendInt(0);  // Vertical corner radius.
1549238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    border->appendInt(0);  // Width, 0 = no border.
1550238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    annotation->insert("Border", border.get());
1551238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
1552b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkAutoTUnref<SkPDFArray> rect(SkNEW(SkPDFArray));
1553238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    rect->reserve(4);
1554238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    rect->appendScalar(translatedRect.fLeft);
1555238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    rect->appendScalar(translatedRect.fTop);
1556238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    rect->appendScalar(translatedRect.fRight);
1557238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    rect->appendScalar(translatedRect.fBottom);
1558238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    annotation->insert("Rect", rect.get());
1559238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
1560b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    return annotation;
1561b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com}
1562b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
1563b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.comvoid SkPDFDevice::handleLinkToURL(SkData* urlData, const SkRect& r,
1564b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com                                  const SkMatrix& matrix) {
1565b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix));
1566b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
1567b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkString url(static_cast<const char *>(urlData->data()),
1568b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com                 urlData->size() - 1);
1569b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkAutoTUnref<SkPDFDict> action(SkNEW_ARGS(SkPDFDict, ("Action")));
1570238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    action->insertName("S", "URI");
1571b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    action->insert("URI", SkNEW_ARGS(SkPDFString, (url)))->unref();
1572238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    annotation->insert("A", action.get());
1573b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com}
1574b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
1575b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.comvoid SkPDFDevice::handleLinkToNamedDest(SkData* nameData, const SkRect& r,
1576b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com                                        const SkMatrix& matrix) {
1577b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkAutoTUnref<SkPDFDict> annotation(createLinkAnnotation(r, matrix));
1578b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkString name(static_cast<const char *>(nameData->data()),
1579b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com                  nameData->size() - 1);
1580b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    annotation->insert("Dest", SkNEW_ARGS(SkPDFName, (name)))->unref();
1581b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com}
1582b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
1583b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.comstruct NamedDestination {
1584b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    const SkData* nameData;
1585b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkPoint point;
1586b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
1587b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    NamedDestination(const SkData* nameData, const SkPoint& point)
1588b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        : nameData(nameData), point(point) {
1589b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        nameData->ref();
1590b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    }
1591238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
1592b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    ~NamedDestination() {
1593b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        nameData->unref();
1594b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    }
1595b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com};
1596b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
1597b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.comvoid SkPDFDevice::defineNamedDestination(SkData* nameData, const SkPoint& point,
1598b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com                                         const SkMatrix& matrix) {
1599b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkMatrix transform = matrix;
1600b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    transform.postConcat(fInitialTransform);
1601b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    SkPoint translatedPoint;
1602b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    transform.mapXY(point.x(), point.y(), &translatedPoint);
1603b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    fNamedDestinations.push(
1604b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        SkNEW_ARGS(NamedDestination, (nameData, translatedPoint)));
1605b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com}
1606b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com
1607b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.comvoid SkPDFDevice::appendDestinations(SkPDFDict* dict, SkPDFObject* page) {
1608b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    int nDest = fNamedDestinations.count();
1609b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    for (int i = 0; i < nDest; i++) {
1610b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        NamedDestination* dest = fNamedDestinations[i];
1611b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        SkAutoTUnref<SkPDFArray> pdfDest(SkNEW(SkPDFArray));
1612b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        pdfDest->reserve(5);
1613b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        pdfDest->append(SkNEW_ARGS(SkPDFObjRef, (page)))->unref();
1614b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        pdfDest->appendName("XYZ");
1615b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        pdfDest->appendScalar(dest->point.x());
1616b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        pdfDest->appendScalar(dest->point.y());
1617b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com        pdfDest->appendInt(0);  // Leave zoom unchanged
16183b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        dict->insert(static_cast<const char *>(dest->nameData->data()),
16193b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                     pdfDest);
1620b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com    }
1621238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org}
1622238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org
1623fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.comSkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() {
1624fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com    SkPDFFormXObject* xobject = SkNEW_ARGS(SkPDFFormXObject, (this));
16259859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    // We always draw the form xobjects that we create back into the device, so
16269859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    // we simply preserve the font usage instead of pulling it out and merging
16279859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    // it back in later.
16289859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org    cleanUp(false);  // Reset this device to have no content.
16296112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    init();
1630fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com    return xobject;
16316112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org}
16326112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
16333b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.orgvoid SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex,
16343b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                          SkPDFFormXObject* mask,
1635481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org                                          const SkClipStack* clipStack,
1636481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org                                          const SkRegion& clipRegion,
16373b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                          SkXfermode::Mode mode,
1638481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org                                          bool invertClip) {
1639481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org    if (clipRegion.isEmpty() && !invertClip) {
1640481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org        return;
1641481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org    }
1642481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org
1643d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org    SkAutoTUnref<SkPDFGraphicState> sMaskGS(
16443b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        SkPDFGraphicState::GetSMaskGraphicState(
16453b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            mask, invertClip, SkPDFGraphicState::kAlpha_SMaskMode));
1646466f3d66f09285d2d988315bacde573a5359ce54vandebo@chromium.org
16473b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkMatrix identity;
16483b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    identity.reset();
16493b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkPaint paint;
16503b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    paint.setXfermodeMode(mode);
16513b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    ScopedContentEntry content(this, clipStack, clipRegion, identity, paint);
1652b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (!content.entry()) {
1653b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        return;
1654b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    }
1655466f3d66f09285d2d988315bacde573a5359ce54vandebo@chromium.org    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1656b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                  &content.entry()->fContent);
16573b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkPDFUtils::DrawFormXObject(xObjectIndex, &content.entry()->fContent);
1658466f3d66f09285d2d988315bacde573a5359ce54vandebo@chromium.org
1659d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org    sMaskGS.reset(SkPDFGraphicState::GetNoSMaskGraphicState());
1660466f3d66f09285d2d988315bacde573a5359ce54vandebo@chromium.org    SkPDFUtils::ApplyGraphicState(addGraphicStateResource(sMaskGS.get()),
1661b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                  &content.entry()->fContent);
1662466f3d66f09285d2d988315bacde573a5359ce54vandebo@chromium.org}
1663466f3d66f09285d2d988315bacde573a5359ce54vandebo@chromium.org
1664b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.orgContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
1665b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                             const SkRegion& clipRegion,
1666b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                             const SkMatrix& matrix,
1667b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                             const SkPaint& paint,
1668b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                             bool hasText,
1669fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com                                             SkPDFFormXObject** dst) {
1670fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com    *dst = NULL;
167125adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    if (clipRegion.isEmpty()) {
1672b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        return NULL;
167325adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
167425adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org
167578dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org    // The clip stack can come from an SkDraw where it is technically optional.
167678dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org    SkClipStack synthesizedClipStack;
167778dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org    if (clipStack == NULL) {
167878dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org        if (clipRegion == fExistingClipRegion) {
167978dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org            clipStack = &fExistingClipStack;
168078dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org        } else {
168178dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org            // GraphicStackState::updateClip expects the clip stack to have
168278dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org            // fExistingClip as a prefix, so start there, then set the clip
168378dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org            // to the passed region.
168478dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org            synthesizedClipStack = fExistingClipStack;
168578dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org            SkPath clipPath;
168678dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org            clipRegion.getBoundaryPath(&clipPath);
16870017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com            synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op,
16880017708a5bcb6d0fbff0fac565085bef65de7433reed@google.com                                             false);
168978dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org            clipStack = &synthesizedClipStack;
169078dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org        }
169178dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org    }
169278dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org
169325adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
169425adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    if (paint.getXfermode()) {
169525adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        paint.getXfermode()->asMode(&xfermode);
169625adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
169725adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org
16983b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    // For the following modes, we want to handle source and destination
16993b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    // separately, so make an object of what's already there.
17003b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (xfermode == SkXfermode::kClear_Mode       ||
17013b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kSrc_Mode     ||
17023b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kSrcIn_Mode   ||
17033b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kDstIn_Mode   ||
17043b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kSrcOut_Mode  ||
17053b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kDstOut_Mode  ||
17063b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kSrcATop_Mode ||
17073b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kDstATop_Mode ||
17083b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kModulate_Mode) {
17093b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        if (!isContentEmpty()) {
1710fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com            *dst = createFormXObjectFromDevice();
17113b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            SkASSERT(isContentEmpty());
17123b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        } else if (xfermode != SkXfermode::kSrc_Mode &&
17133b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                   xfermode != SkXfermode::kSrcOut_Mode) {
17143b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            // Except for Src and SrcOut, if there isn't anything already there,
17153b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            // then we're done.
17163b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            return NULL;
1717481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org        }
17186112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    }
1719769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org    // TODO(vandebo): Figure out how/if we can handle the following modes:
17203b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    // Xor, Plus.
172125adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org
17223b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    // Dst xfer mode doesn't draw source at all.
17233b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (xfermode == SkXfermode::kDst_Mode) {
1724b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        return NULL;
172525adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
172625adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org
17279fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    ContentEntry* entry;
1728e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org    SkAutoTDelete<ContentEntry> newEntry;
17298dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org
17308dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    ContentEntry* lastContentEntry = getLastContentEntry();
17318dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    if (lastContentEntry && lastContentEntry->fContent.getOffset() == 0) {
17328dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        entry = lastContentEntry;
17339fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    } else {
17349fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        newEntry.reset(new ContentEntry);
17359fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        entry = newEntry.get();
17369fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
17379fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
173878dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org    populateGraphicStateEntryFromPaint(matrix, *clipStack, clipRegion, paint,
17399fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                                       hasText, &entry->fState);
17408dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    if (lastContentEntry && xfermode != SkXfermode::kDstOver_Mode &&
17418dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org            entry->fState.compareInitialState(lastContentEntry->fState)) {
17428dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        return lastContentEntry;
17439fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
17449fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
1745e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org    SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries();
17468dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    if (!lastContentEntry) {
17479510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org        contentEntries->reset(entry);
17488dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        setLastContentEntry(entry);
174925adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    } else if (xfermode == SkXfermode::kDstOver_Mode) {
1750e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org        entry->fNext.reset(contentEntries->detach());
17519510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org        contentEntries->reset(entry);
17529fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    } else {
17538dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        lastContentEntry->fNext.reset(entry);
17548dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org        setLastContentEntry(entry);
17559fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
1756e02944075840d672bd1797f3d945ff82d302282fcommit-bot@chromium.org    newEntry.detach();
1757b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    return entry;
17589fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org}
17599fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org
17607542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.orgvoid SkPDFDevice::finishContentEntry(SkXfermode::Mode xfermode,
17613b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                     SkPDFFormXObject* dst,
17623b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                     SkPath* shape) {
17633b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (xfermode != SkXfermode::kClear_Mode       &&
17643b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode != SkXfermode::kSrc_Mode     &&
17657542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            xfermode != SkXfermode::kDstOver_Mode &&
17663b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode != SkXfermode::kSrcIn_Mode   &&
17673b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode != SkXfermode::kDstIn_Mode   &&
17683b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode != SkXfermode::kSrcOut_Mode  &&
17693b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode != SkXfermode::kDstOut_Mode  &&
17703b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode != SkXfermode::kSrcATop_Mode &&
17713b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode != SkXfermode::kDstATop_Mode &&
17723b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode != SkXfermode::kModulate_Mode) {
1773b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        SkASSERT(!dst);
17746112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        return;
17756112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    }
17767542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org    if (xfermode == SkXfermode::kDstOver_Mode) {
17777542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        SkASSERT(!dst);
17787542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        ContentEntry* firstContentEntry = getContentEntries()->get();
17797542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        if (firstContentEntry->fContent.getOffset() == 0) {
17807542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            // For DstOver, an empty content entry was inserted before the rest
17817542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            // of the content entries. If nothing was drawn, it needs to be
17827542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            // removed.
17837542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            SkAutoTDelete<ContentEntry>* contentEntries = getContentEntries();
17847542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            contentEntries->reset(firstContentEntry->fNext.detach());
17857542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        }
17867542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        return;
17877542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org    }
17883b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (!dst) {
17893b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        SkASSERT(xfermode == SkXfermode::kSrc_Mode ||
17903b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                 xfermode == SkXfermode::kSrcOut_Mode);
17913b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        return;
17923b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
17939510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org
17949510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    ContentEntry* contentEntries = getContentEntries()->get();
1795b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    SkASSERT(dst);
17968dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    SkASSERT(!contentEntries->fNext.get());
17974e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org    // Changing the current content into a form-xobject will destroy the clip
17984e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org    // objects which is fine since the xobject will already be clipped. However
17994e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org    // if source has shape, we need to clip it too, so a copy of the clip is
18004e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org    // saved.
18018dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    SkClipStack clipStack = contentEntries->fState.fClipStack;
18028dcf74f27690476193f5d4ca34fba2e87ca7c98dctguil@chromium.org    SkRegion clipRegion = contentEntries->fState.fClipRegion;
1803481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org
18047542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org    SkMatrix identity;
18057542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org    identity.reset();
18067542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org    SkPaint stockPaint;
18077542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org
1808fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com    SkAutoTUnref<SkPDFFormXObject> srcFormXObject;
18093b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (isContentEmpty()) {
18107542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        // If nothing was drawn and there's no shape, then the draw was a
18117542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        // no-op, but dst needs to be restored for that to be true.
18127542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        // If there is shape, then an empty source with Src, SrcIn, SrcOut,
18137542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        // DstIn, DstAtop or Modulate reduces to Clear and DstOut or SrcAtop
18147542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        // reduces to Dst.
18157542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        if (shape == NULL || xfermode == SkXfermode::kDstOut_Mode ||
18167542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org                xfermode == SkXfermode::kSrcATop_Mode) {
18174e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org            ScopedContentEntry content(this, &fExistingClipStack,
18184e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                       fExistingClipRegion, identity,
18197542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org                                       stockPaint);
18207542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
18217542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org                                        &content.entry()->fContent);
18227542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            return;
18237542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        } else {
18247542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            xfermode = SkXfermode::kClear_Mode;
18257542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        }
18263b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    } else {
18273b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        SkASSERT(!fContentEntries->fNext.get());
1828fc641d09e5a1a9f7fae369ae06a8b96089faf57breed@google.com        srcFormXObject.reset(createFormXObjectFromDevice());
1829481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org    }
1830481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org
18313b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    // TODO(vandebo) srcFormXObject may contain alpha, but here we want it
18323b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    // without alpha.
18333b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (xfermode == SkXfermode::kSrcATop_Mode) {
18343b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        // TODO(vandebo): In order to properly support SrcATop we have to track
18353b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        // the shape of what's been drawn at all times. It's the intersection of
18363b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        // the non-transparent parts of the device and the outlines (shape) of
18373b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        // all images and devices drawn.
18383b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
18394e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                &fExistingClipStack, fExistingClipRegion,
18403b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                SkXfermode::kSrcOver_Mode, true);
18413b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    } else {
18423b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        SkAutoTUnref<SkPDFFormXObject> dstMaskStorage;
18433b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        SkPDFFormXObject* dstMask = srcFormXObject.get();
18443b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        if (shape != NULL) {
18453b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            // Draw shape into a form-xobject.
18463b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            SkDraw d;
18473b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            d.fMatrix = &identity;
18483b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            d.fClip = &clipRegion;
18493b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            d.fClipStack = &clipStack;
18503b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            SkPaint filledPaint;
18513b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            filledPaint.setColor(SK_ColorBLACK);
18523b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            filledPaint.setStyle(SkPaint::kFill_Style);
18533b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            this->drawPath(d, *shape, filledPaint, NULL, true);
18543b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org
18553b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            dstMaskStorage.reset(createFormXObjectFromDevice());
18563b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            dstMask = dstMaskStorage.get();
18573b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        }
18584e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org        drawFormXObjectWithMask(addXObjectResource(dst), dstMask,
18594e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                &fExistingClipStack, fExistingClipRegion,
18604e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                SkXfermode::kSrcOver_Mode, true);
1861481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org    }
18626112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
18637542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org    if (xfermode == SkXfermode::kClear_Mode) {
18643b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        return;
18653b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    } else if (xfermode == SkXfermode::kSrc_Mode ||
18663b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kDstATop_Mode) {
18674e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org        ScopedContentEntry content(this, &fExistingClipStack,
18684e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                   fExistingClipRegion, identity, stockPaint);
18693b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        if (content.entry()) {
18703b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            SkPDFUtils::DrawFormXObject(
18713b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                    this->addXObjectResource(srcFormXObject.get()),
18723b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                    &content.entry()->fContent);
18733b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        }
18743b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        if (xfermode == SkXfermode::kSrc_Mode) {
18753b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            return;
18763b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        }
18777542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org    } else if (xfermode == SkXfermode::kSrcATop_Mode) {
18784e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org        ScopedContentEntry content(this, &fExistingClipStack,
18794e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                   fExistingClipRegion, identity, stockPaint);
18807542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        if (content.entry()) {
18817542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org            SkPDFUtils::DrawFormXObject(this->addXObjectResource(dst),
18827542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org                                        &content.entry()->fContent);
18837542dc8897d151afc0eca7dd73d72ea05f92baadcommit-bot@chromium.org        }
18843b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
18853b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org
18863b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkASSERT(xfermode == SkXfermode::kSrcIn_Mode   ||
18873b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org             xfermode == SkXfermode::kDstIn_Mode   ||
18883b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org             xfermode == SkXfermode::kSrcOut_Mode  ||
18893b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org             xfermode == SkXfermode::kDstOut_Mode  ||
18903b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org             xfermode == SkXfermode::kSrcATop_Mode ||
18913b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org             xfermode == SkXfermode::kDstATop_Mode ||
18923b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org             xfermode == SkXfermode::kModulate_Mode);
18933b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org
18946112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    if (xfermode == SkXfermode::kSrcIn_Mode ||
18953b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kSrcOut_Mode ||
18963b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            xfermode == SkXfermode::kSrcATop_Mode) {
18973b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()), dst,
18984e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                &fExistingClipStack, fExistingClipRegion,
18993b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                SkXfermode::kSrcOver_Mode,
19003b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                xfermode == SkXfermode::kSrcOut_Mode);
19016112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    } else {
19023b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode;
19033b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        if (xfermode == SkXfermode::kModulate_Mode) {
19043b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            drawFormXObjectWithMask(addXObjectResource(srcFormXObject.get()),
19054e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                    dst, &fExistingClipStack,
19064e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                    fExistingClipRegion,
19073b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                    SkXfermode::kSrcOver_Mode, false);
19083b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org            mode = SkXfermode::kMultiply_Mode;
19093b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        }
19103b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        drawFormXObjectWithMask(addXObjectResource(dst), srcFormXObject.get(),
19114e8f1e56b17c3663d1892f44a4c1893b568ce67fcommit-bot@chromium.org                                &fExistingClipStack, fExistingClipRegion, mode,
19123b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                xfermode == SkXfermode::kDstOut_Mode);
19136112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    }
19146112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org}
19156112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
1916481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.orgbool SkPDFDevice::isContentEmpty() {
19179510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    ContentEntry* contentEntries = getContentEntries()->get();
19189510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org    if (!contentEntries || contentEntries->fContent.getOffset() == 0) {
19199510ccc06bbfa5e888f66578042674be98d8ac60ctguil@chromium.org        SkASSERT(!contentEntries || !contentEntries->fNext.get());
1920481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org        return true;
1921481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org    }
1922481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org    return false;
1923481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org}
1924481aef68333e01c19badda456d8e60bd1f1bee2avandebo@chromium.org
19259fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.orgvoid SkPDFDevice::populateGraphicStateEntryFromPaint(
19269fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        const SkMatrix& matrix,
19279fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        const SkClipStack& clipStack,
19289fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        const SkRegion& clipRegion,
19299fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        const SkPaint& paint,
19309fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        bool hasText,
19319fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        GraphicStateEntry* entry) {
19326f4e473676ff5c32c06151f4f8451d62715d65d2reed@google.com    NOT_IMPLEMENTED(paint.getPathEffect() != NULL, false);
1933da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org    NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
1934da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org    NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false);
19359b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
19369fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    entry->fMatrix = matrix;
19379fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    entry->fClipStack = clipStack;
19389fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    entry->fClipRegion = clipRegion;
1939da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org    entry->fColor = SkColorSetA(paint.getColor(), 0xFF);
1940da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org    entry->fShaderIndex = -1;
194148543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org
1942da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org    // PDF treats a shader as a color, so we only set one or the other.
1943d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org    SkAutoTUnref<SkPDFObject> pdfShader;
19449fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    const SkShader* shader = paint.getShader();
19459fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    SkColor color = paint.getColor();
1946da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org    if (shader) {
1947da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org        // PDF positions patterns relative to the initial transform, so
1948da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org        // we need to apply the current transform to the shader parameters.
19499fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkMatrix transform = matrix;
195075f97e452e8f2ee55cd2b283df7d7734f48bc2bfvandebo@chromium.org        transform.postConcat(fInitialTransform);
1951da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org
1952da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org        // PDF doesn't support kClamp_TileMode, so we simulate it by making
19539fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        // a pattern the size of the current clip.
1954b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        SkIRect bounds = clipRegion.getBounds();
1955293a758929222b6003678c6a49bfbb2f2f806e8evandebo@chromium.org
1956293a758929222b6003678c6a49bfbb2f2f806e8evandebo@chromium.org        // We need to apply the initial transform to bounds in order to get
1957293a758929222b6003678c6a49bfbb2f2f806e8evandebo@chromium.org        // bounds in a consistent coordinate system.
1958293a758929222b6003678c6a49bfbb2f2f806e8evandebo@chromium.org        SkRect boundsTemp;
1959293a758929222b6003678c6a49bfbb2f2f806e8evandebo@chromium.org        boundsTemp.set(bounds);
1960293a758929222b6003678c6a49bfbb2f2f806e8evandebo@chromium.org        fInitialTransform.mapRect(&boundsTemp);
1961293a758929222b6003678c6a49bfbb2f2f806e8evandebo@chromium.org        boundsTemp.roundOut(&bounds);
1962293a758929222b6003678c6a49bfbb2f2f806e8evandebo@chromium.org
1963d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org        pdfShader.reset(SkPDFShader::GetPDFShader(*shader, transform, bounds));
1964da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org
1965b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org        if (pdfShader.get()) {
1966b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org            // pdfShader has been canonicalized so we can directly compare
1967b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org            // pointers.
1968b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org            int resourceIndex = fShaderResources.find(pdfShader.get());
1969b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org            if (resourceIndex < 0) {
1970b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org                resourceIndex = fShaderResources.count();
1971b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org                fShaderResources.push(pdfShader.get());
1972d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org                pdfShader.get()->ref();
1973b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org            }
1974b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org            entry->fShaderIndex = resourceIndex;
1975b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org        } else {
1976b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org            // A color shader is treated as an invalid shader so we don't have
1977b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org            // to set a shader just for a color.
1978da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            SkShader::GradientInfo gradientInfo;
1979da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            SkColor gradientColor;
1980da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            gradientInfo.fColors = &gradientColor;
1981da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            gradientInfo.fColorOffsets = NULL;
1982da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            gradientInfo.fColorCount = 1;
1983da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            if (shader->asAGradient(&gradientInfo) ==
1984da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org                    SkShader::kColor_GradientType) {
19859fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                entry->fColor = SkColorSetA(gradientColor, 0xFF);
19869fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org                color = gradientColor;
1987da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org            }
1988da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org        }
1989da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org    }
19909b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1991d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org    SkAutoTUnref<SkPDFGraphicState> newGraphicState;
19929fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (color == paint.getColor()) {
1993d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org        newGraphicState.reset(
1994d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org                SkPDFGraphicState::GetGraphicStateForPaint(paint));
19959fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    } else {
19969fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        SkPaint newPaint = paint;
19979fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        newPaint.setColor(color);
1998d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org        newGraphicState.reset(
1999d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org                SkPDFGraphicState::GetGraphicStateForPaint(newPaint));
20009fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    }
20016112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    int resourceIndex = addGraphicStateResource(newGraphicState.get());
20029fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    entry->fGraphicStateIndex = resourceIndex;
200328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
20049fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    if (hasText) {
20059fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        entry->fTextScaleX = paint.getTextScaleX();
20069fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        entry->fTextFill = paint.getStyle();
20079fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org    } else {
20089fbdf875183f5142b8e0ba46ab430cc46ad701bfvandebo@chromium.org        entry->fTextScaleX = 0;
20099b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    }
20109b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
20119b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
20126112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.orgint SkPDFDevice::addGraphicStateResource(SkPDFGraphicState* gs) {
20136112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    // Assumes that gs has been canonicalized (so we can directly compare
20146112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    // pointers).
20156112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    int result = fGraphicStateResources.find(gs);
20166112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    if (result < 0) {
20176112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        result = fGraphicStateResources.count();
20186112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        fGraphicStateResources.push(gs);
20196112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        gs->ref();
20206112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    }
20216112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    return result;
20226112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org}
20236112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
20243b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.orgint SkPDFDevice::addXObjectResource(SkPDFObject* xObject) {
20253b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    // Assumes that xobject has been canonicalized (so we can directly compare
20263b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    // pointers).
20273b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    int result = fXObjectResources.find(xObject);
20283b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (result < 0) {
20293b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        result = fXObjectResources.count();
20303b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        fXObjectResources.push(xObject);
20313b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        xObject->ref();
20323b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
20333b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    return result;
20343b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org}
20353b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org
2036b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.orgvoid SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
2037b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                             ContentEntry* contentEntry) {
20389db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.org    SkTypeface* typeface = paint.getTypeface();
2039b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org    if (contentEntry->fState.fFont == NULL ||
2040b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org            contentEntry->fState.fTextSize != paint.getTextSize() ||
2041b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org            !contentEntry->fState.fFont->hasGlyph(glyphID)) {
20429db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.org        int fontIndex = getFontResourceIndex(typeface, glyphID);
204347401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org        contentEntry->fContent.writeText("/");
204447401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org        contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
204547401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                SkPDFResourceDict::kFont_ResourceType,
204647401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org                fontIndex).c_str());
2047b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        contentEntry->fContent.writeText(" ");
2048b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        SkPDFScalar::Append(paint.getTextSize(), &contentEntry->fContent);
2049b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        contentEntry->fContent.writeText(" Tf\n");
2050b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org        contentEntry->fState.fFont = fFontResources[fontIndex];
20512a22e10ab2946c5590cd2a258427ce3ccfca9bfavandebo@chromium.org    }
20522a22e10ab2946c5590cd2a258427ce3ccfca9bfavandebo@chromium.org}
20532a22e10ab2946c5590cd2a258427ce3ccfca9bfavandebo@chromium.org
20549db86bb9cd1b77be0afc504ccc07026e4282d7e7ctguil@chromium.orgint SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
20553b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkAutoTUnref<SkPDFFont> newFont(SkPDFFont::GetFontResource(typeface,
20563b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org                                                               glyphID));
205728be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    int resourceIndex = fFontResources.find(newFont.get());
205828be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    if (resourceIndex < 0) {
205928be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        resourceIndex = fFontResources.count();
206028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        fFontResources.push(newFont.get());
2061d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org        newFont.get()->ref();
206228be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    }
206328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    return resourceIndex;
206428be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org}
206528be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org
20669cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.comvoid SkPDFDevice::internalDrawBitmap(const SkMatrix& origMatrix,
206778dad54080ad806be89adb5cc0e3c530b031cdafvandebo@chromium.org                                     const SkClipStack* clipStack,
20689cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com                                     const SkRegion& origClipRegion,
20699cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com                                     const SkBitmap& origBitmap,
2070befebb8a8437ce69e3a416b417cb27b66273128dvandebo@chromium.org                                     const SkIRect* srcRect,
20719b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                                     const SkPaint& paint) {
20729cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    SkMatrix matrix = origMatrix;
20739cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    SkRegion perspectiveBounds;
20749cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    const SkRegion* clipRegion = &origClipRegion;
20759cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    SkBitmap perspectiveBitmap;
20769cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    const SkBitmap* bitmap = &origBitmap;
20779cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    SkBitmap tmpSubsetBitmap;
20789cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
20799cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    // Rasterize the bitmap using perspective in a new bitmap.
20809cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    if (origMatrix.hasPerspective()) {
208173a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        if (fRasterDpi == 0) {
208273a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com            return;
208373a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        }
20849cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        SkBitmap* subsetBitmap;
20859cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        if (srcRect) {
20869cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com            if (!origBitmap.extractSubset(&tmpSubsetBitmap, *srcRect)) {
20879cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com               return;
20889cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com            }
20899cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com            subsetBitmap = &tmpSubsetBitmap;
20909cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        } else {
20919cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com            subsetBitmap = &tmpSubsetBitmap;
20929cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com            *subsetBitmap = origBitmap;
20939cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        }
20949cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        srcRect = NULL;
20959cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
209673a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        // Transform the bitmap in the new space, without taking into
209773a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        // account the initial transform.
20989cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        SkPath perspectiveOutline;
20999cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        perspectiveOutline.addRect(
21009cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com                SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()),
21019cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com                               SkIntToScalar(subsetBitmap->height())));
21029cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        perspectiveOutline.transform(origMatrix);
21039cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21049cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // TODO(edisonn): perf - use current clip too.
21059cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // Retrieve the bounds of the new shape.
21069cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        SkRect bounds = perspectiveOutline.getBounds();
21079cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
210873a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        // Transform the bitmap in the new space, taking into
210973a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        // account the initial transform.
211073a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        SkMatrix total = origMatrix;
211173a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        total.postConcat(fInitialTransform);
211273a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        total.postScale(SkIntToScalar(fRasterDpi) /
211373a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com                            SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE),
211473a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com                        SkIntToScalar(fRasterDpi) /
211573a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com                            SkIntToScalar(DPI_FOR_RASTER_SCALE_ONE));
211673a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        SkPath physicalPerspectiveOutline;
211773a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        physicalPerspectiveOutline.addRect(
211873a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com                SkRect::MakeWH(SkIntToScalar(subsetBitmap->width()),
211973a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com                               SkIntToScalar(subsetBitmap->height())));
212073a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        physicalPerspectiveOutline.transform(total);
212173a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com
212273a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        SkScalar scaleX = physicalPerspectiveOutline.getBounds().width() /
212373a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com                              bounds.width();
212473a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        SkScalar scaleY = physicalPerspectiveOutline.getBounds().height() /
212573a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com                              bounds.height();
21269cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21279cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // TODO(edisonn): A better approach would be to use a bitmap shader
21289cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // (in clamp mode) and draw a rect over the entire bounding box. Then
21299cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // intersect perspectiveOutline to the clip. That will avoid introducing
21309cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // alpha to the image while still giving good behavior at the edge of
21319cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // the image.  Avoiding alpha will reduce the pdf size and generation
21329cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // CPU time some.
21339cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21349ebcac54635cde63110d73ad7c43d70772e7872freed@google.com        const int w = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().width());
21359ebcac54635cde63110d73ad7c43d70772e7872freed@google.com        const int h = SkScalarCeilToInt(physicalPerspectiveOutline.getBounds().height());
2136848250415eddc54075f7eb8795e8db79e749c6abreed        if (!perspectiveBitmap.tryAllocN32Pixels(w, h)) {
21379ebcac54635cde63110d73ad7c43d70772e7872freed@google.com            return;
21389ebcac54635cde63110d73ad7c43d70772e7872freed@google.com        }
21399cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        perspectiveBitmap.eraseColor(SK_ColorTRANSPARENT);
21409cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
214189443aba5bfa2b040dc9fd24938b7d0b3decd737reed        SkCanvas canvas(perspectiveBitmap);
21429cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21439cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        SkScalar deltaX = bounds.left();
21449cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        SkScalar deltaY = bounds.top();
21459cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21469cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        SkMatrix offsetMatrix = origMatrix;
21479cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        offsetMatrix.postTranslate(-deltaX, -deltaY);
214873a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        offsetMatrix.postScale(scaleX, scaleY);
21499cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21509cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // Translate the draw in the new canvas, so we perfectly fit the
21519cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // shape in the bitmap.
21529cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        canvas.setMatrix(offsetMatrix);
21539cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21549cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        canvas.drawBitmap(*subsetBitmap, SkIntToScalar(0), SkIntToScalar(0));
21559cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21569cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        // Make sure the final bits are in the bitmap.
21579cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        canvas.flush();
21589cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
215973a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        // In the new space, we use the identity matrix translated
216073a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        // and scaled to reflect DPI.
216173a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        matrix.setScale(1 / scaleX, 1 / scaleY);
216273a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com        matrix.postTranslate(deltaX, deltaY);
216373a7ea3ae0d37ee28f90d6b38c49fda052638253edisonn@google.com
21649cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        perspectiveBounds.setRect(
21659cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com                SkIRect::MakeXYWH(SkScalarFloorToInt(bounds.x()),
21669cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com                                  SkScalarFloorToInt(bounds.y()),
21679cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com                                  SkScalarCeilToInt(bounds.width()),
21689cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com                                  SkScalarCeilToInt(bounds.height())));
21699cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        clipRegion = &perspectiveBounds;
21709cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        srcRect = NULL;
21719cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com        bitmap = &perspectiveBitmap;
21729cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    }
21739cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com
21747e2ff7cf7da604b29378978ef5d4655499485368vandebo@chromium.org    SkMatrix scaled;
21757e2ff7cf7da604b29378978ef5d4655499485368vandebo@chromium.org    // Adjust for origin flip.
2176663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org    scaled.setScale(SK_Scalar1, -SK_Scalar1);
2177663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org    scaled.postTranslate(0, SK_Scalar1);
21787e2ff7cf7da604b29378978ef5d4655499485368vandebo@chromium.org    // Scale the image up from 1x1 to WxH.
21799cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    SkIRect subset = SkIRect::MakeWH(bitmap->width(), bitmap->height());
2180a6d59f60aab59fb6556841b063ead5d49b46ba8dreed@google.com    scaled.postScale(SkIntToScalar(subset.width()),
2181a6d59f60aab59fb6556841b063ead5d49b46ba8dreed@google.com                     SkIntToScalar(subset.height()));
21827e2ff7cf7da604b29378978ef5d4655499485368vandebo@chromium.org    scaled.postConcat(matrix);
21839cf0cb169bda63ad50f4c394739deb6c67003647edisonn@google.com    ScopedContentEntry content(this, clipStack, *clipRegion, scaled, paint);
21843b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (!content.entry() || (srcRect && !subset.intersect(*srcRect))) {
218525adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        return;
218625adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
21873b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (content.needShape()) {
21883b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        SkPath shape;
2189fd3c8c243ab190604e134910a1d6c1326d21e374vandebo@chromium.org        shape.addRect(SkRect::MakeWH(SkIntToScalar(subset.width()),
2190fd3c8c243ab190604e134910a1d6c1326d21e374vandebo@chromium.org                                     SkIntToScalar( subset.height())));
21913b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        shape.transform(matrix);
21923b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        content.setShape(shape);
21933b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    }
21943b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    if (!content.needSource()) {
219525adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        return;
219625adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
219725adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org
2198daefa5b340d7aa36fe31865a3646f6fce321bb38halcanary    SkAutoTUnref<SkPDFObject> image(
2199daefa5b340d7aa36fe31865a3646f6fce321bb38halcanary            SkPDFCreateImageObject(*bitmap, subset, fEncoder));
220025adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    if (!image) {
220125adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        return;
220225adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org    }
22037e2ff7cf7da604b29378978ef5d4655499485368vandebo@chromium.org
22043b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org    SkPDFUtils::DrawFormXObject(this->addXObjectResource(image.get()),
2205b069c8cfcd5df285193eb334b3bc33438782e8davandebo@chromium.org                                &content.entry()->fContent);
22069b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
2207982cb875f01e247843b9a79082f680cdcf234c2creed@google.com
2208