| OLD | NEW |
| (Empty) |
| 1 /* libs/graphics/ports/SkFontHost_android.cpp | |
| 2 ** | |
| 3 ** Copyright 2006, The Android Open Source Project | |
| 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 #include "SkFontHost.h" | |
| 19 #include "SkDescriptor.h" | |
| 20 #include "SkString.h" | |
| 21 #include "SkStream.h" | |
| 22 #include <stdio.h> | |
| 23 | |
| 24 /* define this if we can use mmap() to access fonts from the filesystem */ | |
| 25 #define SK_CAN_USE_MMAP | |
| 26 | |
| 27 #ifndef SK_FONTPATH | |
| 28 #define SK_FONTPATH "the complete path for a font file" | |
| 29 #endif | |
| 30 | |
| 31 struct FontFaceRec { | |
| 32 const char* fFileName; | |
| 33 uint8_t fFamilyIndex; | |
| 34 SkBool8 fBold; | |
| 35 SkBool8 fItalic; | |
| 36 | |
| 37 static const FontFaceRec& FindFace(const FontFaceRec rec[], int count, int i
sBold, int isItalic); | |
| 38 }; | |
| 39 | |
| 40 struct FontFamilyRec { | |
| 41 const FontFaceRec* fFaces; | |
| 42 int fFaceCount; | |
| 43 }; | |
| 44 | |
| 45 const FontFaceRec& FontFaceRec::FindFace(const FontFaceRec rec[], int count, int
isBold, int isItalic) | |
| 46 { | |
| 47 SkASSERT(count > 0); | |
| 48 | |
| 49 int i; | |
| 50 | |
| 51 // look for an exact match | |
| 52 for (i = 0; i < count; i++) { | |
| 53 if (rec[i].fBold == isBold && rec[i].fItalic == isItalic) | |
| 54 return rec[i]; | |
| 55 } | |
| 56 // look for a match in the bold field | |
| 57 for (i = 0; i < count; i++) { | |
| 58 if (rec[i].fBold == isBold) | |
| 59 return rec[i]; | |
| 60 } | |
| 61 // look for a normal/regular face | |
| 62 for (i = 0; i < count; i++) { | |
| 63 if (!rec[i].fBold && !rec[i].fItalic) | |
| 64 return rec[i]; | |
| 65 } | |
| 66 // give up | |
| 67 return rec[0]; | |
| 68 } | |
| 69 | |
| 70 enum { | |
| 71 DEFAULT_FAMILY_INDEX, | |
| 72 | |
| 73 FAMILY_INDEX_COUNT | |
| 74 }; | |
| 75 | |
| 76 static const FontFaceRec gDefaultFaces[] = { | |
| 77 { SK_FONTPATH, DEFAULT_FAMILY_INDEX, 0, 0 } | |
| 78 }; | |
| 79 | |
| 80 // This table must be in the same order as the ..._FAMILY_INDEX enum specifies | |
| 81 static const FontFamilyRec gFamilies[] = { | |
| 82 { gDefaultFaces, SK_ARRAY_COUNT(gDefaultFaces) } | |
| 83 }; | |
| 84 | |
| 85 #define DEFAULT_FAMILY_INDEX DEFAULT_FAMILY_INDEX | |
| 86 #define DEFAULT_FAMILY_FACE_INDEX 0 | |
| 87 | |
| 88 ////////////////////////////////////////////////////////////////////////////////
//////// | |
| 89 | |
| 90 /* map common "web" font names to our font list */ | |
| 91 | |
| 92 struct FontFamilyMatchRec { | |
| 93 const char* fLCName; | |
| 94 int fFamilyIndex; | |
| 95 }; | |
| 96 | |
| 97 /* This is a table of synonyms for collapsing font names | |
| 98 down to their pseudo-equivalents (i.e. in terms of fonts | |
| 99 we actually have.) | |
| 100 Keep this sorted by the first field so we can do a binary search. | |
| 101 If this gets big, we could switch to a hash... | |
| 102 */ | |
| 103 static const FontFamilyMatchRec gMatches[] = { | |
| 104 #if 0 | |
| 105 { "Ahem", Ahem_FAMILY_INDEX }, | |
| 106 { "arial", SANS_FAMILY_INDEX }, | |
| 107 { "courier", MONO_FAMILY_INDEX }, | |
| 108 { "courier new", MONO_FAMILY_INDEX }, | |
| 109 { "cursive", SERIF_FAMILY_INDEX }, | |
| 110 { "fantasy", SERIF_FAMILY_INDEX }, | |
| 111 { "georgia", SERIF_FAMILY_INDEX }, | |
| 112 { "goudy", SERIF_FAMILY_INDEX }, | |
| 113 { "helvetica", SANS_FAMILY_INDEX }, | |
| 114 { "palatino", SERIF_FAMILY_INDEX }, | |
| 115 { "tahoma", SANS_FAMILY_INDEX }, | |
| 116 { "sans-serif", SANS_FAMILY_INDEX }, | |
| 117 { "serif", SERIF_FAMILY_INDEX }, | |
| 118 { "times", SERIF_FAMILY_INDEX }, | |
| 119 { "times new roman", SERIF_FAMILY_INDEX }, | |
| 120 { "verdana", SANS_FAMILY_INDEX } | |
| 121 #endif | |
| 122 }; | |
| 123 | |
| 124 ////////////////////////////////////////////////////////////////////////////////
//////// | |
| 125 | |
| 126 #include "SkTSearch.h" | |
| 127 | |
| 128 static bool contains_only_ascii(const char s[]) | |
| 129 { | |
| 130 for (;;) | |
| 131 { | |
| 132 int c = *s++; | |
| 133 if (c == 0) | |
| 134 break; | |
| 135 if ((c >> 7) != 0) | |
| 136 return false; | |
| 137 } | |
| 138 return true; | |
| 139 } | |
| 140 | |
| 141 #define TRACE_FONT_NAME(code) | |
| 142 //#define TRACE_FONT_NAME(code) code | |
| 143 | |
| 144 const FontFamilyRec* find_family_rec(const char target[]) | |
| 145 { | |
| 146 int index; | |
| 147 | |
| 148 // If we're asked for a font name that contains non-ascii, | |
| 149 // 1) SkStrLCSearch can't handle it | |
| 150 // 2) All of our fonts are have ascii names, so... | |
| 151 | |
| 152 TRACE_FONT_NAME(printf("----------------- font request <%s>", target);) | |
| 153 | |
| 154 if (contains_only_ascii(target)) | |
| 155 { | |
| 156 // Search for the font by matching the entire name | |
| 157 index = SkStrLCSearch(&gMatches[0].fLCName, SK_ARRAY_COUNT(gMatches), ta
rget, sizeof(gMatches[0])); | |
| 158 if (index >= 0) | |
| 159 { | |
| 160 TRACE_FONT_NAME(printf(" found %d\n", index);) | |
| 161 return &gFamilies[gMatches[index].fFamilyIndex]; | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 // Sniff for key words... | |
| 166 | |
| 167 #if 0 | |
| 168 if (strstr(target, "sans") || strstr(target, "Sans")) | |
| 169 { | |
| 170 TRACE_FONT_NAME(printf(" found sans\n");) | |
| 171 return &gFamilies[SANS_FAMILY_INDEX]; | |
| 172 } | |
| 173 if (strstr(target, "serif") || strstr(target, "Serif")) | |
| 174 { | |
| 175 TRACE_FONT_NAME(printf(" found serif\n");) | |
| 176 return &gFamilies[SERIF_FAMILY_INDEX]; | |
| 177 } | |
| 178 if (strstr(target, "mono") || strstr(target, "Mono")) | |
| 179 { | |
| 180 TRACE_FONT_NAME(printf(" found mono\n");) | |
| 181 return &gFamilies[MONO_FAMILY_INDEX]; | |
| 182 } | |
| 183 #endif | |
| 184 | |
| 185 TRACE_FONT_NAME(printf(" use default\n");) | |
| 186 // we give up, just give them the default font | |
| 187 return &gFamilies[DEFAULT_FAMILY_INDEX]; | |
| 188 } | |
| 189 | |
| 190 ////////////////////////////////////////////////////////////////////////////////
/////////////// | |
| 191 | |
| 192 static const FontFaceRec* get_default_face() | |
| 193 { | |
| 194 return &gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX]; | |
| 195 } | |
| 196 | |
| 197 class FontFaceRec_Typeface : public SkTypeface { | |
| 198 public: | |
| 199 FontFaceRec_Typeface(const FontFaceRec& face) : fFace(face) | |
| 200 { | |
| 201 int style = 0; | |
| 202 if (face.fBold) | |
| 203 style |= SkTypeface::kBold; | |
| 204 if (face.fItalic) | |
| 205 style |= SkTypeface::kItalic; | |
| 206 this->setStyle((SkTypeface::Style)style); | |
| 207 } | |
| 208 | |
| 209 // This global const reference completely identifies the face | |
| 210 const FontFaceRec& fFace; | |
| 211 }; | |
| 212 | |
| 213 static const FontFaceRec* get_typeface_rec(const SkTypeface* face) | |
| 214 { | |
| 215 const FontFaceRec_Typeface* f = (FontFaceRec_Typeface*)face; | |
| 216 return f ? &f->fFace : get_default_face(); | |
| 217 } | |
| 218 | |
| 219 static uint32_t ptr2uint32(const void* p) | |
| 220 { | |
| 221 // cast so we avoid warnings on 64bit machines that a ptr difference | |
| 222 // which might be 64bits is being trucated from 64 to 32 | |
| 223 return (uint32_t)((char*)p - (char*)0); | |
| 224 } | |
| 225 | |
| 226 uint32_t SkFontHost::TypefaceHash(const SkTypeface* face) | |
| 227 { | |
| 228 // just use our address as the hash value | |
| 229 return ptr2uint32(get_typeface_rec(face)); | |
| 230 } | |
| 231 | |
| 232 bool SkFontHost::TypefaceEqual(const SkTypeface* facea, const SkTypeface* faceb) | |
| 233 { | |
| 234 return get_typeface_rec(facea) == get_typeface_rec(faceb); | |
| 235 } | |
| 236 | |
| 237 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, const char
familyName[], SkTypeface::Style style) | |
| 238 { | |
| 239 const FontFamilyRec* family; | |
| 240 | |
| 241 if (familyFace) | |
| 242 family = &gFamilies[((FontFaceRec_Typeface*)familyFace)->fFace.fFamilyIn
dex]; | |
| 243 else if (familyName) | |
| 244 family = find_family_rec(familyName); | |
| 245 else | |
| 246 family = &gFamilies[DEFAULT_FAMILY_INDEX]; | |
| 247 | |
| 248 const FontFaceRec& face = FontFaceRec::FindFace(family->fFaces, family->fFac
eCount, | |
| 249 (style & SkTypeface::kBold)
!= 0, | |
| 250 (style & SkTypeface::kItalic
) != 0); | |
| 251 | |
| 252 // if we're returning our input parameter, no need to create a new instance | |
| 253 if (familyFace != NULL && &((FontFaceRec_Typeface*)familyFace)->fFace == &fa
ce) | |
| 254 { | |
| 255 familyFace->ref(); | |
| 256 return (SkTypeface*)familyFace; | |
| 257 } | |
| 258 return SkNEW_ARGS(FontFaceRec_Typeface, (face)); | |
| 259 } | |
| 260 | |
| 261 uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer) | |
| 262 { | |
| 263 const FontFaceRec* face; | |
| 264 | |
| 265 if (tface) | |
| 266 face = &((const FontFaceRec_Typeface*)tface)->fFace; | |
| 267 else | |
| 268 face = get_default_face(); | |
| 269 | |
| 270 size_t size = sizeof(face); | |
| 271 if (buffer) | |
| 272 memcpy(buffer, &face, size); | |
| 273 return size; | |
| 274 } | |
| 275 | |
| 276 void SkFontHost::GetDescriptorKeyString(const SkDescriptor* desc, SkString* key) | |
| 277 { | |
| 278 key->set(SK_FONTPATH); | |
| 279 } | |
| 280 | |
| 281 #ifdef SK_CAN_USE_MMAP | |
| 282 #include <unistd.h> | |
| 283 #include <sys/mman.h> | |
| 284 #include <fcntl.h> | |
| 285 #include <errno.h> | |
| 286 | |
| 287 class SkMMAPStream : public SkMemoryStream { | |
| 288 public: | |
| 289 SkMMAPStream(const char filename[]); | |
| 290 virtual ~SkMMAPStream(); | |
| 291 | |
| 292 virtual void setMemory(const void* data, size_t length); | |
| 293 private: | |
| 294 int fFildes; | |
| 295 void* fAddr; | |
| 296 size_t fSize; | |
| 297 | |
| 298 void closeMMap(); | |
| 299 | |
| 300 typedef SkMemoryStream INHERITED; | |
| 301 }; | |
| 302 | |
| 303 SkMMAPStream::SkMMAPStream(const char filename[]) | |
| 304 { | |
| 305 fFildes = -1; // initialize to failure case | |
| 306 | |
| 307 int fildes = open(filename, O_RDONLY); | |
| 308 if (fildes < 0) | |
| 309 { | |
| 310 SkDEBUGF(("---- failed to open(%s) for mmap stream error=%d\n", filename
, errno)); | |
| 311 return; | |
| 312 } | |
| 313 | |
| 314 off_t size = lseek(fildes, 0, SEEK_END); // find the file size | |
| 315 if (size == -1) | |
| 316 { | |
| 317 SkDEBUGF(("---- failed to lseek(%s) for mmap stream error=%d\n", filenam
e, errno)); | |
| 318 close(fildes); | |
| 319 return; | |
| 320 } | |
| 321 (void)lseek(fildes, 0, SEEK_SET); // restore file offset to beginning | |
| 322 | |
| 323 void* addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fildes, 0); | |
| 324 if (MAP_FAILED == addr) | |
| 325 { | |
| 326 SkDEBUGF(("---- failed to mmap(%s) for mmap stream error=%d\n", filename
, errno)); | |
| 327 close(fildes); | |
| 328 return; | |
| 329 } | |
| 330 | |
| 331 this->INHERITED::setMemory(addr, size); | |
| 332 | |
| 333 fFildes = fildes; | |
| 334 fAddr = addr; | |
| 335 fSize = size; | |
| 336 } | |
| 337 | |
| 338 SkMMAPStream::~SkMMAPStream() | |
| 339 { | |
| 340 this->closeMMap(); | |
| 341 } | |
| 342 | |
| 343 void SkMMAPStream::setMemory(const void* data, size_t length) | |
| 344 { | |
| 345 this->closeMMap(); | |
| 346 this->INHERITED::setMemory(data, length); | |
| 347 } | |
| 348 | |
| 349 void SkMMAPStream::closeMMap() | |
| 350 { | |
| 351 if (fFildes >= 0) | |
| 352 { | |
| 353 munmap(fAddr, fSize); | |
| 354 close(fFildes); | |
| 355 fFildes = -1; | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 #endif | |
| 360 | |
| 361 SkStream* SkFontHost::OpenDescriptorStream(const SkDescriptor* desc, const char
keyString[]) | |
| 362 { | |
| 363 // our key string IS our filename, so we can ignore desc | |
| 364 SkStream* strm; | |
| 365 | |
| 366 #ifdef SK_CAN_USE_MMAP | |
| 367 strm = new SkMMAPStream(keyString); | |
| 368 if (strm->getLength() > 0) | |
| 369 return strm; | |
| 370 | |
| 371 // strm not valid | |
| 372 delete strm; | |
| 373 // fall through to FILEStream attempt | |
| 374 #endif | |
| 375 | |
| 376 strm = new SkFILEStream(keyString); | |
| 377 if (strm->getLength() > 0) | |
| 378 return strm; | |
| 379 | |
| 380 // strm not valid | |
| 381 delete strm; | |
| 382 return NULL; | |
| 383 } | |
| 384 | |
| 385 SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::
Rec& rec) | |
| 386 { | |
| 387 const FontFaceRec* face = get_default_face(); | |
| 388 | |
| 389 SkAutoDescriptor ad(sizeof(rec) + sizeof(face) + SkDescriptor::ComputeOve
rhead(2)); | |
| 390 SkDescriptor* desc = ad.getDesc(); | |
| 391 | |
| 392 desc->init(); | |
| 393 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); | |
| 394 desc->addEntry(kTypeface_SkDescriptorTag, sizeof(face), &face); | |
| 395 desc->computeChecksum(); | |
| 396 | |
| 397 return SkFontHost::CreateScalerContext(desc); | |
| 398 } | |
| 399 | |
| 400 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) | |
| 401 { | |
| 402 return 0; // nothing to do (change me if you want to limit the font cache) | |
| 403 } | |
| 404 | |
| 405 int SkFontHost::ComputeGammaFlag(const SkPaint& paint) | |
| 406 { | |
| 407 return 0; | |
| 408 } | |
| 409 | |
| 410 void SkFontHost::GetGammaTables(const uint8_t* tables[2]) | |
| 411 { | |
| 412 tables[0] = NULL; // black gamma (e.g. exp=1.4) | |
| 413 tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) | |
| 414 } | |
| 415 | |
| OLD | NEW |