Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: src/ports/SkFontConfigInterface_android.cpp

Issue 445143002: Remove Android FontConfigInterface (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Rebase Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/ports/SkTypeface_android.h ('k') | src/ports/SkFontMgr_android.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1
2 /*
3 * Copyright 2013 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "SkFontConfigInterface.h"
10 #include "SkTypeface_android.h"
11
12 #include "SkFontConfigParser_android.h"
13 #include "SkFontConfigTypeface.h"
14 #include "SkFontHost_FreeType_common.h"
15 #include "SkFontMgr.h"
16 #include "SkGlyphCache.h"
17 #include "SkPaint.h"
18 #include "SkString.h"
19 #include "SkStream.h"
20 #include "SkThread.h"
21 #include "SkTypefaceCache.h"
22 #include "SkTArray.h"
23 #include "SkTDict.h"
24 #include "SkTSearch.h"
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #ifndef SK_DEBUG_FONTS
30 #define SK_DEBUG_FONTS 0
31 #endif
32
33 #if SK_DEBUG_FONTS
34 #define DEBUG_FONT(args) SkDebugf args
35 #else
36 #define DEBUG_FONT(args)
37 #endif
38
39 ///////////////////////////////////////////////////////////////////////////////
40
41 // For test only.
42 static const char* gTestMainConfigFile = NULL;
43 static const char* gTestFallbackConfigFile = NULL;
44 static const char* gTestFontFilePrefix = NULL;
45
46 ///////////////////////////////////////////////////////////////////////////////
47
48 typedef int32_t FontRecID;
49 #define INVALID_FONT_REC_ID -1
50
51 typedef int32_t FamilyRecID;
52 #define INVALID_FAMILY_REC_ID -1
53
54 // used to record our notion of the pre-existing fonts
55 struct FontRec {
56 SkAutoTUnref<SkTypeface> fTypeface;
57 SkString fFileName;
58 SkTypeface::Style fStyle;
59 bool fIsValid;
60 FamilyRecID fFamilyRecID;
61 };
62
63 struct FamilyRec {
64 FamilyRec() {
65 memset(fFontRecID, INVALID_FONT_REC_ID, sizeof(fFontRecID));
66 }
67
68 static const int FONT_STYLE_COUNT = 4;
69 FontRecID fFontRecID[FONT_STYLE_COUNT];
70 bool fIsFallbackFont;
71 SkString fFallbackName;
72 SkPaintOptionsAndroid fPaintOptions;
73 };
74
75
76 typedef SkTDArray<FamilyRecID> FallbackFontList;
77
78 class SkFontConfigInterfaceAndroid : public SkFontConfigInterface {
79 public:
80 SkFontConfigInterfaceAndroid(SkTDArray<FontFamily*>& fontFamilies);
81 virtual ~SkFontConfigInterfaceAndroid();
82
83 virtual bool matchFamilyName(const char familyName[],
84 SkTypeface::Style requested,
85 FontIdentity* outFontIdentifier,
86 SkString* outFamilyName,
87 SkTypeface::Style* outStyle) SK_OVERRIDE;
88 virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
89
90 // new APIs
91 virtual SkDataTable* getFamilyNames() SK_OVERRIDE;
92 virtual bool matchFamilySet(const char inFamilyName[],
93 SkString* outFamilyName,
94 SkTArray<FontIdentity>*) SK_OVERRIDE;
95
96 /**
97 * Get the family name of the font in the default fallback font list that
98 * contains the specified chararacter. if no font is found, returns false.
99 */
100 bool getFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* name);
101
102 private:
103 void addFallbackFamily(FamilyRecID fontRecID);
104 SkTypeface* getTypefaceForFontRec(FontRecID fontRecID);
105 FallbackFontList* findFallbackFontList(const SkLanguage& lang, bool isOrigin al = true);
106
107 SkTArray<FontRec, true> fFonts;
108 SkTArray<FamilyRec, true> fFontFamilies;
109 SkTDict<FamilyRecID> fFamilyNameDict;
110 FamilyRecID fDefaultFamilyRecID;
111
112 // (SkLanguage)<->(fallback chain index) translation
113 SkTDict<FallbackFontList*> fFallbackFontDict;
114 SkTDict<FallbackFontList*> fFallbackFontAliasDict;
115 FallbackFontList fDefaultFallbackList;
116
117 // fallback info for current locale
118 SkString fCachedLocale;
119 FallbackFontList* fLocaleFallbackFontList;
120 };
121
122 ///////////////////////////////////////////////////////////////////////////////
123
124 SK_DECLARE_STATIC_MUTEX(gGetSingletonInterfaceMutex);
125 static SkFontConfigInterfaceAndroid* getSingletonInterface() {
126 static SkFontConfigInterfaceAndroid* gFontConfigInterface;
127
128 SkAutoMutexAcquire ac(gGetSingletonInterfaceMutex);
129 if (NULL == gFontConfigInterface) {
130 // load info from a configuration file that we can use to populate the
131 // system/fallback font structures
132 SkTDArray<FontFamily*> fontFamilies;
133 if (!gTestMainConfigFile) {
134 SkFontConfigParser::GetFontFamilies(fontFamilies);
135 } else {
136 SkFontConfigParser::GetTestFontFamilies(fontFamilies, gTestMainConfi gFile,
137 gTestFallbackConfigFile);
138 }
139
140 gFontConfigInterface = new SkFontConfigInterfaceAndroid(fontFamilies);
141
142 // cleanup the data we received from the parser
143 fontFamilies.deleteAll();
144 }
145 return gFontConfigInterface;
146 }
147
148 SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface(SkBase Mutex*) {
149 // Doesn't need passed-in mutex because getSingletonInterface() uses one
150 return getSingletonInterface();
151 }
152
153 ///////////////////////////////////////////////////////////////////////////////
154
155 static bool has_font(const SkTArray<FontRec, true>& array, const SkString& filen ame) {
156 for (int i = 0; i < array.count(); i++) {
157 if (array[i].fFileName == filename) {
158 return true;
159 }
160 }
161 return false;
162 }
163
164 #ifndef SK_FONT_FILE_PREFIX
165 #define SK_FONT_FILE_PREFIX "/fonts/"
166 #endif
167
168 static void get_path_for_sys_fonts(SkString* full, const SkString& name) {
169 if (gTestFontFilePrefix) {
170 full->set(gTestFontFilePrefix);
171 } else {
172 full->set(getenv("ANDROID_ROOT"));
173 full->append(SK_FONT_FILE_PREFIX);
174 }
175 full->append(name);
176 }
177
178 static void insert_into_name_dict(SkTDict<FamilyRecID>& familyNameDict,
179 const char* name, FamilyRecID familyRecID) {
180 SkAutoAsciiToLC tolc(name);
181 if (familyNameDict.find(tolc.lc())) {
182 SkDebugf("---- system font attempting to use a the same name [%s] for"
183 "multiple families. skipping subsequent occurrences", tolc.lc() );
184 } else {
185 familyNameDict.set(tolc.lc(), familyRecID);
186 }
187 }
188
189 ///////////////////////////////////////////////////////////////////////////////
190
191 SkFontConfigInterfaceAndroid::SkFontConfigInterfaceAndroid(SkTDArray<FontFamily* >& fontFamilies) :
192 fFonts(fontFamilies.count()),
193 fFontFamilies(fontFamilies.count() / FamilyRec::FONT_STYLE_COUNT),
194 fFamilyNameDict(1024),
195 fDefaultFamilyRecID(INVALID_FAMILY_REC_ID),
196 fFallbackFontDict(128),
197 fFallbackFontAliasDict(128),
198 fLocaleFallbackFontList(NULL) {
199
200 for (int i = 0; i < fontFamilies.count(); ++i) {
201 FontFamily* family = fontFamilies[i];
202
203 // defer initializing the familyRec until we can be sure that at least
204 // one of it's children contains a valid font file
205 FamilyRec* familyRec = NULL;
206 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
207
208 for (int j = 0; j < family->fFonts.count(); ++j) {
209 SkString filename;
210 get_path_for_sys_fonts(&filename, family->fFonts[j].fFileName);
211
212 if (has_font(fFonts, filename)) {
213 DEBUG_FONT(("---- system font and fallback font files specify a duplicate "
214 "font %s, skipping the second occurrence", filename.c_st r()));
215 }
216
217 FontRec& fontRec = fFonts.push_back();
218 fontRec.fFileName = filename;
219 fontRec.fStyle = SkTypeface::kNormal;
220 fontRec.fIsValid = false;
221 fontRec.fFamilyRecID = familyRecID;
222
223 const FontRecID fontRecID = fFonts.count() - 1;
224
225 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(filename.c_str() ));
226 if (stream.get() != NULL) {
227 bool isFixedWidth;
228 SkString name;
229 fontRec.fIsValid = SkTypeface_FreeType::ScanFont(stream.get(), 0 ,
230 &name, &fontRec .fStyle,
231 &isFixedWidth);
232 } else {
233 if (!family->fIsFallbackFont) {
234 SkDebugf("---- failed to open <%s> as a font\n", filename.c_ str());
235 }
236 }
237
238 if (fontRec.fIsValid) {
239 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s",
240 i, fFonts.count() - 1, family->fIsFallbackFont, filen ame.c_str()));
241 } else {
242 DEBUG_FONT(("---- SystemFonts[%d][%d] fallback=%d file=%s (INVAL ID)",
243 i, fFonts.count() - 1, family->fIsFallbackFont, filen ame.c_str()));
244 continue;
245 }
246
247 // create a familyRec now that we know that at least one font in
248 // the family is valid
249 if (familyRec == NULL) {
250 familyRec = &fFontFamilies.push_back();
251 familyRecID = fFontFamilies.count() - 1;
252 fontRec.fFamilyRecID = familyRecID;
253
254 familyRec->fIsFallbackFont = family->fIsFallbackFont;
255 familyRec->fPaintOptions = family->fFonts[j].fPaintOptions;
256
257 } else if (familyRec->fPaintOptions != family->fFonts[j].fPaintOptio ns) {
258 SkDebugf("Every font file within a family must have identical"
259 "language and variant attributes");
260 sk_throw();
261 }
262
263 // add this font to the current familyRec
264 if (INVALID_FONT_REC_ID != familyRec->fFontRecID[fontRec.fStyle]) {
265 DEBUG_FONT(("Overwriting familyRec for style[%d] old,new:(%d,%d) ",
266 fontRec.fStyle, familyRec->fFontRecID[fontRec.fStyle ],
267 fontRecID));
268 }
269 familyRec->fFontRecID[fontRec.fStyle] = fontRecID;
270 }
271
272 if (familyRec) {
273 if (familyRec->fIsFallbackFont) {
274 // add the font to the appropriate fallback chains and also inse rt a
275 // unique name into the familyNameDict for internal usage
276 addFallbackFamily(familyRecID);
277 } else {
278 // add the names that map to this family to the dictionary for e asy lookup
279 const SkTArray<SkString>& names = family->fNames;
280 if (names.empty()) {
281 SkDEBUGFAIL("ERROR: non-fallback font with no name");
282 continue;
283 }
284
285 for (int i = 0; i < names.count(); i++) {
286 insert_into_name_dict(fFamilyNameDict, names[i].c_str(), fam ilyRecID);
287 }
288 }
289 }
290 }
291
292 DEBUG_FONT(("---- We have %d system fonts", fFonts.count()));
293
294 if (fFontFamilies.count() > 0) {
295 fDefaultFamilyRecID = 0;
296 }
297
298 // scans the default fallback font chain, adding every entry to every other
299 // fallback font chain to which it does not belong. this results in every
300 // language-specific fallback font chain having all of its fallback fonts at
301 // the front of the chain, and everything else at the end.
302 FallbackFontList* fallbackList;
303 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
304 const char* fallbackLang = iter.next(&fallbackList);
305 while(fallbackLang != NULL) {
306 for (int i = 0; i < fDefaultFallbackList.count(); i++) {
307 FamilyRecID familyRecID = fDefaultFallbackList[i];
308 const SkString& fontLang = fFontFamilies[familyRecID].fPaintOptions. getLanguage().getTag();
309 if (strcmp(fallbackLang, fontLang.c_str()) != 0) {
310 fallbackList->push(familyRecID);
311 }
312 }
313 // move to the next fallback list in the dictionary
314 fallbackLang = iter.next(&fallbackList);
315 }
316 }
317
318 SkFontConfigInterfaceAndroid::~SkFontConfigInterfaceAndroid() {
319 // iterate through and cleanup fFallbackFontDict
320 SkTDict<FallbackFontList*>::Iter iter(fFallbackFontDict);
321 FallbackFontList* fallbackList;
322 while(iter.next(&fallbackList) != NULL) {
323 SkDELETE(fallbackList);
324 }
325 }
326
327 void SkFontConfigInterfaceAndroid::addFallbackFamily(FamilyRecID familyRecID) {
328 SkASSERT(familyRecID < fFontFamilies.count());
329 FamilyRec& familyRec = fFontFamilies[familyRecID];
330 SkASSERT(familyRec.fIsFallbackFont);
331
332 // add the fallback family to the name dictionary. This is
333 // needed by getFallbackFamilyNameForChar() so that fallback
334 // families can be identified by a unique name. The unique
335 // identifier that we've chosen is the familyID in hex (e.g. '0F##fallback') .
336 familyRec.fFallbackName.printf("%.2x##fallback", familyRecID);
337 insert_into_name_dict(fFamilyNameDict, familyRec.fFallbackName.c_str(), fami lyRecID);
338
339 // add to the default fallback list
340 fDefaultFallbackList.push(familyRecID);
341
342 // stop here if it is the default language tag
343 const SkString& languageTag = familyRec.fPaintOptions.getLanguage().getTag() ;
344 if (languageTag.isEmpty()) {
345 return;
346 }
347
348 // add to the appropriate language's custom fallback list
349 FallbackFontList* customList = NULL;
350 if (!fFallbackFontDict.find(languageTag.c_str(), &customList)) {
351 DEBUG_FONT(("---- Created fallback list for \"%s\"", languageTag.c_str( )));
352 customList = SkNEW(FallbackFontList);
353 fFallbackFontDict.set(languageTag.c_str(), customList);
354 }
355 SkASSERT(customList != NULL);
356 customList->push(familyRecID);
357 }
358
359
360 static FontRecID find_best_style(const FamilyRec& family, SkTypeface::Style styl e) {
361
362 const FontRecID* fontRecIDs = family.fFontRecID;
363
364 if (fontRecIDs[style] != INVALID_FONT_REC_ID) { // exact match
365 return fontRecIDs[style];
366 }
367 // look for a matching bold
368 style = (SkTypeface::Style)(style ^ SkTypeface::kItalic);
369 if (fontRecIDs[style] != INVALID_FONT_REC_ID) {
370 return fontRecIDs[style];
371 }
372 // look for the plain
373 if (fontRecIDs[SkTypeface::kNormal] != INVALID_FONT_REC_ID) {
374 return fontRecIDs[SkTypeface::kNormal];
375 }
376 // look for anything
377 for (int i = 0; i < FamilyRec::FONT_STYLE_COUNT; i++) {
378 if (fontRecIDs[i] != INVALID_FONT_REC_ID) {
379 return fontRecIDs[i];
380 }
381 }
382 // should never get here, since the fontRecID list should not be empty
383 SkDEBUGFAIL("No valid fonts exist for this family");
384 return -1;
385 }
386
387 bool SkFontConfigInterfaceAndroid::matchFamilyName(const char familyName[],
388 SkTypeface::Style style,
389 FontIdentity* outFontIdentifi er,
390 SkString* outFamilyName,
391 SkTypeface::Style* outStyle) {
392 // clip to legal style bits
393 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
394
395 bool exactNameMatch = false;
396
397 FamilyRecID familyRecID = INVALID_FAMILY_REC_ID;
398 if (NULL != familyName) {
399 SkAutoAsciiToLC tolc(familyName);
400 if (fFamilyNameDict.find(tolc.lc(), &familyRecID)) {
401 exactNameMatch = true;
402 }
403 } else {
404 familyRecID = fDefaultFamilyRecID;
405
406 }
407
408 // If no matching family name is found then return false. This allows client s
409 // to be able to search for other fonts instead of forcing them to use the
410 // default font.
411 if (INVALID_FAMILY_REC_ID == familyRecID) {
412 return false;
413 }
414
415 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], style);
416 FontRec& fontRec = fFonts[fontRecID];
417
418 if (NULL != outFontIdentifier) {
419 outFontIdentifier->fID = fontRecID;
420 outFontIdentifier->fTTCIndex = 0;
421 outFontIdentifier->fString.set(fontRec.fFileName);
422 // outFontIdentifier->fStyle = fontRec.fStyle;
423 }
424
425 if (NULL != outFamilyName) {
426 if (exactNameMatch) {
427 outFamilyName->set(familyName);
428 } else {
429 // find familyName from list of names
430 const char* familyName = NULL;
431 SkAssertResult(fFamilyNameDict.findKey(familyRecID, &familyName));
432 SkASSERT(familyName);
433 outFamilyName->set(familyName);
434 }
435 }
436
437 if (NULL != outStyle) {
438 *outStyle = fontRec.fStyle;
439 }
440
441 return true;
442 }
443
444 SkStream* SkFontConfigInterfaceAndroid::openStream(const FontIdentity& identity) {
445 return SkStream::NewFromFile(identity.fString.c_str());
446 }
447
448 SkDataTable* SkFontConfigInterfaceAndroid::getFamilyNames() {
449 SkTDArray<const char*> names;
450 SkTDArray<size_t> sizes;
451
452 SkTDict<FamilyRecID>::Iter iter(fFamilyNameDict);
453 const char* familyName = iter.next(NULL);
454 while(familyName != NULL) {
455 *names.append() = familyName;
456 *sizes.append() = strlen(familyName) + 1;
457
458 // move to the next familyName in the dictionary
459 familyName = iter.next(NULL);
460 }
461
462 return SkDataTable::NewCopyArrays((const void*const*)names.begin(),
463 sizes.begin(), names.count());
464 }
465
466 bool SkFontConfigInterfaceAndroid::matchFamilySet(const char inFamilyName[],
467 SkString* outFamilyName,
468 SkTArray<FontIdentity>*) {
469 return false;
470 }
471
472 static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
473 const FontRecID* fontRecID = (const FontRecID*)ctx;
474 FontRecID currFontRecID = ((FontConfigTypeface*)face)->getIdentity().fID;
475 return currFontRecID == *fontRecID;
476 }
477
478 SkTypeface* SkFontConfigInterfaceAndroid::getTypefaceForFontRec(FontRecID fontRe cID) {
479 FontRec& fontRec = fFonts[fontRecID];
480 SkTypeface* face = fontRec.fTypeface.get();
481 if (!face) {
482 // look for it in the typeface cache
483 face = SkTypefaceCache::FindByProcAndRef(find_proc, &fontRecID);
484
485 // if it is not in the cache then create it
486 if (!face) {
487 const char* familyName = NULL;
488 SkAssertResult(fFamilyNameDict.findKey(fontRec.fFamilyRecID, &family Name));
489 SkASSERT(familyName);
490 face = SkTypeface::CreateFromName(familyName, fontRec.fStyle);
491 }
492
493 // store the result for subsequent lookups
494 fontRec.fTypeface.reset(face);
495 }
496 SkASSERT(face);
497 return face;
498 }
499
500 bool SkFontConfigInterfaceAndroid::getFallbackFamilyNameForChar(SkUnichar uni,
501 const char* lang ,
502 SkString* name) {
503 const SkString locale(lang);
504 if (NULL == fLocaleFallbackFontList || locale != fCachedLocale) {
505 fCachedLocale = locale;
506 fLocaleFallbackFontList = this->findFallbackFontList(locale);
507 }
508 FallbackFontList* fallbackFontList = fLocaleFallbackFontList;
509
510 for (int i = 0; i < fallbackFontList->count(); i++) {
511 FamilyRecID familyRecID = fallbackFontList->getAt(i);
512
513 // if it is not one of the accepted variants then move to the next famil y
514 int32_t acceptedVariants = SkPaintOptionsAndroid::kDefault_Variant |
515 SkPaintOptionsAndroid::kElegant_Variant;
516 if (!(fFontFamilies[familyRecID].fPaintOptions.getFontVariant() & accept edVariants)) {
517 continue;
518 }
519
520 FontRecID fontRecID = find_best_style(fFontFamilies[familyRecID], SkType face::kNormal);
521 SkTypeface* face = this->getTypefaceForFontRec(fontRecID);
522
523 SkPaint paint;
524 paint.setTypeface(face);
525 paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
526
527 uint16_t glyphID;
528 paint.textToGlyphs(&uni, sizeof(uni), &glyphID);
529 if (glyphID != 0) {
530 name->set(fFontFamilies[familyRecID].fFallbackName);
531 return true;
532 }
533 }
534 return false;
535 }
536
537 FallbackFontList* SkFontConfigInterfaceAndroid::findFallbackFontList(const SkLan guage& lang,
538 bool isOrig inal) {
539 const SkString& langTag = lang.getTag();
540 if (langTag.isEmpty()) {
541 return &fDefaultFallbackList;
542 }
543
544 FallbackFontList* fallbackFontList;
545 if (fFallbackFontDict.find(langTag.c_str(), langTag.size(), &fallbackFontLis t) ||
546 fFallbackFontAliasDict.find(langTag.c_str(), langTag.size(), &fallbackFo ntList)) {
547 return fallbackFontList;
548 }
549
550 // attempt a recursive fuzzy match
551 SkLanguage parent = lang.getParent();
552 fallbackFontList = findFallbackFontList(parent, false);
553
554 // cache the original lang so we don't have to do the recursion again.
555 if (isOriginal) {
556 DEBUG_FONT(("---- Created fallback list alias for \"%s\"", langTag.c_st r()));
557 fFallbackFontAliasDict.set(langTag.c_str(), fallbackFontList);
558 }
559 return fallbackFontList;
560 }
561
562 ///////////////////////////////////////////////////////////////////////////////
563
564 bool SkGetFallbackFamilyNameForChar(SkUnichar uni, const char* lang, SkString* n ame) {
565 SkFontConfigInterfaceAndroid* fontConfig = getSingletonInterface();
566 return fontConfig->getFallbackFamilyNameForChar(uni, lang, name);
567 }
568
569 void SkUseTestFontConfigFile(const char* mainconf, const char* fallbackconf,
570 const char* fontsdir) {
571 gTestMainConfigFile = mainconf;
572 gTestFallbackConfigFile = fallbackconf;
573 gTestFontFilePrefix = fontsdir;
574 SkASSERT(gTestMainConfigFile);
575 SkASSERT(gTestFallbackConfigFile);
576 SkASSERT(gTestFontFilePrefix);
577 SkDEBUGF(("Use Test Config File Main %s, Fallback %s, Font Dir %s",
578 gTestMainConfigFile, gTestFallbackConfigFile, gTestFontFilePrefix) );
579 }
580
581 void SkGetTestFontConfiguration(const char** mainconf, const char** fallbackconf ,
582 const char** fontsdir) {
583 *mainconf = gTestMainConfigFile;
584 *fallbackconf = gTestFallbackConfigFile;
585 *fontsdir = gTestFontFilePrefix;
586 }
OLDNEW
« no previous file with comments | « include/ports/SkTypeface_android.h ('k') | src/ports/SkFontMgr_android.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698