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 <unistd.h> |
| 31 #include <sys/stat.h> |
| 32 |
| 33 #include "SkFontHost.h" |
| 34 #include "SkStream.h" |
| 35 #include "SkFontHost_fontconfig_impl.h" |
| 36 #include "SkFontHost_fontconfig_direct.h" |
| 37 #include "SkFontHost_fontconfig_ipc.h" |
| 38 |
| 39 static FontConfigInterface* global_fc_impl = NULL; |
| 40 |
| 41 void SkiaFontConfigUseDirectImplementation() { |
| 42 global_fc_impl = new FontConfigDirect; |
| 43 } |
| 44 |
| 45 void SkiaFontConfigUseIPCImplementation(int fd) { |
| 46 global_fc_impl = new FontConfigIPC(fd); |
| 47 } |
| 48 |
| 49 static SkMutex global_fc_map_lock; |
| 50 static std::map<uint32_t, SkTypeface *> global_fc_typefaces; |
| 51 |
| 52 // This is the maximum size of the font cache. |
| 53 static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB |
| 54 |
| 55 // UniqueIds are encoded as (fileid << 8) | style |
| 56 |
| 57 static unsigned UniqueIdToFileId(unsigned uniqueid) |
| 58 { |
| 59 return uniqueid >> 8; |
| 60 } |
| 61 |
| 62 static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid) |
| 63 { |
| 64 return static_cast<SkTypeface::Style>(uniqueid & 0xff); |
| 65 } |
| 66 |
| 67 static unsigned FileIdAndStyleToUniqueId(unsigned fileid, |
| 68 SkTypeface::Style style) |
| 69 { |
| 70 SkASSERT(style & 0xff == style); |
| 71 return (fileid << 8) | static_cast<int>(style); |
| 72 } |
| 73 |
| 74 class FontConfigTypeface : public SkTypeface { |
| 75 public: |
| 76 FontConfigTypeface(Style style, uint32_t id) |
| 77 : SkTypeface(style, id) |
| 78 { } |
| 79 }; |
| 80 |
| 81 // static |
| 82 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, |
| 83 const char familyName[], |
| 84 SkTypeface::Style style) |
| 85 { |
| 86 std::string resolved_family_name; |
| 87 |
| 88 if (familyFace) { |
| 89 // Given the fileid we can ask fontconfig for the familyname of the |
| 90 // font. |
| 91 const unsigned fileid = UniqueIdToFileId(familyFace->uniqueID()); |
| 92 if (!global_fc_impl->Match( |
| 93 &resolved_family_name, NULL, true /* fileid valid */, fileid, "", |
| 94 -1, -1)) { |
| 95 return NULL; |
| 96 } |
| 97 } else if (familyName) { |
| 98 resolved_family_name = familyName; |
| 99 } else { |
| 100 return NULL; |
| 101 } |
| 102 |
| 103 const bool bold = style & SkTypeface::kBold; |
| 104 const bool italic = style & SkTypeface::kItalic; |
| 105 unsigned fileid; |
| 106 if (!global_fc_impl->Match(NULL, &fileid, false, -1, /* no fileid */ |
| 107 resolved_family_name, bold, italic)) { |
| 108 return NULL; |
| 109 } |
| 110 |
| 111 const unsigned id = FileIdAndStyleToUniqueId(fileid, style); |
| 112 SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id)); |
| 113 |
| 114 { |
| 115 SkAutoMutexAcquire ac(global_fc_map_lock); |
| 116 global_fc_typefaces[id] = typeface; |
| 117 } |
| 118 |
| 119 return typeface; |
| 120 } |
| 121 |
| 122 // static |
| 123 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) |
| 124 { |
| 125 SkASSERT(!"SkFontHost::CreateTypefaceFromStream unimplemented"); |
| 126 return NULL; |
| 127 } |
| 128 |
| 129 // static |
| 130 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) |
| 131 { |
| 132 SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented"); |
| 133 return NULL; |
| 134 } |
| 135 |
| 136 // static |
| 137 bool SkFontHost::ValidFontID(SkFontID uniqueID) { |
| 138 SkAutoMutexAcquire ac(global_fc_map_lock); |
| 139 return global_fc_typefaces.find(uniqueID) != global_fc_typefaces.end(); |
| 140 } |
| 141 |
| 142 void SkFontHost::Serialize(const SkTypeface*, SkWStream*) { |
| 143 SkASSERT(!"SkFontHost::Serialize unimplemented"); |
| 144 } |
| 145 |
| 146 SkTypeface* SkFontHost::Deserialize(SkStream* stream) { |
| 147 SkASSERT(!"SkFontHost::Deserialize unimplemented"); |
| 148 return NULL; |
| 149 } |
| 150 |
| 151 // static |
| 152 uint32_t SkFontHost::NextLogicalFont(SkFontID fontID) { |
| 153 // We don't handle font fallback, WebKit does. |
| 154 return 0; |
| 155 } |
| 156 |
| 157 /////////////////////////////////////////////////////////////////////////////// |
| 158 |
| 159 class SkFileDescriptorStream : public SkStream { |
| 160 public: |
| 161 SkFileDescriptorStream(int fd) |
| 162 : fd_(fd) { |
| 163 } |
| 164 |
| 165 ~SkFileDescriptorStream() { |
| 166 close(fd_); |
| 167 } |
| 168 |
| 169 virtual bool rewind() { |
| 170 if (lseek(fd_, 0, SEEK_SET) == -1) |
| 171 return false; |
| 172 return true; |
| 173 } |
| 174 |
| 175 // SkStream implementation. |
| 176 virtual size_t read(void* buffer, size_t size) { |
| 177 if (!buffer && !size) { |
| 178 // This is request for the length of the stream. |
| 179 struct stat st; |
| 180 if (fstat(fd_, &st) == -1) |
| 181 return 0; |
| 182 return st.st_size; |
| 183 } |
| 184 |
| 185 if (!buffer) { |
| 186 // This is a request to skip bytes. |
| 187 const off_t current_position = lseek(fd_, 0, SEEK_CUR); |
| 188 if (current_position == -1) |
| 189 return 0; |
| 190 const off_t new_position = lseek(fd_, size, SEEK_CUR); |
| 191 if (new_position == -1) |
| 192 return 0; |
| 193 if (new_position < current_position) { |
| 194 lseek(fd_, current_position, SEEK_SET); |
| 195 return 0; |
| 196 } |
| 197 return new_position; |
| 198 } |
| 199 |
| 200 // This is a request to read bytes. |
| 201 return ::read(fd_, buffer, size); |
| 202 } |
| 203 |
| 204 private: |
| 205 const int fd_; |
| 206 }; |
| 207 |
| 208 /////////////////////////////////////////////////////////////////////////////// |
| 209 |
| 210 // static |
| 211 SkStream* SkFontHost::OpenStream(uint32_t id) |
| 212 { |
| 213 const unsigned fileid = UniqueIdToFileId(id); |
| 214 const int fd = global_fc_impl->Open(fileid); |
| 215 if (fd < 0) |
| 216 return NULL; |
| 217 |
| 218 return SkNEW_ARGS(SkFileDescriptorStream, (fd)); |
| 219 } |
| 220 |
| 221 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) |
| 222 { |
| 223 if (sizeAllocatedSoFar > kFontCacheMemoryBudget) |
| 224 return sizeAllocatedSoFar - kFontCacheMemoryBudget; |
| 225 else |
| 226 return 0; // nothing to do |
| 227 } |
OLD | NEW |