SkPDFGraphicState.cpp revision 48543277728fdf66b993f17421f65fba532a23a2
1/* 2 * Copyright (C) 2011 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "SkPDFGraphicState.h" 18#include "SkStream.h" 19#include "SkTypes.h" 20 21namespace { 22 23const char* blendModeFromXfermode(SkXfermode::Mode mode) { 24 switch (mode) { 25 case SkXfermode::kSrcOver_Mode: return "Normal"; 26 case SkXfermode::kMultiply_Mode: return "Multiply"; 27 case SkXfermode::kScreen_Mode: return "Screen"; 28 case SkXfermode::kOverlay_Mode: return "Overlay"; 29 case SkXfermode::kDarken_Mode: return "Darken"; 30 case SkXfermode::kLighten_Mode: return "Lighten"; 31 case SkXfermode::kColorDodge_Mode: return "ColorDodge"; 32 case SkXfermode::kColorBurn_Mode: return "ColorBurn"; 33 case SkXfermode::kHardLight_Mode: return "HardLight"; 34 case SkXfermode::kSoftLight_Mode: return "SoftLight"; 35 case SkXfermode::kDifference_Mode: return "Difference"; 36 case SkXfermode::kExclusion_Mode: return "Exclusion"; 37 38 // TODO(vandebo) Figure out if we can support more of these modes. 39 case SkXfermode::kClear_Mode: 40 case SkXfermode::kSrc_Mode: 41 case SkXfermode::kDst_Mode: 42 case SkXfermode::kDstOver_Mode: 43 case SkXfermode::kSrcIn_Mode: 44 case SkXfermode::kDstIn_Mode: 45 case SkXfermode::kSrcOut_Mode: 46 case SkXfermode::kDstOut_Mode: 47 case SkXfermode::kSrcATop_Mode: 48 case SkXfermode::kDstATop_Mode: 49 case SkXfermode::kXor_Mode: 50 case SkXfermode::kPlus_Mode: 51 return NULL; 52 } 53 return NULL; 54} 55 56} 57 58SkPDFGraphicState::~SkPDFGraphicState() { 59 SkAutoMutexAcquire lock(canonicalPaintsMutex()); 60 int index = find(fPaint); 61 SkASSERT(index >= 0); 62 canonicalPaints().removeShuffle(index); 63} 64 65void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 66 bool indirect) { 67 populateDict(); 68 SkPDFDict::emitObject(stream, catalog, indirect); 69} 70 71// static 72size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 73 populateDict(); 74 return SkPDFDict::getOutputSize(catalog, indirect); 75} 76 77// static 78SkTDArray<SkPDFGraphicState::GSCanonicalEntry>& 79SkPDFGraphicState::canonicalPaints() { 80 // This initialization is only thread safe with gcc. 81 static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints; 82 return gCanonicalPaints; 83} 84 85// static 86SkMutex& SkPDFGraphicState::canonicalPaintsMutex() { 87 // This initialization is only thread safe with gcc. 88 static SkMutex gCanonicalPaintsMutex; 89 return gCanonicalPaintsMutex; 90} 91 92// static 93SkPDFGraphicState* SkPDFGraphicState::getGraphicStateForPaint( 94 const SkPaint& paint) { 95 SkAutoMutexAcquire lock(canonicalPaintsMutex()); 96 int index = find(paint); 97 if (index >= 0) { 98 canonicalPaints()[index].fGraphicState->ref(); 99 return canonicalPaints()[index].fGraphicState; 100 } 101 GSCanonicalEntry newEntry(new SkPDFGraphicState(paint)); 102 canonicalPaints().push(newEntry); 103 return newEntry.fGraphicState; 104} 105 106// static 107int SkPDFGraphicState::find(const SkPaint& paint) { 108 GSCanonicalEntry search(&paint); 109 return canonicalPaints().find(search); 110} 111 112SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint) 113 : fPaint(paint), 114 fPopulated(false) { 115} 116 117// populateDict and operator== have to stay in sync with each other. 118void SkPDFGraphicState::populateDict() { 119 if (!fPopulated) { 120 fPopulated = true; 121 insert("Type", new SkPDFName("ExtGState"))->unref(); 122 123 SkRefPtr<SkPDFScalar> alpha = 124 new SkPDFScalar(fPaint.getAlpha() * SkScalarInvert(0xFF)); 125 alpha->unref(); // SkRefPtr and new both took a reference. 126 insert("CA", alpha.get()); 127 insert("ca", alpha.get()); 128 129 SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch); 130 SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch); 131 SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch); 132 SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch); 133 SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2); 134 insert("LC", new SkPDFInt(fPaint.getStrokeCap()))->unref(); 135 136 SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch); 137 SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch); 138 SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch); 139 SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch); 140 SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2); 141 insert("LJ", new SkPDFInt(fPaint.getStrokeJoin()))->unref(); 142 143 insert("LW", new SkPDFScalar(fPaint.getStrokeWidth()))->unref(); 144 insert("ML", new SkPDFScalar(fPaint.getStrokeMiter()))->unref(); 145 insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment. 146 147 SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; 148 // If asMode fails return false, default to kSrcOver_Mode. 149 if (fPaint.getXfermode()) 150 fPaint.getXfermode()->asMode(&xfermode); 151 // If we don't support the mode, just use kSrcOver_Mode. 152 if (xfermode < 0 || xfermode > SkXfermode::kLastMode || 153 blendModeFromXfermode(xfermode) == NULL) { 154 fprintf(stderr, "NOT_IMPLEMENTED: xfermode = %d\n", xfermode); 155 xfermode = SkXfermode::kSrcOver_Mode; 156 } 157 insert("BM", new SkPDFName(blendModeFromXfermode(xfermode)))->unref(); 158 } 159} 160 161// We're only interested in some fields of the SkPaint, so we have a custom 162// operator== function. 163bool SkPDFGraphicState::GSCanonicalEntry::operator==( 164 const SkPDFGraphicState::GSCanonicalEntry& gs) const { 165 const SkPaint* a = fPaint; 166 const SkPaint* b = gs.fPaint; 167 SkASSERT(a != NULL); 168 SkASSERT(b != NULL); 169 170 if (SkColorGetA(a->getColor()) != SkColorGetA(b->getColor()) || 171 a->getStrokeCap() != b->getStrokeCap() || 172 a->getStrokeJoin() != b->getStrokeJoin() || 173 a->getStrokeWidth() != b->getStrokeWidth() || 174 a->getStrokeMiter() != b->getStrokeMiter()) { 175 return false; 176 } 177 178 SkXfermode* aXfermode = a->getXfermode(); 179 SkXfermode::Mode aXfermodeName = SkXfermode::kSrcOver_Mode; 180 bool aXfermodeKnown = true; 181 if (aXfermode) 182 aXfermodeKnown = aXfermode->asMode(&aXfermodeName); 183 SkXfermode* bXfermode = b->getXfermode(); 184 SkXfermode::Mode bXfermodeName = SkXfermode::kSrcOver_Mode; 185 bool bXfermodeKnown = true; 186 if (bXfermode) 187 bXfermodeKnown = bXfermode->asMode(&bXfermodeName); 188 189 if (aXfermodeKnown != bXfermodeKnown) 190 return false; 191 if (!aXfermodeKnown) 192 return aXfermode == bXfermode; 193 return aXfermodeName == bXfermodeName; 194} 195