1 /* libs/graphics/ports/SkFontHost_fontconfig.cpp
3 ** Copyright 2008, Google Inc.
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
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 // -----------------------------------------------------------------------------
34 #include "SkFontHost.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() {
44 delete global_fc_impl
;
45 global_fc_impl
= new FontConfigDirect
;
48 void SkiaFontConfigSetImplementation(FontConfigInterface
* font_config
) {
50 delete global_fc_impl
;
51 global_fc_impl
= font_config
;
54 static FontConfigInterface
* GetFcImpl() {
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
)
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
{
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
);
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
;
128 // Given the fileid we can ask fontconfig for the familyname of the
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
)) {
136 } else if (familyName
) {
137 resolved_family_name
= familyName
;
140 bool bold
= style
& SkTypeface::kBold
;
141 bool italic
= style
& SkTypeface::kItalic
;
143 if (!GetFcImpl()->Match(NULL
, &filefaceid
,
144 false, -1, /* no filefaceid */
145 resolved_family_name
, data
, bytelength
,
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
,
155 SkTypeface
* typeface
= SkNEW_ARGS(FontConfigTypeface
, (resulting_style
, id
));
158 SkAutoMutexAcquire
ac(global_fc_map_lock
);
159 global_fc_typefaces
[id
] = typeface
;
166 SkTypeface
* SkFontHost::CreateTypefaceFromStream(SkStream
* stream
)
171 const size_t length
= stream
->read(0, 0);
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
) {
183 SkTypeface::Style style
= static_cast<SkTypeface::Style
>(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
) {
200 SkTypeface
* typeface
= SkNEW_ARGS(FontConfigTypeface
, (style
, id
));
205 SkTypeface
* SkFontHost::CreateTypefaceFromFile(const char path
[])
207 SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
211 void SkFontHost::Serialize(const SkTypeface
*, SkWStream
*) {
212 SkASSERT(!"SkFontHost::Serialize unimplemented");
215 SkTypeface
* SkFontHost::Deserialize(SkStream
* stream
) {
216 SkASSERT(!"SkFontHost::Deserialize unimplemented");
221 uint32_t SkFontHost::NextLogicalFont(SkFontID curr
, SkFontID orig
) {
222 // We don't handle font fallback, WebKit does.
226 ///////////////////////////////////////////////////////////////////////////////
228 class SkFileDescriptorStream
: public SkStream
{
230 SkFileDescriptorStream(int fd
) {
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
243 void* memory
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
245 if (memory
== MAP_FAILED
)
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() {
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.
268 size_t remaining
= length_
- offset_
;
269 if (size
> remaining
)
272 memcpy(buffer
, memory_
+ offset_
, size
);
278 virtual const void* getMemoryBase() {
283 const uint8_t* memory_
;
284 size_t offset_
, length_
;
287 ///////////////////////////////////////////////////////////////////////////////
290 SkStream
* SkFontHost::OpenStream(uint32_t id
)
292 const unsigned filefaceid
= UniqueIdToFileFaceId(id
);
294 if (IsRemoteFont(filefaceid
)) {
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())
302 SkMemoryStream
, (iter
->second
.first
, iter
->second
.second
));
306 const int fd
= GetFcImpl()->Open(filefaceid
);
310 return SkNEW_ARGS(SkFileDescriptorStream
, (fd
));
314 size_t SkFontHost::GetFileName(SkFontID fontID
, char path
[], size_t length
,
316 const unsigned filefaceid
= UniqueIdToFileFaceId(fontID
);
318 if (IsRemoteFont(filefaceid
))
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.
332 SkASSERT(!"SkFontHost::GetFileName does not support the font path "