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
86112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org#include "SkPDFFormXObject.h"
99b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org#include "SkPDFGraphicState.h"
10f71b2103d56dde247605b718a0c89123ad8f0094vandebo@chromium.org#include "SkPDFUtils.h"
119b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org#include "SkStream.h"
1248543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org#include "SkTypes.h"
1348543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org
146112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.orgstatic const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
1548543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org    switch (mode) {
1648543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kSrcOver_Mode:    return "Normal";
17b24f89353ed7a45b27ab0ffc69c222b81bbf87c3commit-bot@chromium.org        case SkXfermode::kMultiply_Mode:   return "Multiply";
1848543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kScreen_Mode:     return "Screen";
1948543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kOverlay_Mode:    return "Overlay";
2048543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kDarken_Mode:     return "Darken";
2148543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kLighten_Mode:    return "Lighten";
2248543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kColorDodge_Mode: return "ColorDodge";
2348543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kColorBurn_Mode:  return "ColorBurn";
2448543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kHardLight_Mode:  return "HardLight";
2548543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kSoftLight_Mode:  return "SoftLight";
2648543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kDifference_Mode: return "Difference";
2748543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kExclusion_Mode:  return "Exclusion";
28b24f89353ed7a45b27ab0ffc69c222b81bbf87c3commit-bot@chromium.org        case SkXfermode::kHue_Mode:        return "Hue";
29b24f89353ed7a45b27ab0ffc69c222b81bbf87c3commit-bot@chromium.org        case SkXfermode::kSaturation_Mode: return "Saturation";
30b24f89353ed7a45b27ab0ffc69c222b81bbf87c3commit-bot@chromium.org        case SkXfermode::kColor_Mode:      return "Color";
31b24f89353ed7a45b27ab0ffc69c222b81bbf87c3commit-bot@chromium.org        case SkXfermode::kLuminosity_Mode: return "Luminosity";
3248543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org
3325adce81ce24702174ede33445c414a8d21d8a23vandebo@chromium.org        // These are handled in SkPDFDevice::setUpContentEntry.
3448543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kClear_Mode:
3548543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kSrc_Mode:
3648543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kDst_Mode:
3748543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kDstOver_Mode:
3848543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kSrcIn_Mode:
3948543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kDstIn_Mode:
4048543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kSrcOut_Mode:
4148543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kDstOut_Mode:
423b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        case SkXfermode::kSrcATop_Mode:
433b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        case SkXfermode::kDstATop_Mode:
443b416216d1e90cb8b1bba41bb95806fe2d40da88vandebo@chromium.org        case SkXfermode::kModulate_Mode:
456112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org            return "Normal";
466112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
47769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org        // TODO(vandebo): Figure out if we can support more of these modes.
4848543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kXor_Mode:
4948543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        case SkXfermode::kPlus_Mode:
5048543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org            return NULL;
5148543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org    }
5248543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org    return NULL;
5348543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org}
5448543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org
559b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.orgSkPDFGraphicState::~SkPDFGraphicState() {
56f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
576112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    if (!fSMask) {
58f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com        int index = Find(fPaint);
596112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        SkASSERT(index >= 0);
60918352f86e939fe042495aad4f5ff33c4ecec9edvandebo@chromium.org        SkASSERT(CanonicalPaints()[index].fGraphicState == this);
61f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com        CanonicalPaints().removeShuffle(index);
626112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    }
636112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    fResources.unrefAll();
646112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org}
656112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
666addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.comvoid SkPDFGraphicState::getResources(
676addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com        const SkTSet<SkPDFObject*>& knownResourceObjects,
686addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com        SkTSet<SkPDFObject*>* newResourceObjects) {
696addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com    GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects);
709b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
719b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
729b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.orgvoid SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
739b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org                                   bool indirect) {
749b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    populateDict();
759b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    SkPDFDict::emitObject(stream, catalog, indirect);
769b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
779b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
7848543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org// static
799b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.orgsize_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
809b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    populateDict();
819b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    return SkPDFDict::getOutputSize(catalog, indirect);
829b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
839b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
849b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org// static
85b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtkleinSkTDArray<SkPDFGraphicState::GSCanonicalEntry>& SkPDFGraphicState::CanonicalPaints() {
86b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    CanonicalPaintsMutex().assertHeld();
879b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints;
889b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    return gCanonicalPaints;
899b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
909b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
919b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org// static
921771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.comSkBaseMutex& SkPDFGraphicState::CanonicalPaintsMutex() {
931771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.com    SK_DECLARE_STATIC_MUTEX(gCanonicalPaintsMutex);
949b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    return gCanonicalPaintsMutex;
959b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
969b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
979b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org// static
98b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtkleinSkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint(const SkPaint& paint) {
99f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
100f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com    int index = Find(paint);
1019b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    if (index >= 0) {
102f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com        CanonicalPaints()[index].fGraphicState->ref();
103f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com        return CanonicalPaints()[index].fGraphicState;
1049b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    }
1059b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    GSCanonicalEntry newEntry(new SkPDFGraphicState(paint));
106f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com    CanonicalPaints().push(newEntry);
1079b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    return newEntry.fGraphicState;
1089b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
1099b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1109b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org// static
11119e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.orgSkPDFObject* SkPDFGraphicState::GetInvertFunction() {
11219e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org    // This assumes that canonicalPaintsMutex is held.
113b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    CanonicalPaintsMutex().assertHeld();
11419e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org    static SkPDFStream* invertFunction = NULL;
11519e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org    if (!invertFunction) {
11619e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        // Acrobat crashes if we use a type 0 function, kpdf crashes if we use
11719e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        // a type 2 function, so we use a type 4 function.
118d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org        SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray);
11919e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        domainAndRange->reserve(2);
120c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        domainAndRange->appendInt(0);
121c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        domainAndRange->appendInt(1);
12219e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org
12319e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        static const char psInvert[] = "{1 exch sub}";
124d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org        SkAutoTUnref<SkMemoryStream> psInvertStream(
125d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org            new SkMemoryStream(&psInvert, strlen(psInvert), true));
12619e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org
12719e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        invertFunction = new SkPDFStream(psInvertStream.get());
128c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        invertFunction->insertInt("FunctionType", 4);
12919e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        invertFunction->insert("Domain", domainAndRange.get());
13019e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        invertFunction->insert("Range", domainAndRange.get());
13119e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org    }
13219e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org    return invertFunction;
13319e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org}
13419e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org
13519e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org// static
136f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.comSkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState(
13793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org        SkPDFFormXObject* sMask, bool invert, SkPDFSMaskMode sMaskMode) {
1386112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    // The practical chances of using the same mask more than once are unlikely
1396112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    // enough that it's not worth canonicalizing.
140f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
1416112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
142d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org    SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask"));
14393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org    if (sMaskMode == kAlpha_SMaskMode) {
14493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org        sMaskDict->insertName("S", "Alpha");
14593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org    } else if (sMaskMode == kLuminosity_SMaskMode) {
14693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org        sMaskDict->insertName("S", "Luminosity");
14793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org    }
1486112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref();
1496112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
1506112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    SkPDFGraphicState* result = new SkPDFGraphicState;
1516112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    result->fPopulated = true;
1526112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    result->fSMask = true;
153c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com    result->insertName("Type", "ExtGState");
1546112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    result->insert("SMask", sMaskDict.get());
1556112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    result->fResources.push(sMask);
1566112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    sMask->ref();
1576112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
1586112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    if (invert) {
15919e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        SkPDFObject* invertFunction = GetInvertFunction();
16019e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        result->fResources.push(invertFunction);
16119e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        invertFunction->ref();
16219e3c1ed1b20ce93cc092d25c3637b62f90c5bc5vandebo@chromium.org        sMaskDict->insert("TR", new SkPDFObjRef(invertFunction))->unref();
1636112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    }
1646112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
1656112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    return result;
1666112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org}
1676112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
1686112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org// static
169f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.comSkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() {
170f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com    SkAutoMutexAcquire lock(CanonicalPaintsMutex());
1716112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    static SkPDFGraphicState* noSMaskGS = NULL;
1726112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    if (!noSMaskGS) {
1736112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        noSMaskGS = new SkPDFGraphicState;
1746112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        noSMaskGS->fPopulated = true;
1756112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org        noSMaskGS->fSMask = true;
176c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        noSMaskGS->insertName("Type", "ExtGState");
177c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        noSMaskGS->insertName("SMask", "None");
1786112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    }
1796112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    noSMaskGS->ref();
1806112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    return noSMaskGS;
1816112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org}
1826112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
1836112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org// static
184f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.comint SkPDFGraphicState::Find(const SkPaint& paint) {
185b83f6c3cbdabc14d8290b00d9f38ba59bf6719a1mtklein    CanonicalPaintsMutex().assertHeld();
1869b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    GSCanonicalEntry search(&paint);
187f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com    return CanonicalPaints().find(search);
1889b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
1899b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
1906112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.orgSkPDFGraphicState::SkPDFGraphicState()
1916112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    : fPopulated(false),
1926112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org      fSMask(false) {
1936112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org}
1946112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org
1959b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.orgSkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint)
1969b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    : fPaint(paint),
1976112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org      fPopulated(false),
1986112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org      fSMask(false) {
1999b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
2009b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
2019b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org// populateDict and operator== have to stay in sync with each other.
2029b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.orgvoid SkPDFGraphicState::populateDict() {
2039b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    if (!fPopulated) {
2049b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        fPopulated = true;
205c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        insertName("Type", "ExtGState");
2069b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
207d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org        SkAutoTUnref<SkPDFScalar> alpha(
208d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org            new SkPDFScalar(SkScalarDiv(fPaint.getAlpha(), 0xFF)));
2099b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        insert("CA", alpha.get());
2109b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        insert("ca", alpha.get());
2119b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
212f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch);
213f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch);
214f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch);
215f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch);
2169b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2);
217c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        insertInt("LC", fPaint.getStrokeCap());
2189b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
219f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch);
220f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch);
221f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch);
222f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch);
2239b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2);
224c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        insertInt("LJ", fPaint.getStrokeJoin());
2259b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
226c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        insertScalar("LW", fPaint.getStrokeWidth());
227c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        insertScalar("ML", fPaint.getStrokeMiter());
228f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org        insert("SA", new SkPDFBool(true))->unref();  // Auto stroke adjustment.
22948543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org
23048543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode;
231f71b2103d56dde247605b718a0c89123ad8f0094vandebo@chromium.org        // If asMode fails, default to kSrcOver_Mode.
23248543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        if (fPaint.getXfermode())
23348543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org            fPaint.getXfermode()->asMode(&xfermode);
23448543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        // If we don't support the mode, just use kSrcOver_Mode.
23548543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        if (xfermode < 0 || xfermode > SkXfermode::kLastMode ||
2366112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org                blend_mode_from_xfermode(xfermode) == NULL) {
23748543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org            xfermode = SkXfermode::kSrcOver_Mode;
238f71b2103d56dde247605b718a0c89123ad8f0094vandebo@chromium.org            NOT_IMPLEMENTED("unsupported xfermode", false);
23948543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        }
240c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com        insertName("BM", blend_mode_from_xfermode(xfermode));
2419b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    }
2429b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
2439b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org
2449b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org// We're only interested in some fields of the SkPaint, so we have a custom
2459b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org// operator== function.
2469b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.orgbool SkPDFGraphicState::GSCanonicalEntry::operator==(
2479b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org        const SkPDFGraphicState::GSCanonicalEntry& gs) const {
2489b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    const SkPaint* a = fPaint;
2499b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    const SkPaint* b = gs.fPaint;
2509b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    SkASSERT(a != NULL);
2519b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    SkASSERT(b != NULL);
25248543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org
25348543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org    if (SkColorGetA(a->getColor()) != SkColorGetA(b->getColor()) ||
25448543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org           a->getStrokeCap() != b->getStrokeCap() ||
25548543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org           a->getStrokeJoin() != b->getStrokeJoin() ||
25648543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org           a->getStrokeWidth() != b->getStrokeWidth() ||
25748543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org           a->getStrokeMiter() != b->getStrokeMiter()) {
25848543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org        return false;
25948543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org    }
26048543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org
26148543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org    SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode;
26269d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    SkXfermode* aXfermode = a->getXfermode();
26369d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    if (aXfermode) {
26469d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org        aXfermode->asMode(&aXfermodeName);
26569d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    }
26669d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    if (aXfermodeName < 0 || aXfermodeName > SkXfermode::kLastMode ||
2676112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org            blend_mode_from_xfermode(aXfermodeName) == NULL) {
26869d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org        aXfermodeName = SkXfermode::kSrcOver_Mode;
26969d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    }
2706112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    const char* aXfermodeString = blend_mode_from_xfermode(aXfermodeName);
27169d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    SkASSERT(aXfermodeString != NULL);
27269d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org
27348543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org    SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode;
27469d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    SkXfermode* bXfermode = b->getXfermode();
27569d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    if (bXfermode) {
27669d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org        bXfermode->asMode(&bXfermodeName);
27769d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    }
27869d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    if (bXfermodeName < 0 || bXfermodeName > SkXfermode::kLastMode ||
2796112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org            blend_mode_from_xfermode(bXfermodeName) == NULL) {
28069d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org        bXfermodeName = SkXfermode::kSrcOver_Mode;
28169d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    }
2826112c215fbdd53388e64ece36e6c7bba0fe3a451vandebo@chromium.org    const char* bXfermodeString = blend_mode_from_xfermode(bXfermodeName);
28369d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    SkASSERT(bXfermodeString != NULL);
28448543277728fdf66b993f17421f65fba532a23a2vandebo@chromium.org
28569d4ca32ec0d6e61061f7d3c321f1b9ced6dd3eavandebo@chromium.org    return strcmp(aXfermodeString, bXfermodeString) == 0;
2869b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org}
287