| OLD | NEW |
| (Empty) |
| 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 | |
| 10 ** | |
| 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. | |
| 16 */ | |
| 17 | |
| 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. | |
| 23 // | |
| 24 // [1] http://fontconfig.org | |
| 25 // ----------------------------------------------------------------------------- | |
| 26 | |
| 27 #include <map> | |
| 28 #include <string> | |
| 29 | |
| 30 #include <sys/mman.h> | |
| 31 #include <sys/stat.h> | |
| 32 #include <unistd.h> | |
| 33 | |
| 34 #include "base/compiler_specific.h" | |
| 35 #include "third_party/skia/src/core/SkFontDescriptor.h" | |
| 36 #include "SkFontHost.h" | |
| 37 #include "SkStream.h" | |
| 38 #include "SkFontHost_fontconfig_control.h" | |
| 39 #include "SkFontHost_fontconfig_impl.h" | |
| 40 #include "SkFontHost_fontconfig_direct.h" | |
| 41 | |
| 42 static FontConfigInterface* global_fc_impl = NULL; | |
| 43 | |
| 44 void SkiaFontConfigUseDirectImplementation() { | |
| 45 if (global_fc_impl) | |
| 46 delete global_fc_impl; | |
| 47 global_fc_impl = new FontConfigDirect; | |
| 48 } | |
| 49 | |
| 50 void SkiaFontConfigSetImplementation(FontConfigInterface* font_config) { | |
| 51 if (global_fc_impl) | |
| 52 delete global_fc_impl; | |
| 53 global_fc_impl = font_config; | |
| 54 } | |
| 55 | |
| 56 static FontConfigInterface* GetFcImpl() { | |
| 57 if (!global_fc_impl) | |
| 58 global_fc_impl = new FontConfigDirect; | |
| 59 return global_fc_impl; | |
| 60 } | |
| 61 | |
| 62 SK_DECLARE_STATIC_MUTEX(global_remote_font_map_lock); | |
| 63 static std::map<uint32_t, std::pair<uint8_t*, size_t> >* global_remote_fonts; | |
| 64 | |
| 65 // Initialize the map declared above. Note that its corresponding mutex must be | |
| 66 // locked before calling this function. | |
| 67 static void AllocateGlobalRemoteFontsMapOnce() { | |
| 68 if (!global_remote_fonts) { | |
| 69 global_remote_fonts = | |
| 70 new std::map<uint32_t, std::pair<uint8_t*, size_t> >(); | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 static unsigned global_next_remote_font_id; | |
| 75 | |
| 76 // This is the maximum size of the font cache. | |
| 77 static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB | |
| 78 | |
| 79 // UniqueIds are encoded as (filefaceid << 8) | style | |
| 80 // For system fonts, filefaceid = (fileid << 4) | face_index. | |
| 81 // For remote fonts, filefaceid = fileid. | |
| 82 | |
| 83 static unsigned UniqueIdToFileFaceId(unsigned uniqueid) | |
| 84 { | |
| 85 return uniqueid >> 8; | |
| 86 } | |
| 87 | |
| 88 static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid) | |
| 89 { | |
| 90 return static_cast<SkTypeface::Style>(uniqueid & 0xff); | |
| 91 } | |
| 92 | |
| 93 static unsigned FileFaceIdAndStyleToUniqueId(unsigned filefaceid, | |
| 94 SkTypeface::Style style) | |
| 95 { | |
| 96 SkASSERT((style & 0xff) == style); | |
| 97 return (filefaceid << 8) | static_cast<int>(style); | |
| 98 } | |
| 99 | |
| 100 static const unsigned kRemoteFontMask = 0x00800000u; | |
| 101 | |
| 102 static bool IsRemoteFont(unsigned filefaceid) | |
| 103 { | |
| 104 return filefaceid & kRemoteFontMask; | |
| 105 } | |
| 106 | |
| 107 class FontConfigTypeface : public SkTypeface { | |
| 108 public: | |
| 109 FontConfigTypeface(Style style, uint32_t id) | |
| 110 : SkTypeface(style, id) | |
| 111 { } | |
| 112 | |
| 113 virtual ~FontConfigTypeface() | |
| 114 { | |
| 115 const uint32_t id = uniqueID(); | |
| 116 if (IsRemoteFont(UniqueIdToFileFaceId(id))) { | |
| 117 SkAutoMutexAcquire ac(global_remote_font_map_lock); | |
| 118 AllocateGlobalRemoteFontsMapOnce(); | |
| 119 std::map<uint32_t, std::pair<uint8_t*, size_t> >::iterator iter | |
| 120 = global_remote_fonts->find(id); | |
| 121 if (iter != global_remote_fonts->end()) { | |
| 122 sk_free(iter->second.first); // remove the font on memory. | |
| 123 global_remote_fonts->erase(iter); | |
| 124 } | |
| 125 } | |
| 126 } | |
| 127 }; | |
| 128 | |
| 129 // static | |
| 130 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, | |
| 131 const char familyName[], | |
| 132 SkTypeface::Style style) | |
| 133 { | |
| 134 std::string resolved_family_name; | |
| 135 | |
| 136 if (familyFace) { | |
| 137 // Given the fileid we can ask fontconfig for the familyname of the | |
| 138 // font. | |
| 139 const unsigned filefaceid = UniqueIdToFileFaceId(familyFace->uniqueID())
; | |
| 140 if (!GetFcImpl()->Match(&resolved_family_name, NULL, | |
| 141 true /* filefaceid valid */, filefaceid, "", | |
| 142 NULL, 0, NULL, NULL)) { | |
| 143 return NULL; | |
| 144 } | |
| 145 } else if (familyName) { | |
| 146 resolved_family_name = familyName; | |
| 147 } | |
| 148 | |
| 149 bool bold = style & SkTypeface::kBold; | |
| 150 bool italic = style & SkTypeface::kItalic; | |
| 151 unsigned filefaceid; | |
| 152 if (!GetFcImpl()->Match(NULL, &filefaceid, | |
| 153 false, -1, /* no filefaceid */ | |
| 154 resolved_family_name, NULL, 0, | |
| 155 &bold, &italic)) { | |
| 156 return NULL; | |
| 157 } | |
| 158 const SkTypeface::Style resulting_style = static_cast<SkTypeface::Style>( | |
| 159 (bold ? SkTypeface::kBold : 0) | | |
| 160 (italic ? SkTypeface::kItalic : 0)); | |
| 161 | |
| 162 const unsigned id = FileFaceIdAndStyleToUniqueId(filefaceid, | |
| 163 resulting_style); | |
| 164 SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (resulting_style, id))
; | |
| 165 return typeface; | |
| 166 } | |
| 167 | |
| 168 // static | |
| 169 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) | |
| 170 { | |
| 171 if (!stream) | |
| 172 return NULL; | |
| 173 | |
| 174 const size_t length = stream->read(0, 0); | |
| 175 if (!length) | |
| 176 return NULL; | |
| 177 if (length >= 1024 * 1024 * 1024) | |
| 178 return NULL; // don't accept too large fonts (>= 1GB) for safety. | |
| 179 | |
| 180 uint8_t* font = (uint8_t*)sk_malloc_throw(length); | |
| 181 if (stream->read(font, length) != length) { | |
| 182 sk_free(font); | |
| 183 return NULL; | |
| 184 } | |
| 185 | |
| 186 SkTypeface::Style style = static_cast<SkTypeface::Style>(0); | |
| 187 unsigned id = 0; | |
| 188 { | |
| 189 SkAutoMutexAcquire ac(global_remote_font_map_lock); | |
| 190 AllocateGlobalRemoteFontsMapOnce(); | |
| 191 id = FileFaceIdAndStyleToUniqueId( | |
| 192 global_next_remote_font_id | kRemoteFontMask, style); | |
| 193 | |
| 194 if (++global_next_remote_font_id >= kRemoteFontMask) | |
| 195 global_next_remote_font_id = 0; | |
| 196 | |
| 197 if (!global_remote_fonts->insert( | |
| 198 std::make_pair(id, std::make_pair(font, length))).second) { | |
| 199 sk_free(font); | |
| 200 return NULL; | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id)); | |
| 205 return typeface; | |
| 206 } | |
| 207 | |
| 208 // static | |
| 209 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) | |
| 210 { | |
| 211 SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented"); | |
| 212 return NULL; | |
| 213 } | |
| 214 | |
| 215 uint32_t SkFontHost::NextLogicalFont(SkFontID curr, SkFontID orig) { | |
| 216 // We don't handle font fallback, WebKit does. | |
| 217 return 0; | |
| 218 } | |
| 219 | |
| 220 /////////////////////////////////////////////////////////////////////////////// | |
| 221 | |
| 222 // Serialize, Deserialize need to be compatible across platforms, hence the use | |
| 223 // of SkFontDescriptor. | |
| 224 | |
| 225 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { | |
| 226 SkFontDescriptor desc(face->style()); | |
| 227 | |
| 228 std::string resolved_family_name; | |
| 229 | |
| 230 const unsigned filefaceid = UniqueIdToFileFaceId(face->uniqueID()); | |
| 231 if (GetFcImpl()->Match(&resolved_family_name, NULL, | |
| 232 true /* filefaceid valid */, filefaceid, "", NULL, 0, NULL, NULL)) | |
| 233 desc.setFamilyName(resolved_family_name.c_str()); | |
| 234 else | |
| 235 desc.setFamilyName("sans-serif"); | |
| 236 | |
| 237 // would also like other names (see SkFontDescriptor.h) | |
| 238 | |
| 239 desc.serialize(stream); | |
| 240 | |
| 241 // by convention, we also write out the actual sfnt data, preceeded by | |
| 242 // a packed-length. For now we skip that, so we just write the zero. | |
| 243 stream->writePackedUInt(0); | |
| 244 } | |
| 245 | |
| 246 SkTypeface* SkFontHost::Deserialize(SkStream* stream) { | |
| 247 SkFontDescriptor desc(stream); | |
| 248 | |
| 249 // by convention, Serialize will have also written the actual sfnt data. | |
| 250 // for now, we just want to skip it. | |
| 251 size_t size = stream->readPackedUInt(); | |
| 252 stream->skip(size); | |
| 253 | |
| 254 return SkFontHost::CreateTypeface(NULL, desc.getFamilyName(), | |
| 255 desc.getStyle()); | |
| 256 } | |
| 257 | |
| 258 /////////////////////////////////////////////////////////////////////////////// | |
| 259 | |
| 260 class SkFileDescriptorStream : public SkStream { | |
| 261 public: | |
| 262 SkFileDescriptorStream(int fd) { | |
| 263 memory_ = NULL; | |
| 264 offset_ = 0; | |
| 265 | |
| 266 // this ensures that if we fail in the constructor, we will safely | |
| 267 // ignore all subsequent calls to read() because we will always trim | |
| 268 // the requested size down to 0 | |
| 269 length_ = 0; | |
| 270 | |
| 271 struct stat st; | |
| 272 if (fstat(fd, &st)) | |
| 273 return; | |
| 274 | |
| 275 void* memory = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); | |
| 276 close(fd); | |
| 277 if (memory == MAP_FAILED) | |
| 278 return; | |
| 279 | |
| 280 memory_ = reinterpret_cast<uint8_t*>(memory); | |
| 281 length_ = st.st_size; | |
| 282 } | |
| 283 | |
| 284 virtual ~SkFileDescriptorStream() { | |
| 285 munmap(const_cast<uint8_t*>(memory_), length_); | |
| 286 } | |
| 287 | |
| 288 virtual bool rewind() OVERRIDE { | |
| 289 offset_ = 0; | |
| 290 return true; | |
| 291 } | |
| 292 | |
| 293 // SkStream implementation. | |
| 294 virtual size_t read(void* buffer, size_t size) OVERRIDE { | |
| 295 if (!buffer && !size) { | |
| 296 // This is request for the length of the stream. | |
| 297 return length_; | |
| 298 } | |
| 299 | |
| 300 size_t remaining = length_ - offset_; | |
| 301 if (size > remaining) | |
| 302 size = remaining; | |
| 303 if (buffer) | |
| 304 memcpy(buffer, memory_ + offset_, size); | |
| 305 | |
| 306 offset_ += size; | |
| 307 return size; | |
| 308 } | |
| 309 | |
| 310 virtual const void* getMemoryBase() OVERRIDE { | |
| 311 return memory_; | |
| 312 } | |
| 313 | |
| 314 private: | |
| 315 const uint8_t* memory_; | |
| 316 size_t offset_, length_; | |
| 317 }; | |
| 318 | |
| 319 /////////////////////////////////////////////////////////////////////////////// | |
| 320 | |
| 321 // static | |
| 322 SkStream* SkFontHost::OpenStream(uint32_t id) | |
| 323 { | |
| 324 const unsigned filefaceid = UniqueIdToFileFaceId(id); | |
| 325 | |
| 326 if (IsRemoteFont(filefaceid)) { | |
| 327 // remote font | |
| 328 SkAutoMutexAcquire ac(global_remote_font_map_lock); | |
| 329 AllocateGlobalRemoteFontsMapOnce(); | |
| 330 std::map<uint32_t, std::pair<uint8_t*, size_t> >::const_iterator iter | |
| 331 = global_remote_fonts->find(id); | |
| 332 if (iter == global_remote_fonts->end()) | |
| 333 return NULL; | |
| 334 return SkNEW_ARGS( | |
| 335 SkMemoryStream, (iter->second.first, iter->second.second)); | |
| 336 } | |
| 337 | |
| 338 // system font | |
| 339 const int fd = GetFcImpl()->Open(filefaceid); | |
| 340 if (fd < 0) | |
| 341 return NULL; | |
| 342 | |
| 343 return SkNEW_ARGS(SkFileDescriptorStream, (fd)); | |
| 344 } | |
| 345 | |
| 346 // static | |
| 347 size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, | |
| 348 int32_t* index) { | |
| 349 const unsigned filefaceid = UniqueIdToFileFaceId(fontID); | |
| 350 | |
| 351 if (IsRemoteFont(filefaceid)) | |
| 352 return 0; | |
| 353 | |
| 354 if (index) { | |
| 355 *index = filefaceid & 0xfu; | |
| 356 // 1 is a bogus return value. | |
| 357 // We had better change the signature of this function in Skia | |
| 358 // to return bool to indicate success/failure and have another | |
| 359 // out param for fileName length. | |
| 360 if (!path) | |
| 361 return 1; | |
| 362 } | |
| 363 | |
| 364 if (path) | |
| 365 SkASSERT(!"SkFontHost::GetFileName does not support the font path " | |
| 366 "retrieval."); | |
| 367 | |
| 368 return 0; | |
| 369 } | |
| OLD | NEW |