blob: ff55941d750f0ac60a8cb87c5177dd80869e9554 [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;
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +000082 insert("Type", new SkPDFName("ExtGState"))->unref();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000083
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000084 SkRefPtr<SkPDFScalar> alpha =
vandebo@chromium.org1cfa2c42011-01-31 19:35:43 +000085 new SkPDFScalar(fPaint.getAlpha() * SkScalarInvert(0xFF));
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000086 alpha->unref(); // SkRefPtr and new both took a reference.
87 insert("CA", alpha.get());
88 insert("ca", alpha.get());
89
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +000090 SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch);
91 SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch);
92 SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch);
93 SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000094 SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +000095 insert("LC", new SkPDFInt(fPaint.getStrokeCap()))->unref();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +000096
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +000097 SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch);
98 SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch);
99 SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch);
100 SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000101 SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000102 insert("LJ", new SkPDFInt(fPaint.getStrokeJoin()))->unref();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000103
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000104 insert("LW", new SkPDFScalar(fPaint.getStrokeWidth()))->unref();
105 insert("ML", new SkPDFScalar(fPaint.getStrokeMiter()))->unref();
106 insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment.
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000107 }
108}
109
110// We're only interested in some fields of the SkPaint, so we have a custom
111// operator== function.
112bool SkPDFGraphicState::GSCanonicalEntry::operator==(
113 const SkPDFGraphicState::GSCanonicalEntry& gs) const {
114 const SkPaint* a = fPaint;
115 const SkPaint* b = gs.fPaint;
116 SkASSERT(a != NULL);
117 SkASSERT(b != NULL);
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000118 return SkColorGetA(a->getColor()) == SkColorGetA(b->getColor()) &&
119 a->getStrokeCap() == b->getStrokeCap() &&
120 a->getStrokeJoin() == b->getStrokeJoin() &&
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000121 a->getStrokeWidth() == b->getStrokeWidth() &&
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000122 a->getStrokeMiter() == b->getStrokeMiter();
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000123}