Line data Source code
1 :
2 : /*
3 : * Copyright 2012 Mozilla Foundation
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 "cairo.h"
10 : #include "cairo-ft.h"
11 :
12 : #include "SkFontHost_FreeType_common.h"
13 :
14 : #include "SkAdvancedTypefaceMetrics.h"
15 : #include "SkFDot6.h"
16 : #include "SkPath.h"
17 : #include "SkScalerContext.h"
18 : #include "SkTypefaceCache.h"
19 :
20 : #include <cmath>
21 :
22 : #include <ft2build.h>
23 : #include FT_FREETYPE_H
24 : #include FT_OUTLINE_H
25 :
26 : // for FT_GlyphSlot_Embolden
27 : #ifdef FT_SYNTHESIS_H
28 : #include FT_SYNTHESIS_H
29 : #endif
30 :
31 : // for FT_Library_SetLcdFilter
32 : #ifdef FT_LCD_FILTER_H
33 : #include FT_LCD_FILTER_H
34 : #else
35 : typedef enum FT_LcdFilter_
36 : {
37 : FT_LCD_FILTER_NONE = 0,
38 : FT_LCD_FILTER_DEFAULT = 1,
39 : FT_LCD_FILTER_LIGHT = 2,
40 : FT_LCD_FILTER_LEGACY = 16,
41 : } FT_LcdFilter;
42 : #endif
43 :
44 : // If compiling with FreeType before 2.5.0
45 : #ifndef FT_LOAD_COLOR
46 : # define FT_LOAD_COLOR ( 1L << 20 )
47 : # define FT_PIXEL_MODE_BGRA 7
48 : #endif
49 :
50 : #ifndef SK_CAN_USE_DLOPEN
51 : #define SK_CAN_USE_DLOPEN 1
52 : #endif
53 : #if SK_CAN_USE_DLOPEN
54 : #include <dlfcn.h>
55 : #endif
56 :
57 : #ifndef SK_FONTHOST_CAIRO_STANDALONE
58 : #define SK_FONTHOST_CAIRO_STANDALONE 1
59 : #endif
60 :
61 : static cairo_user_data_key_t kSkTypefaceKey;
62 :
63 : static bool gFontHintingEnabled = true;
64 : static FT_Error (*gSetLcdFilter)(FT_Library, FT_LcdFilter) = nullptr;
65 : static void (*gGlyphSlotEmbolden)(FT_GlyphSlot) = nullptr;
66 :
67 3 : void SkInitCairoFT(bool fontHintingEnabled)
68 : {
69 3 : gFontHintingEnabled = fontHintingEnabled;
70 : #if SK_CAN_USE_DLOPEN
71 3 : gSetLcdFilter = (FT_Error (*)(FT_Library, FT_LcdFilter))dlsym(RTLD_DEFAULT, "FT_Library_SetLcdFilter");
72 3 : gGlyphSlotEmbolden = (void (*)(FT_GlyphSlot))dlsym(RTLD_DEFAULT, "FT_GlyphSlot_Embolden");
73 : #else
74 : gSetLcdFilter = &FT_Library_SetLcdFilter;
75 : gGlyphSlotEmbolden = &FT_GlyphSlot_Embolden;
76 : #endif
77 : // FT_Library_SetLcdFilter may be provided but have no effect if FreeType
78 : // is built without FT_CONFIG_OPTION_SUBPIXEL_RENDERING.
79 6 : if (gSetLcdFilter &&
80 6 : gSetLcdFilter(nullptr, FT_LCD_FILTER_NONE) == FT_Err_Unimplemented_Feature) {
81 0 : gSetLcdFilter = nullptr;
82 : }
83 3 : }
84 :
85 : #ifndef CAIRO_HAS_FC_FONT
86 : typedef struct _FcPattern FcPattern;
87 : #endif
88 :
89 : class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base {
90 : public:
91 : SkScalerContext_CairoFT(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc,
92 : cairo_font_face_t* fontFace, FcPattern* pattern);
93 : virtual ~SkScalerContext_CairoFT();
94 :
95 2 : bool isValid() const {
96 2 : return fScaledFont != nullptr;
97 : }
98 :
99 : protected:
100 : virtual unsigned generateGlyphCount() override;
101 : virtual uint16_t generateCharToGlyph(SkUnichar uniChar) override;
102 : virtual void generateAdvance(SkGlyph* glyph) override;
103 : virtual void generateMetrics(SkGlyph* glyph) override;
104 : virtual void generateImage(const SkGlyph& glyph) override;
105 : virtual void generatePath(const SkGlyphID glyphID, SkPath* path) override;
106 : virtual void generateFontMetrics(SkPaint::FontMetrics* metrics) override;
107 : virtual SkUnichar generateGlyphToChar(uint16_t glyph) override;
108 :
109 : private:
110 : bool computeShapeMatrix(const SkMatrix& m);
111 : void prepareGlyph(FT_GlyphSlot glyph);
112 : void fixVerticalLayoutBearing(FT_GlyphSlot glyph);
113 :
114 : #ifdef CAIRO_HAS_FC_FONT
115 : void parsePattern(FcPattern* pattern);
116 : #endif
117 :
118 : cairo_scaled_font_t* fScaledFont;
119 : FT_Int32 fLoadGlyphFlags;
120 : FT_LcdFilter fLcdFilter;
121 : SkScalar fScaleX;
122 : SkScalar fScaleY;
123 : SkMatrix fShapeMatrix;
124 : FT_Matrix fShapeMatrixFT;
125 : bool fHaveShape;
126 : };
127 :
128 : class CairoLockedFTFace {
129 : public:
130 122 : CairoLockedFTFace(cairo_scaled_font_t* scaledFont)
131 122 : : fScaledFont(scaledFont)
132 122 : , fFace(cairo_ft_scaled_font_lock_face(scaledFont))
133 122 : {}
134 :
135 122 : ~CairoLockedFTFace()
136 122 : {
137 122 : cairo_ft_scaled_font_unlock_face(fScaledFont);
138 122 : }
139 :
140 122 : FT_Face getFace()
141 : {
142 122 : return fFace;
143 : }
144 :
145 : private:
146 : cairo_scaled_font_t* fScaledFont;
147 : FT_Face fFace;
148 : };
149 :
150 120 : template<typename T> static bool isLCD(const T& rec) {
151 120 : return SkMask::kLCD16_Format == rec.fMaskFormat;
152 : }
153 :
154 21 : static bool bothZero(SkScalar a, SkScalar b) {
155 21 : return 0 == a && 0 == b;
156 : }
157 :
158 : // returns false if there is any non-90-rotation or skew
159 21 : static bool isAxisAligned(const SkScalerContext::Rec& rec) {
160 63 : return 0 == rec.fPreSkewX &&
161 21 : (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
162 21 : bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
163 : }
164 :
165 : class SkCairoFTTypeface : public SkTypeface {
166 : public:
167 2 : static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, FT_Face face,
168 : FcPattern* pattern = nullptr) {
169 2 : SkASSERT(fontFace != nullptr);
170 2 : SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT);
171 2 : SkASSERT(face != nullptr);
172 :
173 2 : SkFontStyle style(face->style_flags & FT_STYLE_FLAG_BOLD ?
174 : SkFontStyle::kBold_Weight : SkFontStyle::kNormal_Weight,
175 : SkFontStyle::kNormal_Width,
176 2 : face->style_flags & FT_STYLE_FLAG_ITALIC ?
177 4 : SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
178 :
179 2 : bool isFixedWidth = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
180 :
181 2 : return new SkCairoFTTypeface(style, isFixedWidth, fontFace, pattern);
182 : }
183 :
184 0 : virtual SkStreamAsset* onOpenStream(int*) const override { return nullptr; }
185 :
186 : virtual SkAdvancedTypefaceMetrics*
187 0 : onGetAdvancedTypefaceMetrics(PerGlyphInfo,
188 : const uint32_t*, uint32_t) const override
189 : {
190 0 : SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedTypefaceMetrics unimplemented\n"));
191 0 : return nullptr;
192 : }
193 :
194 2 : virtual SkScalerContext* onCreateScalerContext(const SkScalerContextEffects& effects, const SkDescriptor* desc) const override
195 : {
196 : SkScalerContext_CairoFT* ctx =
197 4 : new SkScalerContext_CairoFT(sk_ref_sp(const_cast<SkCairoFTTypeface*>(this)),
198 4 : effects, desc, fFontFace, fPattern);
199 2 : if (!ctx->isValid()) {
200 0 : delete ctx;
201 0 : return nullptr;
202 : }
203 2 : return ctx;
204 : }
205 :
206 21 : virtual void onFilterRec(SkScalerContextRec* rec) const override
207 : {
208 : // No subpixel AA unless enabled in Fontconfig.
209 21 : if (!fPattern && isLCD(*rec)) {
210 0 : rec->fMaskFormat = SkMask::kA8_Format;
211 : }
212 :
213 : // rotated text looks bad with hinting, so we disable it as needed
214 21 : if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
215 0 : rec->setHinting(SkPaint::kNo_Hinting);
216 : }
217 :
218 : // Don't apply any gamma so that we match cairo-ft's results.
219 21 : rec->ignorePreBlend();
220 21 : }
221 :
222 0 : virtual int onGetVariationDesignPosition(
223 : SkFontArguments::VariationPosition::Coordinate coordinates[],
224 : int coordinateCount) const override
225 : {
226 0 : return -1;
227 : }
228 :
229 0 : virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const override
230 : {
231 0 : SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n"));
232 0 : }
233 :
234 0 : virtual int onCharsToGlyphs(void const*, SkTypeface::Encoding, uint16_t*, int) const override
235 : {
236 0 : return 0;
237 : }
238 :
239 0 : virtual int onCountGlyphs() const override
240 : {
241 0 : return 0;
242 : }
243 :
244 0 : virtual int onGetUPEM() const override
245 : {
246 0 : return 0;
247 : }
248 :
249 0 : virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override
250 : {
251 0 : return nullptr;
252 : }
253 :
254 0 : virtual void onGetFamilyName(SkString* familyName) const override
255 : {
256 0 : familyName->reset();
257 0 : }
258 :
259 0 : virtual int onGetTableTags(SkFontTableTag*) const override
260 : {
261 0 : return 0;
262 : }
263 :
264 0 : virtual size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override
265 : {
266 0 : return 0;
267 : }
268 :
269 : private:
270 :
271 2 : SkCairoFTTypeface(const SkFontStyle& style, bool isFixedWidth,
272 : cairo_font_face_t* fontFace, FcPattern* pattern)
273 2 : : SkTypeface(style, isFixedWidth)
274 : , fFontFace(fontFace)
275 2 : , fPattern(pattern)
276 : {
277 2 : cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, nullptr);
278 2 : cairo_font_face_reference(fFontFace);
279 : #ifdef CAIRO_HAS_FC_FONT
280 2 : if (fPattern) {
281 2 : FcPatternReference(fPattern);
282 : }
283 : #endif
284 2 : }
285 :
286 0 : ~SkCairoFTTypeface()
287 0 : {
288 0 : cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, nullptr, nullptr);
289 0 : cairo_font_face_destroy(fFontFace);
290 : #ifdef CAIRO_HAS_FC_FONT
291 0 : if (fPattern) {
292 0 : FcPatternDestroy(fPattern);
293 : }
294 : #endif
295 0 : }
296 :
297 : cairo_font_face_t* fFontFace;
298 : FcPattern* fPattern;
299 : };
300 :
301 21 : SkTypeface* SkCreateTypefaceFromCairoFTFontWithFontconfig(cairo_scaled_font_t* scaledFont, FcPattern* pattern)
302 : {
303 21 : cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(scaledFont);
304 21 : SkASSERT(cairo_font_face_status(fontFace) == CAIRO_STATUS_SUCCESS);
305 :
306 21 : SkTypeface* typeface = reinterpret_cast<SkTypeface*>(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey));
307 21 : if (typeface) {
308 19 : typeface->ref();
309 : } else {
310 4 : CairoLockedFTFace faceLock(scaledFont);
311 2 : if (FT_Face face = faceLock.getFace()) {
312 2 : typeface = SkCairoFTTypeface::CreateTypeface(fontFace, face, pattern);
313 2 : SkTypefaceCache::Add(typeface);
314 : }
315 : }
316 :
317 21 : return typeface;
318 : }
319 :
320 0 : SkTypeface* SkCreateTypefaceFromCairoFTFont(cairo_scaled_font_t* scaledFont)
321 : {
322 0 : return SkCreateTypefaceFromCairoFTFontWithFontconfig(scaledFont, nullptr);
323 : }
324 :
325 2 : SkScalerContext_CairoFT::SkScalerContext_CairoFT(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc,
326 2 : cairo_font_face_t* fontFace, FcPattern* pattern)
327 2 : : SkScalerContext_FreeType_Base(std::move(typeface), effects, desc)
328 2 : , fLcdFilter(FT_LCD_FILTER_NONE)
329 : {
330 : SkMatrix matrix;
331 2 : fRec.getSingleMatrix(&matrix);
332 :
333 : cairo_matrix_t fontMatrix, ctMatrix;
334 2 : cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0);
335 2 : cairo_matrix_init_identity(&ctMatrix);
336 :
337 2 : cairo_font_options_t *fontOptions = cairo_font_options_create();
338 2 : fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions);
339 2 : cairo_font_options_destroy(fontOptions);
340 :
341 2 : computeShapeMatrix(matrix);
342 :
343 2 : fRec.fFlags |= SkScalerContext::kEmbeddedBitmapText_Flag;
344 :
345 : #ifdef CAIRO_HAS_FC_FONT
346 2 : if (pattern) {
347 2 : parsePattern(pattern);
348 : }
349 : #endif
350 :
351 2 : FT_Int32 loadFlags = FT_LOAD_DEFAULT;
352 :
353 2 : if (SkMask::kBW_Format == fRec.fMaskFormat) {
354 0 : if (fRec.getHinting() == SkPaint::kNo_Hinting) {
355 0 : loadFlags |= FT_LOAD_NO_HINTING;
356 : } else {
357 0 : loadFlags = FT_LOAD_TARGET_MONO;
358 : }
359 0 : loadFlags |= FT_LOAD_MONOCHROME;
360 : } else {
361 2 : switch (fRec.getHinting()) {
362 : case SkPaint::kNo_Hinting:
363 0 : loadFlags |= FT_LOAD_NO_HINTING;
364 0 : break;
365 : case SkPaint::kSlight_Hinting:
366 2 : loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT
367 2 : break;
368 : case SkPaint::kNormal_Hinting:
369 0 : if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
370 0 : loadFlags |= FT_LOAD_FORCE_AUTOHINT;
371 : }
372 0 : break;
373 : case SkPaint::kFull_Hinting:
374 0 : if (isLCD(fRec)) {
375 0 : if (fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag) {
376 0 : loadFlags = FT_LOAD_TARGET_LCD_V;
377 : } else {
378 0 : loadFlags = FT_LOAD_TARGET_LCD;
379 : }
380 : }
381 0 : if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) {
382 0 : loadFlags |= FT_LOAD_FORCE_AUTOHINT;
383 : }
384 0 : break;
385 : default:
386 0 : SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting());
387 0 : break;
388 : }
389 : }
390 :
391 : // Disable autohinting to disable hinting even for "tricky" fonts.
392 2 : if (!gFontHintingEnabled) {
393 0 : loadFlags |= FT_LOAD_NO_AUTOHINT;
394 : }
395 :
396 2 : if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) {
397 0 : loadFlags |= FT_LOAD_NO_BITMAP;
398 : }
399 :
400 : // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct
401 : // advances, as fontconfig and cairo do.
402 : // See http://code.google.com/p/skia/issues/detail?id=222.
403 2 : loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
404 :
405 2 : if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
406 0 : loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
407 : }
408 :
409 2 : loadFlags |= FT_LOAD_COLOR;
410 :
411 2 : fLoadGlyphFlags = loadFlags;
412 2 : }
413 :
414 0 : SkScalerContext_CairoFT::~SkScalerContext_CairoFT()
415 : {
416 0 : cairo_scaled_font_destroy(fScaledFont);
417 0 : }
418 :
419 : #ifdef CAIRO_HAS_FC_FONT
420 2 : void SkScalerContext_CairoFT::parsePattern(FcPattern* pattern)
421 : {
422 : FcBool antialias, autohint, bitmap, embolden, hinting, vertical;
423 :
424 2 : if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &autohint) == FcResultMatch && autohint) {
425 0 : fRec.fFlags |= SkScalerContext::kForceAutohinting_Flag;
426 : }
427 2 : if (FcPatternGetBool(pattern, FC_EMBOLDEN, 0, &embolden) == FcResultMatch && embolden) {
428 0 : fRec.fFlags |= SkScalerContext::kEmbolden_Flag;
429 : }
430 2 : if (FcPatternGetBool(pattern, FC_VERTICAL_LAYOUT, 0, &vertical) == FcResultMatch && vertical) {
431 0 : fRec.fFlags |= SkScalerContext::kVertical_Flag;
432 : }
433 :
434 : // Match cairo-ft's handling of embeddedbitmap:
435 : // If AA is explicitly disabled, leave bitmaps enabled.
436 : // Otherwise, disable embedded bitmaps unless explicitly enabled.
437 2 : if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &antialias) == FcResultMatch && !antialias) {
438 0 : fRec.fMaskFormat = SkMask::kBW_Format;
439 2 : } else if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &bitmap) != FcResultMatch || !bitmap) {
440 0 : fRec.fFlags &= ~SkScalerContext::kEmbeddedBitmapText_Flag;
441 : }
442 :
443 2 : if (fRec.fMaskFormat != SkMask::kBW_Format) {
444 : int rgba;
445 4 : if (!isLCD(fRec) ||
446 2 : FcPatternGetInteger(pattern, FC_RGBA, 0, &rgba) != FcResultMatch) {
447 0 : rgba = FC_RGBA_UNKNOWN;
448 : }
449 2 : switch (rgba) {
450 : case FC_RGBA_RGB:
451 2 : break;
452 : case FC_RGBA_BGR:
453 0 : fRec.fFlags |= SkScalerContext::kLCD_BGROrder_Flag;
454 0 : break;
455 : case FC_RGBA_VRGB:
456 0 : fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag;
457 0 : break;
458 : case FC_RGBA_VBGR:
459 0 : fRec.fFlags |= SkScalerContext::kLCD_Vertical_Flag |
460 0 : SkScalerContext::kLCD_BGROrder_Flag;
461 0 : break;
462 : default:
463 0 : fRec.fMaskFormat = SkMask::kA8_Format;
464 0 : break;
465 : }
466 :
467 : int filter;
468 2 : if (isLCD(fRec)) {
469 2 : if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) != FcResultMatch) {
470 0 : filter = FC_LCD_LEGACY;
471 : }
472 2 : switch (filter) {
473 : case FC_LCD_NONE:
474 0 : fLcdFilter = FT_LCD_FILTER_NONE;
475 0 : break;
476 : case FC_LCD_DEFAULT:
477 2 : fLcdFilter = FT_LCD_FILTER_DEFAULT;
478 2 : break;
479 : case FC_LCD_LIGHT:
480 0 : fLcdFilter = FT_LCD_FILTER_LIGHT;
481 0 : break;
482 : case FC_LCD_LEGACY:
483 : default:
484 0 : fLcdFilter = FT_LCD_FILTER_LEGACY;
485 0 : break;
486 : }
487 : }
488 : }
489 :
490 2 : if (fRec.getHinting() != SkPaint::kNo_Hinting) {
491 : // Hinting was requested, so check if the fontconfig pattern needs to override it.
492 : // If hinting is either explicitly enabled by fontconfig or not configured, try to
493 : // parse the hint style. Otherwise, ensure hinting is disabled.
494 : int hintstyle;
495 2 : if (FcPatternGetBool(pattern, FC_HINTING, 0, &hinting) != FcResultMatch || hinting) {
496 2 : if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) {
497 0 : hintstyle = FC_HINT_FULL;
498 : }
499 : } else {
500 0 : hintstyle = FC_HINT_NONE;
501 : }
502 2 : switch (hintstyle) {
503 : case FC_HINT_NONE:
504 0 : fRec.setHinting(SkPaint::kNo_Hinting);
505 0 : break;
506 : case FC_HINT_SLIGHT:
507 2 : fRec.setHinting(SkPaint::kSlight_Hinting);
508 2 : break;
509 : case FC_HINT_MEDIUM:
510 : default:
511 0 : fRec.setHinting(SkPaint::kNormal_Hinting);
512 0 : break;
513 : case FC_HINT_FULL:
514 0 : fRec.setHinting(SkPaint::kFull_Hinting);
515 0 : break;
516 : }
517 : }
518 2 : }
519 : #endif
520 :
521 2 : bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m)
522 : {
523 : // Compute a shape matrix compatible with Cairo's _compute_transform.
524 : // Finds major/minor scales and uses them to normalize the transform.
525 2 : double scaleX = m.getScaleX();
526 2 : double skewX = m.getSkewX();
527 2 : double skewY = m.getSkewY();
528 2 : double scaleY = m.getScaleY();
529 2 : double det = scaleX * scaleY - skewY * skewX;
530 2 : if (!std::isfinite(det)) {
531 0 : fScaleX = fRec.fTextSize * fRec.fPreScaleX;
532 0 : fScaleY = fRec.fTextSize;
533 0 : fHaveShape = false;
534 0 : return false;
535 : }
536 2 : double major = det != 0.0 ? hypot(scaleX, skewY) : 0.0;
537 2 : double minor = major != 0.0 ? fabs(det) / major : 0.0;
538 : // Limit scales to be above 1pt.
539 2 : major = SkTMax(major, 1.0);
540 2 : minor = SkTMax(minor, 1.0);
541 :
542 : // If the font is not scalable, then choose the best available size.
543 4 : CairoLockedFTFace faceLock(fScaledFont);
544 2 : FT_Face face = faceLock.getFace();
545 2 : if (face && !FT_IS_SCALABLE(face)) {
546 0 : double bestDist = DBL_MAX;
547 0 : FT_Int bestSize = -1;
548 0 : for (FT_Int i = 0; i < face->num_fixed_sizes; i++) {
549 : // Distance is positive if strike is larger than desired size,
550 : // or negative if smaller. If previously a found smaller strike,
551 : // then prefer a larger strike. Otherwise, minimize distance.
552 0 : double dist = face->available_sizes[i].y_ppem / 64.0 - minor;
553 0 : if (bestDist < 0 ? dist >= bestDist : fabs(dist) <= bestDist) {
554 0 : bestDist = dist;
555 0 : bestSize = i;
556 : }
557 : }
558 0 : if (bestSize < 0) {
559 0 : fScaleX = fRec.fTextSize * fRec.fPreScaleX;
560 0 : fScaleY = fRec.fTextSize;
561 0 : fHaveShape = false;
562 0 : return false;
563 : }
564 0 : major = face->available_sizes[bestSize].x_ppem / 64.0;
565 0 : minor = face->available_sizes[bestSize].y_ppem / 64.0;
566 0 : fHaveShape = true;
567 : } else {
568 2 : fHaveShape = !m.isScaleTranslate();
569 : }
570 :
571 2 : fScaleX = SkDoubleToScalar(major);
572 2 : fScaleY = SkDoubleToScalar(minor);
573 :
574 2 : if (fHaveShape) {
575 : // Normalize the transform and convert to fixed-point.
576 0 : fShapeMatrix = m;
577 0 : fShapeMatrix.preScale(SkDoubleToScalar(1.0 / major), SkDoubleToScalar(1.0 / minor));
578 :
579 0 : fShapeMatrixFT.xx = SkScalarToFixed(fShapeMatrix.getScaleX());
580 0 : fShapeMatrixFT.yx = SkScalarToFixed(-fShapeMatrix.getSkewY());
581 0 : fShapeMatrixFT.xy = SkScalarToFixed(-fShapeMatrix.getSkewX());
582 0 : fShapeMatrixFT.yy = SkScalarToFixed(fShapeMatrix.getScaleY());
583 : }
584 2 : return true;
585 : }
586 :
587 0 : unsigned SkScalerContext_CairoFT::generateGlyphCount()
588 : {
589 0 : CairoLockedFTFace faceLock(fScaledFont);
590 0 : return faceLock.getFace()->num_glyphs;
591 : }
592 :
593 0 : uint16_t SkScalerContext_CairoFT::generateCharToGlyph(SkUnichar uniChar)
594 : {
595 0 : CairoLockedFTFace faceLock(fScaledFont);
596 0 : return SkToU16(FT_Get_Char_Index(faceLock.getFace(), uniChar));
597 : }
598 :
599 0 : void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph)
600 : {
601 0 : generateMetrics(glyph);
602 0 : }
603 :
604 118 : void SkScalerContext_CairoFT::prepareGlyph(FT_GlyphSlot glyph)
605 : {
606 118 : if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
607 0 : gGlyphSlotEmbolden) {
608 0 : gGlyphSlotEmbolden(glyph);
609 : }
610 118 : if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
611 0 : fixVerticalLayoutBearing(glyph);
612 : }
613 118 : }
614 :
615 0 : void SkScalerContext_CairoFT::fixVerticalLayoutBearing(FT_GlyphSlot glyph)
616 : {
617 : FT_Vector vector;
618 0 : vector.x = glyph->metrics.vertBearingX - glyph->metrics.horiBearingX;
619 0 : vector.y = -glyph->metrics.vertBearingY - glyph->metrics.horiBearingY;
620 0 : if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
621 0 : if (fHaveShape) {
622 0 : FT_Vector_Transform(&vector, &fShapeMatrixFT);
623 : }
624 0 : FT_Outline_Translate(&glyph->outline, vector.x, vector.y);
625 0 : } else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
626 0 : glyph->bitmap_left += SkFDot6Floor(vector.x);
627 0 : glyph->bitmap_top += SkFDot6Floor(vector.y);
628 : }
629 0 : }
630 :
631 60 : void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
632 : {
633 60 : SkASSERT(fScaledFont != nullptr);
634 :
635 60 : glyph->zeroMetrics();
636 :
637 120 : CairoLockedFTFace faceLock(fScaledFont);
638 60 : FT_Face face = faceLock.getFace();
639 :
640 60 : FT_Error err = FT_Load_Glyph( face, glyph->getGlyphID(), fLoadGlyphFlags );
641 60 : if (err != 0) {
642 0 : return;
643 : }
644 :
645 60 : prepareGlyph(face->glyph);
646 :
647 60 : switch (face->glyph->format) {
648 : case FT_GLYPH_FORMAT_OUTLINE:
649 60 : if (!face->glyph->outline.n_contours) {
650 62 : break;
651 : }
652 :
653 : FT_BBox bbox;
654 58 : FT_Outline_Get_CBox(&face->glyph->outline, &bbox);
655 58 : bbox.xMin &= ~63;
656 58 : bbox.yMin &= ~63;
657 58 : bbox.xMax = (bbox.xMax + 63) & ~63;
658 58 : bbox.yMax = (bbox.yMax + 63) & ~63;
659 58 : glyph->fWidth = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin));
660 58 : glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
661 58 : glyph->fTop = -SkToS16(SkFDot6Floor(bbox.yMax));
662 58 : glyph->fLeft = SkToS16(SkFDot6Floor(bbox.xMin));
663 :
664 174 : if (isLCD(fRec) &&
665 174 : gSetLcdFilter &&
666 58 : (fLcdFilter == FT_LCD_FILTER_DEFAULT ||
667 0 : fLcdFilter == FT_LCD_FILTER_LIGHT)) {
668 58 : if (fRec.fFlags & kLCD_Vertical_Flag) {
669 0 : glyph->fTop -= 1;
670 0 : glyph->fHeight += 2;
671 : } else {
672 58 : glyph->fLeft -= 1;
673 58 : glyph->fWidth += 2;
674 : }
675 : }
676 58 : break;
677 : case FT_GLYPH_FORMAT_BITMAP:
678 0 : if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
679 0 : glyph->fMaskFormat = SkMask::kARGB32_Format;
680 : }
681 :
682 0 : if (isLCD(fRec)) {
683 0 : fRec.fMaskFormat = SkMask::kA8_Format;
684 : }
685 :
686 0 : if (fHaveShape) {
687 : // Ensure filtering is preserved when the bitmap is transformed.
688 : // Otherwise, the result will look horrifically aliased.
689 0 : if (fRec.fMaskFormat == SkMask::kBW_Format) {
690 0 : fRec.fMaskFormat = SkMask::kA8_Format;
691 : }
692 :
693 : // Apply the shape matrix to the glyph's bounding box.
694 : SkRect srcRect = SkRect::MakeXYWH(
695 0 : SkIntToScalar(face->glyph->bitmap_left),
696 0 : -SkIntToScalar(face->glyph->bitmap_top),
697 0 : SkIntToScalar(face->glyph->bitmap.width),
698 0 : SkIntToScalar(face->glyph->bitmap.rows));
699 : SkRect destRect;
700 0 : fShapeMatrix.mapRect(&destRect, srcRect);
701 0 : SkIRect glyphRect = destRect.roundOut();
702 0 : glyph->fWidth = SkToU16(glyphRect.width());
703 0 : glyph->fHeight = SkToU16(glyphRect.height());
704 0 : glyph->fTop = SkToS16(SkScalarRoundToInt(destRect.fTop));
705 0 : glyph->fLeft = SkToS16(SkScalarRoundToInt(destRect.fLeft));
706 : } else {
707 0 : glyph->fWidth = SkToU16(face->glyph->bitmap.width);
708 0 : glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
709 0 : glyph->fTop = -SkToS16(face->glyph->bitmap_top);
710 0 : glyph->fLeft = SkToS16(face->glyph->bitmap_left);
711 : }
712 0 : break;
713 : default:
714 0 : SkDEBUGFAIL("unknown glyph format");
715 0 : return;
716 : }
717 :
718 60 : if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
719 0 : glyph->fAdvanceX = -SkFDot6ToFloat(face->glyph->advance.x);
720 0 : glyph->fAdvanceY = SkFDot6ToFloat(face->glyph->advance.y);
721 : } else {
722 60 : glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x);
723 60 : glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y);
724 : }
725 : }
726 :
727 58 : void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph)
728 : {
729 58 : SkASSERT(fScaledFont != nullptr);
730 116 : CairoLockedFTFace faceLock(fScaledFont);
731 58 : FT_Face face = faceLock.getFace();
732 :
733 58 : FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), fLoadGlyphFlags);
734 :
735 58 : if (err != 0) {
736 0 : memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
737 0 : return;
738 : }
739 :
740 58 : prepareGlyph(face->glyph);
741 :
742 : bool useLcdFilter =
743 116 : face->glyph->format == FT_GLYPH_FORMAT_OUTLINE &&
744 116 : isLCD(glyph) &&
745 116 : gSetLcdFilter;
746 58 : if (useLcdFilter) {
747 58 : gSetLcdFilter(face->glyph->library, fLcdFilter);
748 : }
749 :
750 : SkMatrix matrix;
751 58 : if (face->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
752 0 : fHaveShape) {
753 0 : matrix = fShapeMatrix;
754 : } else {
755 58 : matrix.setIdentity();
756 : }
757 58 : generateGlyphImage(face, glyph, matrix);
758 :
759 58 : if (useLcdFilter) {
760 58 : gSetLcdFilter(face->glyph->library, FT_LCD_FILTER_NONE);
761 : }
762 : }
763 :
764 0 : void SkScalerContext_CairoFT::generatePath(const SkGlyphID glyphID, SkPath* path)
765 : {
766 0 : SkASSERT(fScaledFont != nullptr);
767 0 : CairoLockedFTFace faceLock(fScaledFont);
768 0 : FT_Face face = faceLock.getFace();
769 :
770 0 : SkASSERT(path);
771 :
772 0 : uint32_t flags = fLoadGlyphFlags;
773 0 : flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
774 0 : flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline)
775 :
776 0 : FT_Error err = FT_Load_Glyph(face, glyphID, flags);
777 :
778 0 : if (err != 0) {
779 0 : path->reset();
780 0 : return;
781 : }
782 :
783 0 : prepareGlyph(face->glyph);
784 :
785 0 : generateGlyphPath(face, path);
786 : }
787 :
788 2 : void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* metrics)
789 : {
790 2 : if (metrics) {
791 2 : memset(metrics, 0, sizeof(SkPaint::FontMetrics));
792 : }
793 2 : }
794 :
795 0 : SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph)
796 : {
797 0 : SkASSERT(fScaledFont != nullptr);
798 0 : CairoLockedFTFace faceLock(fScaledFont);
799 0 : FT_Face face = faceLock.getFace();
800 :
801 : FT_UInt glyphIndex;
802 0 : SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex);
803 0 : while (glyphIndex != 0) {
804 0 : if (glyphIndex == glyph) {
805 0 : return charCode;
806 : }
807 0 : charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
808 : }
809 :
810 0 : return 0;
811 : }
812 :
813 : ///////////////////////////////////////////////////////////////////////////////
814 :
815 : #include "SkFontMgr.h"
816 :
817 0 : sk_sp<SkFontMgr> SkFontMgr::Factory() {
818 : // todo
819 0 : return nullptr;
820 : }
821 :
|