SkPDFGraphicState.cpp revision 28be72b63e457c680c192a34fb9f58e1c693363f
1/* 2 * Copyright (C) 2010 The Android Open Source Project 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 20SkPDFGraphicState::~SkPDFGraphicState() { 21 SkAutoMutexAcquire lock(canonicalPaintsMutex()); 22 int index = find(fPaint); 23 SkASSERT(index >= 0); 24 canonicalPaints().removeShuffle(index); 25} 26 27void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 28 bool indirect) { 29 populateDict(); 30 SkPDFDict::emitObject(stream, catalog, indirect); 31} 32 33size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 34 populateDict(); 35 return SkPDFDict::getOutputSize(catalog, indirect); 36} 37 38// static 39SkTDArray<SkPDFGraphicState::GSCanonicalEntry>& 40SkPDFGraphicState::canonicalPaints() { 41 // This initialization is only thread safe with gcc. 42 static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints; 43 return gCanonicalPaints; 44} 45 46// static 47SkMutex& SkPDFGraphicState::canonicalPaintsMutex() { 48 // This initialization is only thread safe with gcc. 49 static SkMutex gCanonicalPaintsMutex; 50 return gCanonicalPaintsMutex; 51} 52 53// static 54SkPDFGraphicState* SkPDFGraphicState::getGraphicStateForPaint( 55 const SkPaint& paint) { 56 SkAutoMutexAcquire lock(canonicalPaintsMutex()); 57 int index = find(paint); 58 if (index >= 0) { 59 canonicalPaints()[index].fGraphicState->ref(); 60 return canonicalPaints()[index].fGraphicState; 61 } 62 GSCanonicalEntry newEntry(new SkPDFGraphicState(paint)); 63 canonicalPaints().push(newEntry); 64 return newEntry.fGraphicState; 65} 66 67// static 68int SkPDFGraphicState::find(const SkPaint& paint) { 69 GSCanonicalEntry search(&paint); 70 return canonicalPaints().find(search); 71} 72 73SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint) 74 : fPaint(paint), 75 fPopulated(false) { 76} 77 78// populateDict and operator== have to stay in sync with each other. 79void SkPDFGraphicState::populateDict() { 80 if (!fPopulated) { 81 fPopulated = true; 82 SkRefPtr<SkPDFName> typeName = new SkPDFName("ExtGState"); 83 typeName->unref(); // SkRefPtr and new both took a reference. 84 insert("Type", typeName.get()); 85 86 SkScalar maxAlpha = SkIntToScalar(0xFF); 87 SkRefPtr<SkPDFScalar> alpha = 88 new SkPDFScalar(SkColorGetA(fPaint.getColor())/maxAlpha); 89 alpha->unref(); // SkRefPtr and new both took a reference. 90 insert("CA", alpha.get()); 91 insert("ca", alpha.get()); 92 93 SkASSERT(SkPaint::kButt_Cap == 0); 94 SkASSERT(SkPaint::kRound_Cap == 1); 95 SkASSERT(SkPaint::kSquare_Cap == 2); 96 SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2); 97 SkRefPtr<SkPDFInt> strokeCap = new SkPDFInt(fPaint.getStrokeCap()); 98 strokeCap->unref(); // SkRefPtr and new both took a reference. 99 insert("LC", strokeCap.get()); 100 101 SkASSERT(SkPaint::kMiter_Join == 0); 102 SkASSERT(SkPaint::kRound_Join == 1); 103 SkASSERT(SkPaint::kBevel_Join == 2); 104 SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2); 105 SkRefPtr<SkPDFInt> strokeJoin = new SkPDFInt(fPaint.getStrokeJoin()); 106 strokeJoin->unref(); // SkRefPtr and new both took a reference. 107 insert("LJ", strokeJoin.get()); 108 109 SkRefPtr<SkPDFScalar> strokeWidth = 110 new SkPDFScalar(fPaint.getStrokeWidth()); 111 strokeWidth->unref(); // SkRefPtr and new both took a reference. 112 insert("LW", strokeWidth.get()); 113 114 SkRefPtr<SkPDFScalar> strokeMiterLimit = new SkPDFScalar( 115 fPaint.getStrokeMiter()); 116 strokeMiterLimit->unref(); // SkRefPtr and new both took a reference. 117 insert("ML", strokeWidth.get()); 118 119 // Turn on automatic stroke adjustment. 120 SkRefPtr<SkPDFBool> trueVal = new SkPDFBool(true); 121 trueVal->unref(); // SkRefPtr and new both took a reference. 122 insert("SA", trueVal.get()); 123 } 124} 125 126// We're only interested in some fields of the SkPaint, so we have a custom 127// operator== function. 128bool SkPDFGraphicState::GSCanonicalEntry::operator==( 129 const SkPDFGraphicState::GSCanonicalEntry& gs) const { 130 const SkPaint* a = fPaint; 131 const SkPaint* b = gs.fPaint; 132 SkASSERT(a != NULL); 133 SkASSERT(b != NULL); 134 return SkColorGetA(a->getColor()) == SkColorGetA(b->getColor()) && 135 a->getStrokeCap() == b->getStrokeCap() && 136 a->getStrokeJoin() == b->getStrokeJoin() && 137 a->getStrokeWidth() == b->getStrokeWidth() && 138 a->getStrokeMiter() == b->getStrokeMiter(); 139} 140