blob: 1bbc53af4ec19b7defaaa15e78ca83dd0ccf1a03 [file] [log] [blame]
vandebo@chromium.org28be72b2010-11-11 21:37:00 +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 "SkPaint.h"
18#include "SkPDFFont.h"
19#include "SkUtils.h"
20
21namespace {
22
23uint16_t unicharToWinAnsiGlyphID(SkUnichar uniChar) {
24 // TODO(vandebo) Quick hack to get text working. Either finish the
25 // implementation of this, or remove it and use the encoding built into
26 // the real font.
27 if (uniChar < ' ')
28 return 0;
29 if (uniChar < '~')
30 return uniChar;
31 return 0;
32}
33
34}
35
36SkPDFFont::~SkPDFFont() {
37 SkAutoMutexAcquire lock(canonicalFontsMutex());
38 int index = find(fFontID);
39 SkASSERT(index >= 0);
40 canonicalFonts().removeShuffle(index);
41}
42
43void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
44 resourceList->setReserve(resourceList->count() + fResources.count());
45 for (int i = 0; i < fResources.count(); i++) {
46 resourceList->push(fResources[i]);
47 fResources[i]->ref();
48 fResources[i]->getResources(resourceList);
49 }
50}
51
52uint32_t SkPDFFont::fontID() {
53 return fFontID;
54}
55
56bool SkPDFFont::multiByteGlyphs() {
57 return fMultiByteGlyphs;
58}
59
60// TODO(vandebo) This function goes or stays with unicharToWinAnsiGlyphID.
61int SkPDFFont::textToPDFGlyphs(const void* text, size_t byteLength,
62 const SkPaint& paint, uint16_t glyphs[],
63 size_t glyphsLength) const {
64 // For a regular, non built-in font, just ask the paint.
65 if (fResources.count() != 0) {
66 SkASSERT(glyphsLength >= byteLength / 2);
67 if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
68 memcpy(glyphs, text, byteLength / 2 * 2);
69 return byteLength / 2;
70 } else {
71 return paint.textToGlyphs(text, byteLength, glyphs);
72 }
73 }
74
75 const char* data = (const char*)text;
76 const char* stop = data + byteLength;
77 const uint16_t* data16 = (const uint16_t*)data;
78 const uint16_t* stop16 = (const uint16_t*)stop;
79 uint16_t* gPtr = glyphs;
80 uint16_t* gEnd = glyphs + glyphsLength;
81
82 // For a built-in font (no resources), we may have to undo glyph encoding
83 // before converting to the standard pdf encoding.
84 switch(paint.getTextEncoding()) {
85 case SkPaint::kUTF8_TextEncoding:
86 while (data < stop && gPtr < gEnd)
87 *gPtr++ = unicharToWinAnsiGlyphID(SkUTF8_NextUnichar(&data));
88 SkASSERT(data >= stop);
89 break;
90 case SkPaint::kUTF16_TextEncoding:
91 while (data16 < stop16 && gPtr < gEnd)
92 *gPtr++ = unicharToWinAnsiGlyphID(SkUTF16_NextUnichar(&data16));
93 SkASSERT(data16 >= stop16);
94 break;
95 case SkPaint::kGlyphID_TextEncoding:
96 while (data16 < stop16 && gPtr < gEnd) {
97 SkUnichar buf;
98 paint.glyphsToUnichars(data16++, 1, &buf);
99 *gPtr++ = unicharToWinAnsiGlyphID(buf);
100 }
101 SkASSERT(data16 >= stop16);
102 break;
103 default:
104 SkASSERT(!"Unknown text encoding");
105 break;
106 }
107 return gPtr - glyphs;
108}
109
110// static
111SkPDFFont* SkPDFFont::getFontResouceByID(uint32_t fontID) {
112 SkAutoMutexAcquire lock(canonicalFontsMutex());
113 int index = find(fontID);
114 if (index >= 0) {
115 canonicalFonts()[index].fFont->ref();
116 return canonicalFonts()[index].fFont;
117 }
118
119 // TODO(vandebo) Lookup and create the font. For now, just use the built-in
120 // Helevtica.
121 SkPDFFont* font = new SkPDFFont(fontID, false);
122 font->populateBuiltinFont("Helvetica");
123
124 FontRec newEntry(font, fontID);
125 canonicalFonts().push(newEntry);
126 return font; // Return the reference new SkPDFFont() created.
127}
128
129// static
130SkTDArray<SkPDFFont::FontRec>& SkPDFFont::canonicalFonts() {
131 // This initialization is only thread safe with gcc.
132 static SkTDArray<FontRec> gCanonicalFonts;
133 return gCanonicalFonts;
134}
135
136// static
137SkMutex& SkPDFFont::canonicalFontsMutex() {
138 // This initialization is only thread safe with gcc.
139 static SkMutex gCanonicalFontsMutex;
140 return gCanonicalFontsMutex;
141}
142
143// static
144int SkPDFFont::find(uint32_t fontID) {
145 FontRec search(NULL, fontID);
146 return canonicalFonts().find(search);
147}
148
149SkPDFFont::SkPDFFont(uint32_t fontID, bool multiByteGlyphs)
150 : fFontID(fontID),
151 fMultiByteGlyphs(multiByteGlyphs) {
152}
153
154void SkPDFFont::populateBuiltinFont(const char fontName[]) {
155 SkASSERT(strcmp(fontName, "Time-Roman") == 0 ||
156 strcmp(fontName, "Time-Bold") == 0 ||
157 strcmp(fontName, "Time-Italic") == 0 ||
158 strcmp(fontName, "Time-BoldItalic") == 0 ||
159 strcmp(fontName, "Helvetica") == 0 ||
160 strcmp(fontName, "Helvetica-Bold") == 0 ||
161 strcmp(fontName, "Helvetica-Oblique") == 0 ||
162 strcmp(fontName, "Helvetica-BoldOblique") == 0 ||
163 strcmp(fontName, "Courier") == 0 ||
164 strcmp(fontName, "Courier-Bold") == 0 ||
165 strcmp(fontName, "Courier-Oblique") == 0 ||
166 strcmp(fontName, "Courier-BoldOblique") == 0 ||
167 strcmp(fontName, "Symbol") == 0 ||
168 strcmp(fontName, "ZapfDingbats") == 0);
169
170 SkRefPtr<SkPDFName> type = new SkPDFName("Font");
171 type->unref(); // SkRefPtr and new both took a reference.
172 insert("Type", type.get());
173
174 SkRefPtr<SkPDFName> subType = new SkPDFName("Type1");
175 subType->unref(); // SkRefPtr and new both took a reference.
176 insert("Subtype", subType.get());
177
178 SkRefPtr<SkPDFName> baseFont = new SkPDFName(fontName);
179 baseFont->unref(); // SkRefPtr and new both took a reference.
180 insert("BaseFont", baseFont.get());
181
182 SkRefPtr<SkPDFName> encoding = new SkPDFName("WinAnsiEncoding");
183 encoding->unref(); // SkRefPtr and new both took a reference.
184 insert("Encoding", encoding.get());
185}
186
187void SkPDFFont::populateFont(const char subType[], const char fontName[],
188 int firstChar, int lastChar, int widths[],
189 SkPDFObject* fontDescriptor) {
190}
191
192bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
193 return fFontID == b.fFontID;
194}
195
196SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID)
197 : fFont(font),
198 fFontID(fontID) {
199}