OLD | NEW |
| (Empty) |
1 /* | |
2 ** Copyright 2006, The Android Open Source Project | |
3 ** | |
4 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
5 ** you may not use this file except in compliance with the License. | |
6 ** You may obtain a copy of the License at | |
7 ** | |
8 ** http://www.apache.org/licenses/LICENSE-2.0 | |
9 ** | |
10 ** Unless required by applicable law or agreed to in writing, software | |
11 ** distributed under the License is distributed on an "AS IS" BASIS, | |
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 ** See the License for the specific language governing permissions and | |
14 ** limitations under the License. | |
15 */ | |
16 | |
17 #include "SkFontHost.h" | |
18 #include "SkDescriptor.h" | |
19 | |
20 // Give 1MB font cache budget | |
21 #define FONT_CACHE_MEMORY_BUDGET (1024 * 1024) | |
22 | |
23 const char* gDefaultfont = "Arial"; // hard code for now | |
24 static SkMutex gFTMutex; | |
25 | |
26 inline SkPoint F32PtToSkPoint(const Float32Point p) | |
27 { | |
28 SkPoint sp = { SkFloatToFixed(p.x),SkFloatToFixed(p.y) }; | |
29 return sp; | |
30 } | |
31 | |
32 static inline uint32_t _rotl(uint32_t v, uint32_t r) | |
33 { | |
34 return (v << r | v >> (32 - r)); | |
35 } | |
36 | |
37 // This will generate a unique ID based on the fontname + fontstyle | |
38 // and also used by upper layer | |
39 uint32_t FontFaceChecksum(const char *name,SkTypeface::Style style) | |
40 { | |
41 if (!name) return style; | |
42 | |
43 char* q = (char*)name; | |
44 | |
45 // From "Performance in Practice of String Hashing Functions" | |
46 // Ramakrishna & Zobel | |
47 const uint32_t L = 5; | |
48 const uint32_t R = 2; | |
49 | |
50 uint32_t h = 0x12345678; | |
51 while (*q) { | |
52 uint32_t ql = tolower(*q); | |
53 h ^= ((h << L) + (h >> R) + ql); | |
54 q ++; | |
55 } | |
56 | |
57 // add style | |
58 h = _rotl(h, 3) ^ style; | |
59 | |
60 return h; | |
61 } | |
62 | |
63 #pragma mark - | |
64 struct SkFaceRec { | |
65 SkFaceRec* fNext; | |
66 uint32_t fRefCnt; | |
67 ATSUFontID fFontID; | |
68 ATSUStyle fStyle; | |
69 | |
70 SkFaceRec() : fFontID(0), fRefCnt(0), fStyle(NULL) {}; | |
71 | |
72 ~SkFaceRec() { | |
73 if (fStyle) { | |
74 ::ATSUDisposeStyle(fStyle); | |
75 fStyle = NULL; | |
76 } | |
77 } | |
78 | |
79 uint32_t ref() { | |
80 return ++fRefCnt; | |
81 } | |
82 }; | |
83 | |
84 // Font Face list | |
85 static SkFaceRec* gFaceRecHead = NULL; | |
86 | |
87 static SkFaceRec* find_ft_face(const ATSUFontID fontID) { | |
88 SkFaceRec* rec = gFaceRecHead; | |
89 while (rec) { | |
90 if (rec->fFontID == fontID) { | |
91 return rec; | |
92 } | |
93 rec = rec->fNext; | |
94 } | |
95 | |
96 return NULL; | |
97 } | |
98 | |
99 static SkFaceRec* insert_ft_face(const ATSUFontID afontID, const ATSUStyle atsuS
tyle) { | |
100 SkFaceRec* rec = find_ft_face(afontID); | |
101 if (rec) { | |
102 return rec; // found? | |
103 } | |
104 | |
105 rec = SkNEW(SkFaceRec); | |
106 rec->fFontID = afontID; | |
107 rec->fStyle = atsuStyle; | |
108 rec->fNext = gFaceRecHead; | |
109 gFaceRecHead = rec; | |
110 | |
111 return rec; | |
112 } | |
113 | |
114 static void unref_ft_face(const ATSUFontID fontID) { | |
115 | |
116 SkFaceRec* rec = gFaceRecHead; | |
117 SkFaceRec* prev = NULL; | |
118 while (rec) { | |
119 SkFaceRec* next = rec->fNext; | |
120 if (rec->fFontID == fontID) { | |
121 if (--rec->fRefCnt == 0) { | |
122 if (prev) | |
123 prev->fNext = next; | |
124 else | |
125 gFaceRecHead = next; | |
126 | |
127 SkDELETE(rec); | |
128 } | |
129 return; | |
130 } | |
131 prev = rec; | |
132 rec = next; | |
133 } | |
134 SkASSERT("shouldn't get here, face not in list"); | |
135 } | |
136 | |
137 #pragma mark - | |
138 | |
139 // have to do this because SkTypeface::SkTypeface() is protected | |
140 class SkTypeface_Mac : public SkTypeface { | |
141 public: | |
142 SkTypeface_Mac(SkTypeface::Style style, uint32_t id) : SkTypeface(style, id)
{} | |
143 | |
144 ~SkTypeface_Mac() {} | |
145 }; | |
146 | |
147 #pragma mark - | |
148 | |
149 static SkTypeface* CreateTypeface_(const char *name, const SkTypeface::Style sty
le) { | |
150 | |
151 OSStatus err; | |
152 ATSUStyle atsuStyle; | |
153 ::ATSUCreateStyle(&atsuStyle); | |
154 if (name != NULL) { | |
155 static const ATSUAttributeTag fontTag = kATSUFontTag; | |
156 static const ByteCount fontTagSize = sizeof(ATSUFontID); | |
157 | |
158 ATSUFontID fontID = 0; | |
159 #if 1 | |
160 err = ::ATSUFindFontFromName( | |
161 name,strlen(name),kFontNoNameCode, /* instead of regular, kFo
ntFamilyName returns bold and/or italic sometimes, but why this works?? */ | |
162 kFontMacintoshPlatform,kFontNoScriptCode,kFontNoLanguageCode,&fo
ntID); | |
163 #else | |
164 CFStringRef cfontName = CFStringCreateWithCString(NULL, name, kCFStringE
ncodingASCII); | |
165 ATSFontRef fontRef = ::ATSFontFindFromName(cfontName,kATSOptionFlagsDefa
ult); | |
166 fontID = ::FMGetFontFromATSFontRef(fontRef); | |
167 CFRelease(cfontName); | |
168 #endif | |
169 if (0 != fontID) { | |
170 const ATSUAttributeValuePtr values[] = { &fontID }; | |
171 err = ::ATSUSetAttributes(atsuStyle,1,&fontTag,&fontTagSize,values); | |
172 } | |
173 else { | |
174 } | |
175 } | |
176 if (style != SkTypeface::kNormal) { | |
177 Boolean fontItalic = ((style & SkTypeface::kItalic) != 0); | |
178 Boolean fontBold = ((style & SkTypeface::kBold) != 0); | |
179 const ATSUAttributeTag tags[2] = { kATSUQDBoldfaceTag, kATSUQDIta
licTag }; | |
180 const ATSUAttributeValuePtr values[2] = { &fontBold, &fontItalic }; | |
181 const ByteCount sizes[2] = { sizeof(Boolean), sizeof(Bool
ean) }; | |
182 err = ::ATSUSetAttributes(atsuStyle,2,tags,sizes,values); | |
183 } | |
184 | |
185 uint32_t cs = FontFaceChecksum(name,style); | |
186 SkTypeface_Mac* ptypeface = new SkTypeface_Mac(style,cs); | |
187 | |
188 if (NULL == ptypeface) { | |
189 SkASSERT(false); | |
190 return NULL; | |
191 } | |
192 | |
193 SkFaceRec* rec = insert_ft_face(cs, atsuStyle); | |
194 SkASSERT(rec); | |
195 | |
196 return ptypeface; | |
197 } | |
198 | |
199 static SkTypeface* CreateTypeface_(const SkFaceRec* rec, const SkTypeface::Style
style) { | |
200 | |
201 OSStatus err; | |
202 ATSUStyle atsuStyle; | |
203 err = ::ATSUCreateAndCopyStyle(rec->fStyle, &atsuStyle); | |
204 | |
205 Boolean fontItalic = ((style & SkTypeface::kItalic) != 0); | |
206 Boolean fontBold = ((style & SkTypeface::kBold) != 0); | |
207 const ATSUAttributeTag tags[2] = { kATSUQDBoldfaceTag, kATSUQDItalicT
ag }; | |
208 const ATSUAttributeValuePtr values[2] = { &fontBold, &fontItalic }; | |
209 const ByteCount sizes[2] = { sizeof(Boolean), sizeof(Boolean)
}; | |
210 err = ::ATSUSetAttributes(atsuStyle,2,tags,sizes,values); | |
211 | |
212 // get old font id and name | |
213 ATSUFontID fontID = 0; | |
214 ByteCount actual = 0; | |
215 err = ::ATSUGetAttribute(rec->fStyle,kATSUFontTag,sizeof(ATSUFontID),&fontID
,&actual); | |
216 | |
217 ByteCount actualLength = 0; | |
218 char *fontname = NULL; | |
219 err = ::ATSUFindFontName(fontID , kFontFamilyName, kFontUnicodePlatform, kFo
ntNoScriptCode, | |
220 kFontNoLanguageCode , 0 , NULL , &actualLength , NULL ); | |
221 if ( err == noErr) | |
222 { | |
223 actualLength += 1 ; | |
224 fontname = (char*)malloc( actualLength ); | |
225 err = ::ATSUFindFontName(fontID, kFontFamilyName, kFontUnicodePlatform,
kFontNoScriptCode, | |
226 kFontNoLanguageCode, actualLength, fontname , NULL, NULL); | |
227 } | |
228 | |
229 SkTypeface_Mac* ptypeface = NULL; | |
230 if (fontname == NULL) { | |
231 ptypeface = new SkTypeface_Mac(style,rec->fFontID); | |
232 return ptypeface; | |
233 } | |
234 else { | |
235 uint32_t cs = FontFaceChecksum(fontname,style); | |
236 ptypeface = new SkTypeface_Mac(style, cs); | |
237 | |
238 if (NULL == ptypeface) { | |
239 SkASSERT(false); | |
240 return NULL; | |
241 } | |
242 | |
243 free(fontname); | |
244 | |
245 insert_ft_face(cs,atsuStyle); | |
246 } | |
247 return ptypeface; | |
248 } | |
249 | |
250 #pragma mark - | |
251 | |
252 class SkScalerContext_Mac : public SkScalerContext { | |
253 public: | |
254 SkScalerContext_Mac(const SkDescriptor* desc); | |
255 virtual ~SkScalerContext_Mac(); | |
256 | |
257 protected: | |
258 virtual unsigned generateGlyphCount() const; | |
259 virtual uint16_t generateCharToGlyph(SkUnichar uni); | |
260 virtual void generateAdvance(SkGlyph* glyph); | |
261 virtual void generateMetrics(SkGlyph* glyph); | |
262 virtual void generateImage(const SkGlyph& glyph); | |
263 virtual void generatePath(const SkGlyph& glyph, SkPath* path); | |
264 virtual void generateLineHeight(SkPoint* ascent, SkPoint* descent); | |
265 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetr
ics* mY); | |
266 virtual SkDeviceContext getDC() { return NULL; } // not implemented on Mac | |
267 | |
268 private: | |
269 ATSUTextLayout fLayout; | |
270 ATSUStyle fStyle; | |
271 | |
272 static OSStatus MoveTo(const Float32Point *pt, void *cb); | |
273 static OSStatus Line(const Float32Point *pt, void *cb); | |
274 static OSStatus Curve(const Float32Point *pt1, const Float32Point *pt2, cons
t Float32Point *pt3, void *cb); | |
275 static OSStatus Close(void *cb); | |
276 }; | |
277 | |
278 SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc) | |
279 : SkScalerContext(desc), fLayout(0), fStyle(0) | |
280 { | |
281 SkAutoMutexAcquire ac(gFTMutex); | |
282 OSStatus err; | |
283 | |
284 SkFaceRec* rec = find_ft_face(fRec.fFontID); | |
285 if (rec) { | |
286 rec->ref(); | |
287 err = ::ATSUCreateAndCopyStyle(rec->fStyle, &fStyle); | |
288 } | |
289 else { | |
290 SkASSERT(false); | |
291 // create a default | |
292 err = ::ATSUCreateStyle(&fStyle); | |
293 } | |
294 | |
295 uint32_t size = SkFixedFloor(fRec.fTextSize); | |
296 Fixed fixedSize = IntToFixed(size); | |
297 static const ATSUAttributeTag sizeTag = kATSUSizeTag; | |
298 static const ByteCount sizeTagSize = sizeof(Fixed); | |
299 const ATSUAttributeValuePtr values[] = { &fixedSize }; | |
300 err = ::ATSUSetAttributes(fStyle,1,&sizeTag,&sizeTagSize,values); | |
301 | |
302 err = ::ATSUCreateTextLayout(&fLayout); | |
303 } | |
304 | |
305 SkScalerContext_Mac::~SkScalerContext_Mac() | |
306 { | |
307 unref_ft_face(fRec.fFontID); | |
308 | |
309 ::ATSUDisposeTextLayout(fLayout); | |
310 ::ATSUDisposeStyle(fStyle); | |
311 } | |
312 | |
313 unsigned SkScalerContext_Mac::generateGlyphCount() const | |
314 { | |
315 return 0xFFFF; | |
316 } | |
317 | |
318 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) | |
319 { | |
320 SkAutoMutexAcquire ac(gFTMutex); | |
321 | |
322 OSStatus err; | |
323 UniChar achar = uni; | |
324 err = ::ATSUSetTextPointerLocation(fLayout,&achar,0,1,1); | |
325 err = ::ATSUSetRunStyle(fLayout,fStyle,kATSUFromTextBeginning,kATSUToTextEnd
); | |
326 | |
327 ATSLayoutRecord *layoutPtr; | |
328 ItemCount count; | |
329 ATSGlyphRef glyph; | |
330 | |
331 err = ::ATSUDirectGetLayoutDataArrayPtrFromTextLayout(fLayout,0,kATSUDirectD
ataLayoutRecordATSLayoutRecordCurrent,(void**)&layoutPtr,&count); | |
332 glyph = layoutPtr->glyphID; | |
333 ::ATSUDirectReleaseLayoutDataArrayPtr(NULL,kATSUDirectDataLayoutRecordATSLay
outRecordCurrent,(void**)&layoutPtr); | |
334 return glyph; | |
335 } | |
336 | |
337 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { | |
338 this->generateMetrics(glyph); | |
339 } | |
340 | |
341 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) | |
342 { | |
343 GlyphID glyphID = glyph->fID; | |
344 ATSGlyphScreenMetrics metrics= { 0 }; | |
345 | |
346 glyph->fRsbDelta = 0; | |
347 glyph->fLsbDelta = 0; | |
348 | |
349 OSStatus err = ATSUGlyphGetScreenMetrics(fStyle,1,&glyphID,0,true,true,&metr
ics); | |
350 if (err == noErr) { | |
351 glyph->fAdvanceX = SkFloatToFixed(metrics.deviceAdvance.x); | |
352 glyph->fAdvanceY = SkFloatToFixed(metrics.deviceAdvance.y); | |
353 //glyph->fWidth = metrics.width; | |
354 //glyph->fHeight = metrics.height; | |
355 glyph->fWidth = metrics.width + ceil(metrics.sideBearing.x - metrics.oth
erSideBearing.x); | |
356 glyph->fHeight = metrics.height + ceil(metrics.sideBearing.y - metrics.o
therSideBearing.y) + 1; | |
357 | |
358 glyph->fTop = -metrics.topLeft.y; | |
359 glyph->fLeft = metrics.topLeft.x; | |
360 } | |
361 } | |
362 | |
363 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint:
:FontMetrics* my) { | |
364 //SkASSERT(false); | |
365 if (mx) | |
366 memset(mx, 0, sizeof(SkPaint::FontMetrics)); | |
367 if (my) | |
368 memset(my, 0, sizeof(SkPaint::FontMetrics)); | |
369 return; | |
370 } | |
371 | |
372 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) | |
373 { | |
374 SkAutoMutexAcquire ac(gFTMutex); | |
375 | |
376 GlyphID glyphID = glyph.fID; | |
377 ATSGlyphScreenMetrics metrics= { 0 }; | |
378 | |
379 SkASSERT(fLayout); | |
380 OSStatus err = ::ATSUGlyphGetScreenMetrics(fStyle,1,&glyphID,0,true,true,&me
trics); | |
381 | |
382 // uint32_t w = metrics.width; | |
383 // uint32_t h = metrics.height; | |
384 // uint32_t pitch = (w + 3) & ~0x3; | |
385 // if (pitch != glyph.rowBytes()) { | |
386 // SkASSERT(false); // it's different from previously cacluated in genera
teMetrics(), so the size of glyph.fImage buffer is incorrect! | |
387 // } | |
388 | |
389 CGColorSpaceRef greyColorSpace = ::CGColorSpaceCreateWithName(kCGColorSpaceG
enericGray); | |
390 CGContextRef contextRef = ::CGBitmapContextCreate((uint8_t*)glyph.fImage, gl
yph.fWidth, glyph.fHeight, 8, glyph.rowBytes(), greyColorSpace, kCGImageAlphaNon
e); | |
391 if (!contextRef) { | |
392 SkASSERT(false); | |
393 return; | |
394 } | |
395 | |
396 ::CGContextSetFillColorSpace(contextRef, greyColorSpace); | |
397 ::CGContextSetStrokeColorSpace(contextRef, greyColorSpace); | |
398 | |
399 ::CGContextSetGrayFillColor(contextRef, 0.0, 1.0); | |
400 ::CGContextFillRect(contextRef, ::CGRectMake(0, 0, glyph.fWidth, glyph.fHeig
ht)); | |
401 | |
402 ::CGContextSetGrayFillColor(contextRef, 1.0, 1.0); | |
403 ::CGContextSetGrayStrokeColor(contextRef, 1.0, 1.0); | |
404 ::CGContextSetTextDrawingMode(contextRef, kCGTextFill); | |
405 | |
406 ATSUAttributeTag tag = kATSUCGContextTag; | |
407 ByteCount size = sizeof(CGContextRef); | |
408 ATSUAttributeValuePtr value = &contextRef; | |
409 err = ::ATSUSetLayoutControls(fLayout,1,&tag,&size,&value); | |
410 err = ::ATSUDrawText(fLayout,kATSUFromTextBeginning,kATSUToTextEnd,FloatToFi
xed(-metrics.topLeft.x),FloatToFixed(glyph.fHeight-metrics.topLeft.y)); | |
411 ::CGContextRelease(contextRef); | |
412 } | |
413 | |
414 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) | |
415 { | |
416 SkAutoMutexAcquire ac(gFTMutex); | |
417 OSStatus err,result; | |
418 | |
419 err = ::ATSUGlyphGetCubicPaths( | |
420 fStyle,glyph.fID, | |
421 &SkScalerContext_Mac::MoveTo, | |
422 &SkScalerContext_Mac::Line, | |
423 &SkScalerContext_Mac::Curve, | |
424 &SkScalerContext_Mac::Close, | |
425 path,&result); | |
426 SkASSERT(err == noErr); | |
427 } | |
428 | |
429 void SkScalerContext_Mac::generateLineHeight(SkPoint* ascent, SkPoint* descent) | |
430 { | |
431 ATSUTextMeasurement textAscent, textDescent; | |
432 ByteCount actual = 0; | |
433 OSStatus err = ::ATSUGetAttribute(fStyle,kATSULineAscentTag,sizeof(ATSUTextM
easurement),&textAscent,&actual); | |
434 ascent->set(0,textAscent); | |
435 err = ::ATSUGetAttribute(fStyle,kATSULineDescentTag,sizeof(ATSUTextMeasureme
nt),&textDescent,&actual); | |
436 descent->set(0,textDescent); | |
437 } | |
438 | |
439 OSStatus SkScalerContext_Mac::MoveTo(const Float32Point *pt, void *cb) | |
440 { | |
441 reinterpret_cast<SkPath*>(cb)->moveTo(F32PtToSkPoint(*pt)); | |
442 return noErr; | |
443 } | |
444 | |
445 OSStatus SkScalerContext_Mac::Line(const Float32Point *pt, void *cb) | |
446 { | |
447 reinterpret_cast<SkPath*>(cb)->lineTo(F32PtToSkPoint(*pt)); | |
448 return noErr; | |
449 } | |
450 | |
451 OSStatus SkScalerContext_Mac::Curve(const Float32Point *pt1, const Float32Point
*pt2, const Float32Point *pt3, void *cb) | |
452 { | |
453 reinterpret_cast<SkPath*>(cb)->cubicTo(F32PtToSkPoint(*pt1),F32PtToSkPoint(*
pt2),F32PtToSkPoint(*pt3)); | |
454 return noErr; | |
455 } | |
456 | |
457 OSStatus SkScalerContext_Mac::Close(void *cb) | |
458 { | |
459 reinterpret_cast<SkPath*>(cb)->close(); | |
460 return noErr; | |
461 } | |
462 | |
463 #pragma mark - | |
464 | |
465 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { | |
466 SkASSERT(!"SkFontHost::Serialize unimplemented"); | |
467 } | |
468 | |
469 SkTypeface* SkFontHost::Deserialize(SkStream* stream) { | |
470 SkASSERT(!"SkFontHost::Deserialize unimplemented"); | |
471 return NULL; | |
472 } | |
473 | |
474 SkTypeface* SkFontHost::CreateTypeface(SkStream* stream) { | |
475 | |
476 //Should not be used on Mac, keep linker happy | |
477 SkASSERT(false); | |
478 return CreateTypeface_(gDefaultfont,SkTypeface::kNormal); | |
479 } | |
480 | |
481 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) | |
482 { | |
483 return new SkScalerContext_Mac(desc); | |
484 } | |
485 | |
486 SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::
Rec& rec) | |
487 { | |
488 SkAutoDescriptor ad(sizeof(rec) + sizeof(gDefaultfont) + SkDescriptor::Co
mputeOverhead(2)); | |
489 SkDescriptor* desc = ad.getDesc(); | |
490 | |
491 desc->init(); | |
492 SkScalerContext::Rec* newRec = | |
493 (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, sizeof(rec),
&rec); | |
494 | |
495 CreateTypeface_(gDefaultfont,SkTypeface::kNormal); | |
496 newRec->fFontID = FontFaceChecksum(gDefaultfont,SkTypeface::kNormal); | |
497 desc->computeChecksum(); | |
498 | |
499 return SkFontHost::CreateScalerContext(desc); | |
500 } | |
501 | |
502 | |
503 /** Return the closest matching typeface given either an existing family | |
504 (specified by a typeface in that family) or by a familyName, and a | |
505 requested style. | |
506 1) If familyFace is null, use famillyName. | |
507 2) If famillyName is null, use familyFace. | |
508 3) If both are null, return the default font that best matches style | |
509 This MUST not return NULL. | |
510 */ | |
511 | |
512 SkTypeface* SkFontHost::FindTypeface(const SkTypeface* familyFace, const char fa
milyName[], SkTypeface::Style style) { | |
513 | |
514 SkAutoMutexAcquire ac(gFTMutex); | |
515 | |
516 // clip to legal style bits | |
517 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); | |
518 | |
519 SkTypeface* tf = NULL; | |
520 | |
521 if (NULL == familyFace && NULL == familyName) { | |
522 tf = CreateTypeface_(gDefaultfont,style); | |
523 } | |
524 else { | |
525 if (NULL != familyFace) { | |
526 uint32_t id = familyFace->uniqueID(); | |
527 SkFaceRec* rec = find_ft_face(id); | |
528 if (!rec) { | |
529 SkASSERT(false); | |
530 tf = CreateTypeface_(gDefaultfont,style); | |
531 } | |
532 else { | |
533 tf = CreateTypeface_(rec,style); | |
534 } | |
535 } | |
536 else { | |
537 tf = CreateTypeface_(familyName,style); | |
538 } | |
539 } | |
540 | |
541 if (NULL == tf) { | |
542 tf = CreateTypeface_(gDefaultfont,style); | |
543 } | |
544 return tf; | |
545 | |
546 } | |
547 | |
548 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { | |
549 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) | |
550 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; | |
551 else | |
552 return 0; // nothing to do | |
553 } | |
554 | |
555 int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { | |
556 return 0; | |
557 } | |
558 | |
559 void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { | |
560 tables[0] = NULL; // black gamma (e.g. exp=1.4) | |
561 tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) | |
562 } | |
OLD | NEW |