| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkData.h" | 8 #include "SkData.h" |
| 9 #include "SkPDFCanon.h" |
| 9 #include "SkPDFFormXObject.h" | 10 #include "SkPDFFormXObject.h" |
| 10 #include "SkPDFGraphicState.h" | 11 #include "SkPDFGraphicState.h" |
| 11 #include "SkPDFUtils.h" | 12 #include "SkPDFUtils.h" |
| 12 #include "SkTypes.h" | 13 #include "SkTypes.h" |
| 13 | 14 |
| 14 static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) { | |
| 15 switch (mode) { | |
| 16 case SkXfermode::kSrcOver_Mode: return "Normal"; | |
| 17 case SkXfermode::kMultiply_Mode: return "Multiply"; | |
| 18 case SkXfermode::kScreen_Mode: return "Screen"; | |
| 19 case SkXfermode::kOverlay_Mode: return "Overlay"; | |
| 20 case SkXfermode::kDarken_Mode: return "Darken"; | |
| 21 case SkXfermode::kLighten_Mode: return "Lighten"; | |
| 22 case SkXfermode::kColorDodge_Mode: return "ColorDodge"; | |
| 23 case SkXfermode::kColorBurn_Mode: return "ColorBurn"; | |
| 24 case SkXfermode::kHardLight_Mode: return "HardLight"; | |
| 25 case SkXfermode::kSoftLight_Mode: return "SoftLight"; | |
| 26 case SkXfermode::kDifference_Mode: return "Difference"; | |
| 27 case SkXfermode::kExclusion_Mode: return "Exclusion"; | |
| 28 case SkXfermode::kHue_Mode: return "Hue"; | |
| 29 case SkXfermode::kSaturation_Mode: return "Saturation"; | |
| 30 case SkXfermode::kColor_Mode: return "Color"; | |
| 31 case SkXfermode::kLuminosity_Mode: return "Luminosity"; | |
| 32 | |
| 33 // These are handled in SkPDFDevice::setUpContentEntry. | |
| 34 case SkXfermode::kClear_Mode: | |
| 35 case SkXfermode::kSrc_Mode: | |
| 36 case SkXfermode::kDst_Mode: | |
| 37 case SkXfermode::kDstOver_Mode: | |
| 38 case SkXfermode::kSrcIn_Mode: | |
| 39 case SkXfermode::kDstIn_Mode: | |
| 40 case SkXfermode::kSrcOut_Mode: | |
| 41 case SkXfermode::kDstOut_Mode: | |
| 42 case SkXfermode::kSrcATop_Mode: | |
| 43 case SkXfermode::kDstATop_Mode: | |
| 44 case SkXfermode::kModulate_Mode: | |
| 45 return "Normal"; | |
| 46 | |
| 47 // TODO(vandebo): Figure out if we can support more of these modes. | |
| 48 case SkXfermode::kXor_Mode: | |
| 49 case SkXfermode::kPlus_Mode: | |
| 50 return NULL; | |
| 51 } | |
| 52 return NULL; | |
| 53 } | |
| 54 | |
| 55 SkPDFGraphicState::~SkPDFGraphicState() { | 15 SkPDFGraphicState::~SkPDFGraphicState() { |
| 56 SkAutoMutexAcquire lock(CanonicalPaintsMutex()); | 16 SkAutoMutexAcquire lock(SkPDFCanon::GetPaintMutex()); |
| 57 if (!fSMask) { | 17 if (!fSMask) { |
| 58 int index = Find(fPaint); | 18 SkPDFCanon::GetCanon().removeGraphicState(this); |
| 59 SkASSERT(index >= 0); | |
| 60 SkASSERT(CanonicalPaints()[index].fGraphicState == this); | |
| 61 CanonicalPaints().removeShuffle(index); | |
| 62 } | 19 } |
| 63 fResources.unrefAll(); | 20 fResources.unrefAll(); |
| 64 } | 21 } |
| 65 | 22 |
| 66 void SkPDFGraphicState::getResources( | 23 void SkPDFGraphicState::getResources( |
| 67 const SkTSet<SkPDFObject*>& knownResourceObjects, | 24 const SkTSet<SkPDFObject*>& knownResourceObjects, |
| 68 SkTSet<SkPDFObject*>* newResourceObjects) { | 25 SkTSet<SkPDFObject*>* newResourceObjects) { |
| 69 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); | 26 GetResourcesHelper(&fResources, knownResourceObjects, newResourceObjects); |
| 70 } | 27 } |
| 71 | 28 |
| 72 void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog, | 29 void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog, |
| 73 bool indirect) { | 30 bool indirect) { |
| 74 populateDict(); | 31 populateDict(); |
| 75 SkPDFDict::emitObject(stream, catalog, indirect); | 32 SkPDFDict::emitObject(stream, catalog, indirect); |
| 76 } | 33 } |
| 77 | 34 |
| 78 // static | 35 // static |
| 79 size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) { | 36 size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) { |
| 80 populateDict(); | 37 populateDict(); |
| 81 return SkPDFDict::getOutputSize(catalog, indirect); | 38 return SkPDFDict::getOutputSize(catalog, indirect); |
| 82 } | 39 } |
| 83 | 40 |
| 84 // static | 41 // static |
| 85 SkTDArray<SkPDFGraphicState::GSCanonicalEntry>& SkPDFGraphicState::CanonicalPain
ts() { | |
| 86 CanonicalPaintsMutex().assertHeld(); | |
| 87 static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints; | |
| 88 return gCanonicalPaints; | |
| 89 } | |
| 90 | |
| 91 SK_DECLARE_STATIC_MUTEX(gCanonicalPaintsMutex); | |
| 92 // static | |
| 93 SkBaseMutex& SkPDFGraphicState::CanonicalPaintsMutex() { | |
| 94 return gCanonicalPaintsMutex; | |
| 95 } | |
| 96 | |
| 97 // static | |
| 98 SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint(const SkPaint& pai
nt) { | 42 SkPDFGraphicState* SkPDFGraphicState::GetGraphicStateForPaint(const SkPaint& pai
nt) { |
| 99 SkAutoMutexAcquire lock(CanonicalPaintsMutex()); | 43 SkAutoMutexAcquire lock(SkPDFCanon::GetPaintMutex()); |
| 100 int index = Find(paint); | 44 SkPDFGraphicState* pdfGraphicState = |
| 101 if (index >= 0) { | 45 SkPDFCanon::GetCanon().findGraphicState(paint); |
| 102 CanonicalPaints()[index].fGraphicState->ref(); | 46 if (pdfGraphicState) { |
| 103 return CanonicalPaints()[index].fGraphicState; | 47 return SkRef(pdfGraphicState); |
| 104 } | 48 } |
| 105 GSCanonicalEntry newEntry(new SkPDFGraphicState(paint)); | 49 pdfGraphicState = new SkPDFGraphicState(paint); |
| 106 CanonicalPaints().push(newEntry); | 50 SkPDFCanon::GetCanon().addGraphicState(pdfGraphicState); |
| 107 return newEntry.fGraphicState; | 51 return pdfGraphicState; |
| 108 } | 52 } |
| 109 | 53 |
| 110 // static | 54 // static |
| 111 SkPDFObject* SkPDFGraphicState::GetInvertFunction() { | 55 SkPDFObject* SkPDFGraphicState::GetInvertFunction() { |
| 112 // This assumes that canonicalPaintsMutex is held. | 56 // This assumes that canonicalPaintsMutex is held. |
| 113 CanonicalPaintsMutex().assertHeld(); | 57 SkPDFCanon::GetPaintMutex().assertHeld(); |
| 114 static SkPDFStream* invertFunction = NULL; | 58 static SkPDFStream* invertFunction = NULL; |
| 115 if (!invertFunction) { | 59 if (!invertFunction) { |
| 116 // Acrobat crashes if we use a type 0 function, kpdf crashes if we use | 60 // Acrobat crashes if we use a type 0 function, kpdf crashes if we use |
| 117 // a type 2 function, so we use a type 4 function. | 61 // a type 2 function, so we use a type 4 function. |
| 118 SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray); | 62 SkAutoTUnref<SkPDFArray> domainAndRange(new SkPDFArray); |
| 119 domainAndRange->reserve(2); | 63 domainAndRange->reserve(2); |
| 120 domainAndRange->appendInt(0); | 64 domainAndRange->appendInt(0); |
| 121 domainAndRange->appendInt(1); | 65 domainAndRange->appendInt(1); |
| 122 | 66 |
| 123 static const char psInvert[] = "{1 exch sub}"; | 67 static const char psInvert[] = "{1 exch sub}"; |
| 124 // Do not copy the trailing '\0' into the SkData. | 68 // Do not copy the trailing '\0' into the SkData. |
| 125 SkAutoTUnref<SkData> psInvertStream( | 69 SkAutoTUnref<SkData> psInvertStream( |
| 126 SkData::NewWithoutCopy(psInvert, strlen(psInvert))); | 70 SkData::NewWithoutCopy(psInvert, strlen(psInvert))); |
| 127 | 71 |
| 128 invertFunction = new SkPDFStream(psInvertStream.get()); | 72 invertFunction = new SkPDFStream(psInvertStream.get()); |
| 129 invertFunction->insertInt("FunctionType", 4); | 73 invertFunction->insertInt("FunctionType", 4); |
| 130 invertFunction->insert("Domain", domainAndRange.get()); | 74 invertFunction->insert("Domain", domainAndRange.get()); |
| 131 invertFunction->insert("Range", domainAndRange.get()); | 75 invertFunction->insert("Range", domainAndRange.get()); |
| 132 } | 76 } |
| 133 return invertFunction; | 77 return invertFunction; |
| 134 } | 78 } |
| 135 | 79 |
| 136 // static | 80 // static |
| 137 SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState( | 81 SkPDFGraphicState* SkPDFGraphicState::GetSMaskGraphicState( |
| 138 SkPDFFormXObject* sMask, bool invert, SkPDFSMaskMode sMaskMode) { | 82 SkPDFFormXObject* sMask, bool invert, SkPDFSMaskMode sMaskMode) { |
| 139 // The practical chances of using the same mask more than once are unlikely | 83 // The practical chances of using the same mask more than once are unlikely |
| 140 // enough that it's not worth canonicalizing. | 84 // enough that it's not worth canonicalizing. |
| 141 SkAutoMutexAcquire lock(CanonicalPaintsMutex()); | 85 SkAutoMutexAcquire lock(SkPDFCanon::GetPaintMutex()); |
| 142 | |
| 143 SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask")); | 86 SkAutoTUnref<SkPDFDict> sMaskDict(new SkPDFDict("Mask")); |
| 144 if (sMaskMode == kAlpha_SMaskMode) { | 87 if (sMaskMode == kAlpha_SMaskMode) { |
| 145 sMaskDict->insertName("S", "Alpha"); | 88 sMaskDict->insertName("S", "Alpha"); |
| 146 } else if (sMaskMode == kLuminosity_SMaskMode) { | 89 } else if (sMaskMode == kLuminosity_SMaskMode) { |
| 147 sMaskDict->insertName("S", "Luminosity"); | 90 sMaskDict->insertName("S", "Luminosity"); |
| 148 } | 91 } |
| 149 sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref(); | 92 sMaskDict->insert("G", new SkPDFObjRef(sMask))->unref(); |
| 150 | 93 |
| 151 SkPDFGraphicState* result = new SkPDFGraphicState; | 94 SkPDFGraphicState* result = new SkPDFGraphicState; |
| 152 result->fPopulated = true; | 95 result->fPopulated = true; |
| 153 result->fSMask = true; | 96 result->fSMask = true; |
| 154 result->insertName("Type", "ExtGState"); | 97 result->insertName("Type", "ExtGState"); |
| 155 result->insert("SMask", sMaskDict.get()); | 98 result->insert("SMask", sMaskDict.get()); |
| 156 result->fResources.push(sMask); | 99 result->fResources.push(sMask); |
| 157 sMask->ref(); | 100 sMask->ref(); |
| 158 | 101 |
| 159 if (invert) { | 102 if (invert) { |
| 160 SkPDFObject* invertFunction = GetInvertFunction(); | 103 SkPDFObject* invertFunction = GetInvertFunction(); |
| 161 result->fResources.push(invertFunction); | 104 result->fResources.push(invertFunction); |
| 162 invertFunction->ref(); | 105 invertFunction->ref(); |
| 163 sMaskDict->insert("TR", new SkPDFObjRef(invertFunction))->unref(); | 106 sMaskDict->insert("TR", new SkPDFObjRef(invertFunction))->unref(); |
| 164 } | 107 } |
| 165 | 108 |
| 166 return result; | 109 return result; |
| 167 } | 110 } |
| 168 | 111 |
| 169 // static | 112 // static |
| 170 SkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() { | 113 SkPDFGraphicState* SkPDFGraphicState::GetNoSMaskGraphicState() { |
| 171 SkAutoMutexAcquire lock(CanonicalPaintsMutex()); | 114 SkAutoMutexAcquire lock(SkPDFCanon::GetPaintMutex()); |
| 172 static SkPDFGraphicState* noSMaskGS = NULL; | 115 static SkPDFGraphicState* noSMaskGS = NULL; |
| 173 if (!noSMaskGS) { | 116 if (!noSMaskGS) { |
| 174 noSMaskGS = new SkPDFGraphicState; | 117 noSMaskGS = new SkPDFGraphicState; |
| 175 noSMaskGS->fPopulated = true; | 118 noSMaskGS->fPopulated = true; |
| 176 noSMaskGS->fSMask = true; | 119 noSMaskGS->fSMask = true; |
| 177 noSMaskGS->insertName("Type", "ExtGState"); | 120 noSMaskGS->insertName("Type", "ExtGState"); |
| 178 noSMaskGS->insertName("SMask", "None"); | 121 noSMaskGS->insertName("SMask", "None"); |
| 179 } | 122 } |
| 180 noSMaskGS->ref(); | 123 noSMaskGS->ref(); |
| 181 return noSMaskGS; | 124 return noSMaskGS; |
| 182 } | 125 } |
| 183 | 126 |
| 184 // static | |
| 185 int SkPDFGraphicState::Find(const SkPaint& paint) { | |
| 186 CanonicalPaintsMutex().assertHeld(); | |
| 187 GSCanonicalEntry search(&paint); | |
| 188 return CanonicalPaints().find(search); | |
| 189 } | |
| 190 | |
| 191 SkPDFGraphicState::SkPDFGraphicState() | 127 SkPDFGraphicState::SkPDFGraphicState() |
| 192 : fPopulated(false), | 128 : fPopulated(false), |
| 193 fSMask(false) { | 129 fSMask(false) { |
| 194 } | 130 } |
| 195 | 131 |
| 196 SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint) | 132 SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint) |
| 197 : fPaint(paint), | 133 : fPaint(paint), |
| 198 fPopulated(false), | 134 fPopulated(false), |
| 199 fSMask(false) { | 135 fSMask(false) { |
| 200 } | 136 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 227 insertScalar("LW", fPaint.getStrokeWidth()); | 163 insertScalar("LW", fPaint.getStrokeWidth()); |
| 228 insertScalar("ML", fPaint.getStrokeMiter()); | 164 insertScalar("ML", fPaint.getStrokeMiter()); |
| 229 insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment. | 165 insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment. |
| 230 | 166 |
| 231 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; | 167 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; |
| 232 // If asMode fails, default to kSrcOver_Mode. | 168 // If asMode fails, default to kSrcOver_Mode. |
| 233 if (fPaint.getXfermode()) | 169 if (fPaint.getXfermode()) |
| 234 fPaint.getXfermode()->asMode(&xfermode); | 170 fPaint.getXfermode()->asMode(&xfermode); |
| 235 // If we don't support the mode, just use kSrcOver_Mode. | 171 // If we don't support the mode, just use kSrcOver_Mode. |
| 236 if (xfermode < 0 || xfermode > SkXfermode::kLastMode || | 172 if (xfermode < 0 || xfermode > SkXfermode::kLastMode || |
| 237 blend_mode_from_xfermode(xfermode) == NULL) { | 173 PDFBlendModeFromXfermode(xfermode) == NULL) { |
| 238 xfermode = SkXfermode::kSrcOver_Mode; | 174 xfermode = SkXfermode::kSrcOver_Mode; |
| 239 NOT_IMPLEMENTED("unsupported xfermode", false); | 175 NOT_IMPLEMENTED("unsupported xfermode", false); |
| 240 } | 176 } |
| 241 insertName("BM", blend_mode_from_xfermode(xfermode)); | 177 insertName("BM", PDFBlendModeFromXfermode(xfermode)); |
| 242 } | 178 } |
| 243 } | 179 } |
| 244 | 180 |
| 245 // We're only interested in some fields of the SkPaint, so we have a custom | |
| 246 // operator== function. | |
| 247 bool SkPDFGraphicState::GSCanonicalEntry::operator==( | |
| 248 const SkPDFGraphicState::GSCanonicalEntry& gs) const { | |
| 249 const SkPaint* a = fPaint; | |
| 250 const SkPaint* b = gs.fPaint; | |
| 251 SkASSERT(a != NULL); | |
| 252 SkASSERT(b != NULL); | |
| 253 | |
| 254 if (SkColorGetA(a->getColor()) != SkColorGetA(b->getColor()) || | |
| 255 a->getStrokeCap() != b->getStrokeCap() || | |
| 256 a->getStrokeJoin() != b->getStrokeJoin() || | |
| 257 a->getStrokeWidth() != b->getStrokeWidth() || | |
| 258 a->getStrokeMiter() != b->getStrokeMiter()) { | |
| 259 return false; | |
| 260 } | |
| 261 | |
| 262 SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode; | |
| 263 SkXfermode* aXfermode = a->getXfermode(); | |
| 264 if (aXfermode) { | |
| 265 aXfermode->asMode(&aXfermodeName); | |
| 266 } | |
| 267 if (aXfermodeName < 0 || aXfermodeName > SkXfermode::kLastMode || | |
| 268 blend_mode_from_xfermode(aXfermodeName) == NULL) { | |
| 269 aXfermodeName = SkXfermode::kSrcOver_Mode; | |
| 270 } | |
| 271 const char* aXfermodeString = blend_mode_from_xfermode(aXfermodeName); | |
| 272 SkASSERT(aXfermodeString != NULL); | |
| 273 | |
| 274 SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode; | |
| 275 SkXfermode* bXfermode = b->getXfermode(); | |
| 276 if (bXfermode) { | |
| 277 bXfermode->asMode(&bXfermodeName); | |
| 278 } | |
| 279 if (bXfermodeName < 0 || bXfermodeName > SkXfermode::kLastMode || | |
| 280 blend_mode_from_xfermode(bXfermodeName) == NULL) { | |
| 281 bXfermodeName = SkXfermode::kSrcOver_Mode; | |
| 282 } | |
| 283 const char* bXfermodeString = blend_mode_from_xfermode(bXfermodeName); | |
| 284 SkASSERT(bXfermodeString != NULL); | |
| 285 | |
| 286 return strcmp(aXfermodeString, bXfermodeString) == 0; | |
| 287 } | |
| OLD | NEW |