blob: 286468bb620d8e6975c19277169cb6a67e238a6e [file] [log] [blame]
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00001/*
vandebo@chromium.org2a22e102011-01-25 21:01:34 +00002 * Copyright (C) 2011 Google Inc.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +00003 *
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"
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000019
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
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000109 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.
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000117 insert("ML", strokeMiterLimit.get());
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000118
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);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000134 return SkColorGetA(a->getColor()) == SkColorGetA(b->getColor()) &&
135 a->getStrokeCap() == b->getStrokeCap() &&
136 a->getStrokeJoin() == b->getStrokeJoin() &&
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000137 a->getStrokeWidth() == b->getStrokeWidth() &&
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000138 a->getStrokeMiter() == b->getStrokeMiter();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000139}