chromeos: bluetooth: add BluetoothInputClient
[chromium-blink-merge.git] / skia / ext / SkFontHost_fontconfig.cpp
blobef73553e7c3d79f926905b808678e7e72b737892
1 /* libs/graphics/ports/SkFontHost_fontconfig.cpp
2 **
3 ** Copyright 2008, Google Inc.
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
18 // -----------------------------------------------------------------------------
19 // This file provides implementations of the font resolution members of
20 // SkFontHost by using the fontconfig[1] library. Fontconfig is usually found
21 // on Linux systems and handles configuration, parsing and caching issues
22 // involved with enumerating and matching fonts.
24 // [1] http://fontconfig.org
25 // -----------------------------------------------------------------------------
27 #include <map>
28 #include <string>
30 #include <sys/mman.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
34 #include "SkFontHost.h"
35 #include "SkStream.h"
36 #include "SkFontHost_fontconfig_control.h"
37 #include "SkFontHost_fontconfig_impl.h"
38 #include "SkFontHost_fontconfig_direct.h"
40 static FontConfigInterface* global_fc_impl = NULL;
42 void SkiaFontConfigUseDirectImplementation() {
43 if (global_fc_impl)
44 delete global_fc_impl;
45 global_fc_impl = new FontConfigDirect;
48 void SkiaFontConfigSetImplementation(FontConfigInterface* font_config) {
49 if (global_fc_impl)
50 delete global_fc_impl;
51 global_fc_impl = font_config;
54 static FontConfigInterface* GetFcImpl() {
55 if (!global_fc_impl)
56 global_fc_impl = new FontConfigDirect;
57 return global_fc_impl;
60 static SkMutex global_fc_map_lock;
61 static std::map<uint32_t, SkTypeface *> global_fc_typefaces;
63 static SkMutex global_remote_font_map_lock;
64 static std::map<uint32_t, std::pair<uint8_t*, size_t> > global_remote_fonts;
65 static unsigned global_next_remote_font_id;
67 // This is the maximum size of the font cache.
68 static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB
70 // UniqueIds are encoded as (filefaceid << 8) | style
71 // For system fonts, filefaceid = (fileid << 4) | face_index.
72 // For remote fonts, filefaceid = fileid.
74 static unsigned UniqueIdToFileFaceId(unsigned uniqueid)
76 return uniqueid >> 8;
79 static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid)
81 return static_cast<SkTypeface::Style>(uniqueid & 0xff);
84 static unsigned FileFaceIdAndStyleToUniqueId(unsigned filefaceid,
85 SkTypeface::Style style)
87 SkASSERT((style & 0xff) == style);
88 return (filefaceid << 8) | static_cast<int>(style);
91 static const unsigned kRemoteFontMask = 0x00800000u;
93 static bool IsRemoteFont(unsigned filefaceid)
95 return filefaceid & kRemoteFontMask;
98 class FontConfigTypeface : public SkTypeface {
99 public:
100 FontConfigTypeface(Style style, uint32_t id)
101 : SkTypeface(style, id)
104 ~FontConfigTypeface()
106 const uint32_t id = uniqueID();
107 if (IsRemoteFont(UniqueIdToFileFaceId(id))) {
108 SkAutoMutexAcquire ac(global_remote_font_map_lock);
109 std::map<uint32_t, std::pair<uint8_t*, size_t> >::iterator iter
110 = global_remote_fonts.find(id);
111 if (iter != global_remote_fonts.end()) {
112 sk_free(iter->second.first); // remove the font on memory.
113 global_remote_fonts.erase(iter);
119 // static
120 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
121 const char familyName[],
122 const void* data, size_t bytelength,
123 SkTypeface::Style style)
125 std::string resolved_family_name;
127 if (familyFace) {
128 // Given the fileid we can ask fontconfig for the familyname of the
129 // font.
130 const unsigned filefaceid = UniqueIdToFileFaceId(familyFace->uniqueID());
131 if (!GetFcImpl()->Match(&resolved_family_name, NULL,
132 true /* filefaceid valid */, filefaceid, "",
133 NULL, 0, NULL, NULL)) {
134 return NULL;
136 } else if (familyName) {
137 resolved_family_name = familyName;
140 bool bold = style & SkTypeface::kBold;
141 bool italic = style & SkTypeface::kItalic;
142 unsigned filefaceid;
143 if (!GetFcImpl()->Match(NULL, &filefaceid,
144 false, -1, /* no filefaceid */
145 resolved_family_name, data, bytelength,
146 &bold, &italic)) {
147 return NULL;
149 const SkTypeface::Style resulting_style = static_cast<SkTypeface::Style>(
150 (bold ? SkTypeface::kBold : 0) |
151 (italic ? SkTypeface::kItalic : 0));
153 const unsigned id = FileFaceIdAndStyleToUniqueId(filefaceid,
154 resulting_style);
155 SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (resulting_style, id));
158 SkAutoMutexAcquire ac(global_fc_map_lock);
159 global_fc_typefaces[id] = typeface;
162 return typeface;
165 // static
166 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
168 if (!stream)
169 return NULL;
171 const size_t length = stream->read(0, 0);
172 if (!length)
173 return NULL;
174 if (length >= 1024 * 1024 * 1024)
175 return NULL; // don't accept too large fonts (>= 1GB) for safety.
177 uint8_t* font = (uint8_t*)sk_malloc_throw(length);
178 if (stream->read(font, length) != length) {
179 sk_free(font);
180 return NULL;
183 SkTypeface::Style style = static_cast<SkTypeface::Style>(0);
184 unsigned id = 0;
186 SkAutoMutexAcquire ac(global_remote_font_map_lock);
187 id = FileFaceIdAndStyleToUniqueId(
188 global_next_remote_font_id | kRemoteFontMask, style);
190 if (++global_next_remote_font_id >= kRemoteFontMask)
191 global_next_remote_font_id = 0;
193 if (!global_remote_fonts.insert(
194 std::make_pair(id, std::make_pair(font, length))).second) {
195 sk_free(font);
196 return NULL;
200 SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
201 return typeface;
204 // static
205 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
207 SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
208 return NULL;
211 void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
212 SkASSERT(!"SkFontHost::Serialize unimplemented");
215 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
216 SkASSERT(!"SkFontHost::Deserialize unimplemented");
217 return NULL;
220 // static
221 uint32_t SkFontHost::NextLogicalFont(SkFontID curr, SkFontID orig) {
222 // We don't handle font fallback, WebKit does.
223 return 0;
226 ///////////////////////////////////////////////////////////////////////////////
228 class SkFileDescriptorStream : public SkStream {
229 public:
230 SkFileDescriptorStream(int fd) {
231 memory_ = NULL;
232 offset_ = 0;
234 // this ensures that if we fail in the constructor, we will safely
235 // ignore all subsequent calls to read() because we will always trim
236 // the requested size down to 0
237 length_ = 0;
239 struct stat st;
240 if (fstat(fd, &st))
241 return;
243 void* memory = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
244 close(fd);
245 if (memory == MAP_FAILED)
246 return;
248 memory_ = reinterpret_cast<uint8_t*>(memory);
249 length_ = st.st_size;
252 ~SkFileDescriptorStream() {
253 munmap(const_cast<uint8_t*>(memory_), length_);
256 virtual bool rewind() {
257 offset_ = 0;
258 return true;
261 // SkStream implementation.
262 virtual size_t read(void* buffer, size_t size) {
263 if (!buffer && !size) {
264 // This is request for the length of the stream.
265 return length_;
268 size_t remaining = length_ - offset_;
269 if (size > remaining)
270 size = remaining;
271 if (buffer)
272 memcpy(buffer, memory_ + offset_, size);
274 offset_ += size;
275 return size;
278 virtual const void* getMemoryBase() {
279 return memory_;
282 private:
283 const uint8_t* memory_;
284 size_t offset_, length_;
287 ///////////////////////////////////////////////////////////////////////////////
289 // static
290 SkStream* SkFontHost::OpenStream(uint32_t id)
292 const unsigned filefaceid = UniqueIdToFileFaceId(id);
294 if (IsRemoteFont(filefaceid)) {
295 // remote font
296 SkAutoMutexAcquire ac(global_remote_font_map_lock);
297 std::map<uint32_t, std::pair<uint8_t*, size_t> >::const_iterator iter
298 = global_remote_fonts.find(id);
299 if (iter == global_remote_fonts.end())
300 return NULL;
301 return SkNEW_ARGS(
302 SkMemoryStream, (iter->second.first, iter->second.second));
305 // system font
306 const int fd = GetFcImpl()->Open(filefaceid);
307 if (fd < 0)
308 return NULL;
310 return SkNEW_ARGS(SkFileDescriptorStream, (fd));
313 // static
314 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
315 int32_t* index) {
316 const unsigned filefaceid = UniqueIdToFileFaceId(fontID);
318 if (IsRemoteFont(filefaceid))
319 return 0;
321 if (index) {
322 *index = filefaceid & 0xfu;
323 // 1 is a bogus return value.
324 // We had better change the signature of this function in Skia
325 // to return bool to indicate success/failure and have another
326 // out param for fileName length.
327 if (!path)
328 return 1;
331 if (path)
332 SkASSERT(!"SkFontHost::GetFileName does not support the font path "
333 "retrieval.");
335 return 0;