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