blob: d0d47b5e6f098481754e79e683f24c723841185c [file] [log] [blame]
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00001/*
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#include "SkTypeface.h"
20
21SkPDFGraphicState::~SkPDFGraphicState() {
22 SkAutoMutexAcquire lock(canonicalPaintsMutex());
23 int index = find(fPaint);
24 SkASSERT(index >= 0);
25 canonicalPaints().removeShuffle(index);
26}
27
28void SkPDFGraphicState::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
29 bool indirect) {
30 populateDict();
31 SkPDFDict::emitObject(stream, catalog, indirect);
32}
33
34size_t SkPDFGraphicState::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
35 populateDict();
36 return SkPDFDict::getOutputSize(catalog, indirect);
37}
38
39// static
40SkTDArray<SkPDFGraphicState::GSCanonicalEntry>&
41SkPDFGraphicState::canonicalPaints() {
42 // This initialization is only thread safe with gcc.
43 static SkTDArray<SkPDFGraphicState::GSCanonicalEntry> gCanonicalPaints;
44 return gCanonicalPaints;
45}
46
47// static
48SkMutex& SkPDFGraphicState::canonicalPaintsMutex() {
49 // This initialization is only thread safe with gcc.
50 static SkMutex gCanonicalPaintsMutex;
51 return gCanonicalPaintsMutex;
52}
53
54// static
55SkPDFGraphicState* SkPDFGraphicState::getGraphicStateForPaint(
56 const SkPaint& paint) {
57 SkAutoMutexAcquire lock(canonicalPaintsMutex());
58 int index = find(paint);
59 if (index >= 0) {
60 canonicalPaints()[index].fGraphicState->ref();
61 return canonicalPaints()[index].fGraphicState;
62 }
63 GSCanonicalEntry newEntry(new SkPDFGraphicState(paint));
64 canonicalPaints().push(newEntry);
65 return newEntry.fGraphicState;
66}
67
68// static
69int SkPDFGraphicState::find(const SkPaint& paint) {
70 GSCanonicalEntry search(&paint);
71 return canonicalPaints().find(search);
72}
73
74SkPDFGraphicState::SkPDFGraphicState(const SkPaint& paint)
75 : fPaint(paint),
76 fPopulated(false) {
77}
78
79// populateDict and operator== have to stay in sync with each other.
80void SkPDFGraphicState::populateDict() {
81 if (!fPopulated) {
82 fPopulated = true;
83 SkRefPtr<SkPDFName> typeName = new SkPDFName("ExtGState");
84 typeName->unref(); // SkRefPtr and new both took a reference.
85 insert("Type", typeName.get());
86
87 SkScalar maxAlpha = SkIntToScalar(0xFF);
88 SkRefPtr<SkPDFScalar> alpha =
89 new SkPDFScalar(SkColorGetA(fPaint.getColor())/maxAlpha);
90 alpha->unref(); // SkRefPtr and new both took a reference.
91 insert("CA", alpha.get());
92 insert("ca", alpha.get());
93
94 SkASSERT(SkPaint::kButt_Cap == 0);
95 SkASSERT(SkPaint::kRound_Cap == 1);
96 SkASSERT(SkPaint::kSquare_Cap == 2);
97 SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2);
98 SkRefPtr<SkPDFInt> strokeCap = new SkPDFInt(fPaint.getStrokeCap());
99 strokeCap->unref(); // SkRefPtr and new both took a reference.
100 insert("LC", strokeCap.get());
101
102 SkASSERT(SkPaint::kMiter_Join == 0);
103 SkASSERT(SkPaint::kRound_Join == 1);
104 SkASSERT(SkPaint::kBevel_Join == 2);
105 SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2);
106 SkRefPtr<SkPDFInt> strokeJoin = new SkPDFInt(fPaint.getStrokeJoin());
107 strokeJoin->unref(); // SkRefPtr and new both took a reference.
108 insert("LJ", strokeJoin.get());
109
110 /* TODO(vandebo) Font.
111 if (fPaint.getTypeFace() != NULL) {
112 SkRefPtr<SkPDFTypeFace> typeFace =
113 SkPDFTypeFace::getFontForTypeFace(fPaint.getTypeFace);
114 SkRefPtr<SkPDFObjRef> typeFaceRef = new SkPDFObjRef(typeFace.get());
115 fontRef->unref(); // SkRefPtr and new both took a reference.
116 SkRefPtr<SkPDFScalar> fontSize =
117 new SkPDFScalar(fPaint.getTetSize());
118 fontSize->unref(); // SkRefPtr and new both took a reference.
119 SkRefPtr<SkPDFArray> font = new SkPDFArray();
120 font->unref(); // SkRefPtr and new both took a reference.
121 font->reserve(2);
122 font->append(typeFaceRef.get());
123 font->append(fontSize.get());
124 insert("LJ", font.get());
125 }
126 */
127
128 SkRefPtr<SkPDFScalar> strokeWidth =
129 new SkPDFScalar(fPaint.getStrokeWidth());
130 strokeWidth->unref(); // SkRefPtr and new both took a reference.
131 insert("LW", strokeWidth.get());
132
133 SkRefPtr<SkPDFScalar> strokeMiterLimit = new SkPDFScalar(
134 fPaint.getStrokeMiter());
135 strokeMiterLimit->unref(); // SkRefPtr and new both took a reference.
136 insert("ML", strokeWidth.get());
137
138 // Turn on automatic stroke adjustment.
139 SkRefPtr<SkPDFBool> trueVal = new SkPDFBool(true);
140 trueVal->unref(); // SkRefPtr and new both took a reference.
141 insert("SA", trueVal.get());
142 }
143}
144
145// We're only interested in some fields of the SkPaint, so we have a custom
146// operator== function.
147bool SkPDFGraphicState::GSCanonicalEntry::operator==(
148 const SkPDFGraphicState::GSCanonicalEntry& gs) const {
149 const SkPaint* a = fPaint;
150 const SkPaint* b = gs.fPaint;
151 SkASSERT(a != NULL);
152 SkASSERT(b != NULL);
153 SkTypeface* aFace = a->getTypeface();
154 SkTypeface* bFace = b->getTypeface();
155 return SkColorGetA(a->getColor()) == SkColorGetA(b->getColor()) &&
156 a->getStrokeCap() == b->getStrokeCap() &&
157 a->getStrokeJoin() == b->getStrokeJoin() &&
158 a->getTextSize() == b->getTextSize() &&
159 a->getStrokeWidth() == b->getStrokeWidth() &&
160 a->getStrokeMiter() == b->getStrokeMiter() &&
161 (aFace == NULL) == (bFace == NULL) &&
162 (aFace == NULL || aFace->uniqueID() == bFace->uniqueID());
163}