1From: George Wright <george@mozilla.com>
2Date: Wed, 1 Aug 2012 16:43:15 -0400
3Subject: Bug 736276 - Add a new SkFontHost that takes a cairo_scaled_font_t r=karl
4
5
6diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in
7index 5ebbd2e..7c8cdbf 100644
8--- a/gfx/skia/Makefile.in
9+++ b/gfx/skia/Makefile.in
10@@ -60,15 +60,15 @@ VPATH += \
11 	$(NULL)
12
13 ifeq (android,$(MOZ_WIDGET_TOOLKIT))
14-OS_CXXFLAGS += $(CAIRO_FT_CFLAGS)
15+OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(CAIRO_FT_CFLAGS)
16 endif
17
18 ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
19-OS_CXXFLAGS += $(MOZ_PANGO_CFLAGS)
20+OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PANGO_CFLAGS) $(CAIRO_FT_CFLAGS)
21 endif
22
23 ifeq (qt,$(MOZ_WIDGET_TOOLKIT))
24-OS_CXXFLAGS += $(MOZ_PANGO_CFLAGS)
25+OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PANGO_CFLAGS) $(CAIRO_FT_CFLAGS)
26 ifeq (Linux,$(OS_TARGET))
27 DEFINES += -DSK_USE_POSIX_THREADS=1
28 endif
29diff --git a/gfx/skia/include/ports/SkTypeface_cairo.h b/gfx/skia/include/ports/SkTypeface_cairo.h
30new file mode 100644
31index 0000000..7e44f04
32--- /dev/null
33+++ b/gfx/skia/include/ports/SkTypeface_cairo.h
34@@ -0,0 +1,11 @@
35+#ifndef SkTypeface_cairo_DEFINED
36+#define SkTypeface_cairo_DEFINED
37+
38+#include <cairo.h>
39+
40+#include "SkTypeface.h"
41+
42+SK_API extern SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth);
43+
44+#endif
45+
46diff --git a/gfx/skia/moz.build b/gfx/skia/moz.build
47index 9ceba59..66efd52 100644
48--- a/gfx/skia/moz.build
49+++ b/gfx/skia/moz.build
50@@ -171,10 +171,12 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
51         'SkTime_win.cpp',
52     ]
53 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2':
54+    EXPORTS.skia += [
55+        'include/ports/SkTypeface_cairo.h',
56+    ]
57     CPP_SOURCES += [
58-        'SkFontHost_FreeType.cpp',
59+        'SkFontHost_cairo.cpp',
60         'SkFontHost_FreeType_common.cpp',
61-        'SkFontHost_linux.cpp',
62         'SkThread_pthread.cpp',
63         'SkThreadUtils_pthread.cpp',
64         'SkThreadUtils_pthread_linux.cpp',
65@@ -183,14 +185,15 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2':
66     ]
67 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
68     CPP_SOURCES += [
69-        'SkFontHost_FreeType.cpp',
70+        'SkFontHost_cairo.cpp',
71         'SkFontHost_FreeType_common.cpp',
72         'SkOSFile.cpp',
73     ]
74     if CONFIG['OS_TARGET'] == 'Linux':
75+        EXPORTS.skia += [
76+            'include/ports/SkTypeface_cairo.h',
77+        ]
78         CPP_SOURCES += [
79-            'SkFontHost_linux.cpp',
80-            'SkFontHost_tables.cpp',
81             'SkThread_pthread.cpp',
82             'SkThreadUtils_pthread.cpp',
83             'SkThreadUtils_pthread_linux.cpp',
84@@ -204,11 +207,13 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
85 # Separate 'if' from above, since the else below applies to all != 'android'
86 # toolkits.
87 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
88+    EXPORTS.skia += [
89+        'include/ports/SkTypeface_cairo.h',
90+    ]
91     CPP_SOURCES += [
92         'ashmem.cpp',
93         'SkDebug_android.cpp',
94-        'SkFontHost_android_old.cpp',
95-        'SkFontHost_FreeType.cpp',
96+        'SkFontHost_cairo.cpp',
97         'SkFontHost_FreeType_common.cpp',
98         'SkImageRef_ashmem.cpp',
99         'SkTime_Unix.cpp',
100diff --git a/gfx/skia/src/ports/SkFontHost_cairo.cpp b/gfx/skia/src/ports/SkFontHost_cairo.cpp
101new file mode 100644
102index 0000000..bb5b778
103--- /dev/null
104+++ b/gfx/skia/src/ports/SkFontHost_cairo.cpp
105@@ -0,0 +1,364 @@
106+
107+/*
108+ * Copyright 2012 Mozilla Foundation
109+ *
110+ * Use of this source code is governed by a BSD-style license that can be
111+ * found in the LICENSE file.
112+ */
113+
114+#include "cairo.h"
115+#include "cairo-ft.h"
116+
117+#include "SkFontHost_FreeType_common.h"
118+
119+#include "SkAdvancedTypefaceMetrics.h"
120+#include "SkFontHost.h"
121+#include "SkPath.h"
122+#include "SkScalerContext.h"
123+#include "SkTypefaceCache.h"
124+
125+#include <ft2build.h>
126+#include FT_FREETYPE_H
127+
128+static cairo_user_data_key_t kSkTypefaceKey;
129+
130+class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base {
131+public:
132+    SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc);
133+    virtual ~SkScalerContext_CairoFT();
134+
135+protected:
136+    virtual unsigned generateGlyphCount() SK_OVERRIDE;
137+    virtual uint16_t generateCharToGlyph(SkUnichar uniChar) SK_OVERRIDE;
138+    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
139+    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
140+    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
141+    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
142+    virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
143+                                     SkPaint::FontMetrics* my) SK_OVERRIDE;
144+    virtual SkUnichar generateGlyphToChar(uint16_t glyph) SK_OVERRIDE;
145+private:
146+    cairo_scaled_font_t* fScaledFont;
147+    uint32_t fLoadGlyphFlags;
148+};
149+
150+class CairoLockedFTFace {
151+public:
152+    CairoLockedFTFace(cairo_scaled_font_t* scaledFont)
153+        : fScaledFont(scaledFont)
154+        , fFace(cairo_ft_scaled_font_lock_face(scaledFont))
155+    {}
156+
157+    ~CairoLockedFTFace()
158+    {
159+        cairo_ft_scaled_font_unlock_face(fScaledFont);
160+    }
161+
162+    FT_Face getFace()
163+    {
164+        return fFace;
165+    }
166+
167+private:
168+    cairo_scaled_font_t* fScaledFont;
169+    FT_Face fFace;
170+};
171+
172+class SkCairoFTTypeface : public SkTypeface {
173+public:
174+    static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) {
175+        SkASSERT(fontFace != NULL);
176+        SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT);
177+
178+        SkFontID newId = SkTypefaceCache::NewFontID();
179+
180+        return SkNEW_ARGS(SkCairoFTTypeface, (fontFace, style, newId, isFixedWidth));
181+    }
182+
183+    cairo_font_face_t* getFontFace() {
184+        return fFontFace;
185+    }
186+
187+    virtual SkStream* onOpenStream(int*) const SK_OVERRIDE { return NULL; }
188+
189+    virtual SkAdvancedTypefaceMetrics*
190+        onGetAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::PerGlyphInfo,
191+                                     const uint32_t*, uint32_t) const SK_OVERRIDE
192+    {
193+        SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedTypefaceMetrics unimplemented\n"));
194+        return NULL;
195+    }
196+
197+    virtual SkScalerContext* onCreateScalerContext(const SkDescriptor* desc) const SK_OVERRIDE
198+    {
199+        return SkNEW_ARGS(SkScalerContext_CairoFT, (const_cast<SkCairoFTTypeface*>(this), desc));
200+    }
201+
202+    virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE
203+    {
204+        SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onFilterRec unimplemented\n"));
205+    }
206+
207+    virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE
208+    {
209+        SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n"));
210+    }
211+
212+
213+private:
214+
215+    SkCairoFTTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, SkFontID id, bool isFixedWidth)
216+        : SkTypeface(style, id, isFixedWidth)
217+        , fFontFace(fontFace)
218+    {
219+        cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, NULL);
220+        cairo_font_face_reference(fFontFace);
221+    }
222+
223+    ~SkCairoFTTypeface()
224+    {
225+        cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, NULL, NULL);
226+        cairo_font_face_destroy(fFontFace);
227+    }
228+
229+    cairo_font_face_t* fFontFace;
230+};
231+
232+SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth)
233+{
234+    SkTypeface* typeface = reinterpret_cast<SkTypeface*>(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey));
235+
236+    if (typeface) {
237+        typeface->ref();
238+    } else {
239+        typeface = SkCairoFTTypeface::CreateTypeface(fontFace, style, isFixedWidth);
240+        SkTypefaceCache::Add(typeface, style);
241+    }
242+
243+    return typeface;
244+}
245+
246+SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
247+                                     const char famillyName[],
248+                                     SkTypeface::Style style)
249+{
250+    SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented");
251+    return NULL;
252+}
253+
254+SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*)
255+{
256+    SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented");
257+    return NULL;
258+}
259+
260+SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*)
261+{
262+    SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented");
263+    return NULL;
264+}
265+
266+///////////////////////////////////////////////////////////////////////////////
267+
268+static bool isLCD(const SkScalerContext::Rec& rec) {
269+    switch (rec.fMaskFormat) {
270+        case SkMask::kLCD16_Format:
271+        case SkMask::kLCD32_Format:
272+            return true;
273+        default:
274+            return false;
275+    }
276+}
277+
278+///////////////////////////////////////////////////////////////////////////////
279+SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc)
280+    : SkScalerContext_FreeType_Base(typeface, desc)
281+{
282+    SkMatrix matrix;
283+    fRec.getSingleMatrix(&matrix);
284+
285+    cairo_font_face_t* fontFace = static_cast<SkCairoFTTypeface*>(typeface)->getFontFace();
286+
287+    cairo_matrix_t fontMatrix, ctMatrix;
288+    cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0);
289+    cairo_matrix_init_scale(&ctMatrix, 1.0, 1.0);
290+
291+    // We need to ensure that the font options match for hinting, as generateMetrics()
292+    // uses the fScaledFont which uses these font options
293+    cairo_font_options_t *fontOptions = cairo_font_options_create();
294+
295+    FT_Int32 loadFlags = FT_LOAD_DEFAULT;
296+
297+    if (SkMask::kBW_Format == fRec.fMaskFormat) {
298+        // See http://code.google.com/p/chromium/issues/detail?id=43252#c24
299+        loadFlags = FT_LOAD_TARGET_MONO;
300+        if (fRec.getHinting() == SkPaint::kNo_Hinting) {
301+            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE);
302+            loadFlags = FT_LOAD_NO_HINTING;
303+        }
304+    } else {
305+        switch (fRec.getHinting()) {
306+        case SkPaint::kNo_Hinting:
307+            loadFlags = FT_LOAD_NO_HINTING;
308+            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE);
309+            break;
310+        case SkPaint::kSlight_Hinting:
311+            loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
312+            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_SLIGHT);
313+            break;
314+        case SkPaint::kNormal_Hinting:
315+            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_MEDIUM);
316+            if (fRec.fFlags & SkScalerContext::kAutohinting_Flag) {
317+                loadFlags = FT_LOAD_FORCE_AUTOHINT;
318+            }
319+            break;
320+        case SkPaint::kFull_Hinting:
321+            cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_FULL);
322+            if (fRec.fFlags & SkScalerContext::kAutohinting_Flag) {
323+                loadFlags = FT_LOAD_FORCE_AUTOHINT;
324+            }
325+            if (isLCD(fRec)) {
326+                if (SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag)) {
327+                    loadFlags = FT_LOAD_TARGET_LCD_V;
328+                } else {
329+                    loadFlags = FT_LOAD_TARGET_LCD;
330+                }
331+            }
332+            break;
333+        default:
334+            SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting());
335+            break;
336+        }
337+    }
338+
339+    fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions);
340+
341+    if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) {
342+        loadFlags |= FT_LOAD_NO_BITMAP;
343+    }
344+
345+    // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct
346+    // advances, as fontconfig and cairo do.
347+    // See http://code.google.com/p/skia/issues/detail?id=222.
348+    loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
349+
350+    fLoadGlyphFlags = loadFlags;
351+}
352+
353+SkScalerContext_CairoFT::~SkScalerContext_CairoFT()
354+{
355+    cairo_scaled_font_destroy(fScaledFont);
356+}
357+
358+unsigned SkScalerContext_CairoFT::generateGlyphCount()
359+{
360+    CairoLockedFTFace faceLock(fScaledFont);
361+    return faceLock.getFace()->num_glyphs;
362+}
363+
364+uint16_t SkScalerContext_CairoFT::generateCharToGlyph(SkUnichar uniChar)
365+{
366+    CairoLockedFTFace faceLock(fScaledFont);
367+    return SkToU16(FT_Get_Char_Index(faceLock.getFace(), uniChar));
368+}
369+
370+void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph)
371+{
372+    generateMetrics(glyph);
373+}
374+
375+void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
376+{
377+    SkASSERT(fScaledFont != NULL);
378+    cairo_text_extents_t extents;
379+    cairo_glyph_t cairoGlyph = { glyph->getGlyphID(fBaseGlyphCount), 0.0, 0.0 };
380+    cairo_scaled_font_glyph_extents(fScaledFont, &cairoGlyph, 1, &extents);
381+
382+    glyph->fAdvanceX = SkDoubleToFixed(extents.x_advance);
383+    glyph->fAdvanceY = SkDoubleToFixed(extents.y_advance);
384+    glyph->fWidth = SkToU16(SkScalarCeil(extents.width));
385+    glyph->fHeight = SkToU16(SkScalarCeil(extents.height));
386+    glyph->fLeft = SkToS16(SkScalarCeil(extents.x_bearing));
387+    glyph->fTop = SkToS16(SkScalarCeil(extents.y_bearing));
388+    glyph->fLsbDelta = 0;
389+    glyph->fRsbDelta = 0;
390+}
391+
392+void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph)
393+{
394+    SkASSERT(fScaledFont != NULL);
395+    CairoLockedFTFace faceLock(fScaledFont);
396+    FT_Face face = faceLock.getFace();
397+
398+    FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags);
399+
400+    if (err != 0) {
401+        memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight);
402+        return;
403+    }
404+
405+    generateGlyphImage(face, glyph);
406+}
407+
408+void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path)
409+{
410+    SkASSERT(fScaledFont != NULL);
411+    CairoLockedFTFace faceLock(fScaledFont);
412+    FT_Face face = faceLock.getFace();
413+
414+    SkASSERT(&glyph && path);
415+
416+    uint32_t flags = fLoadGlyphFlags;
417+    flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
418+    flags &= ~FT_LOAD_RENDER;   // don't scan convert (we just want the outline)
419+
420+    FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(fBaseGlyphCount), flags);
421+
422+    if (err != 0) {
423+        path->reset();
424+        return;
425+    }
426+
427+    generateGlyphPath(face, path);
428+}
429+
430+void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* mx,
431+                                                  SkPaint::FontMetrics* my)
432+{
433+    SkDEBUGCODE(SkDebugf("SkScalerContext_CairoFT::generateFontMetrics unimplemented\n"));
434+}
435+
436+SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph)
437+{
438+    SkASSERT(fScaledFont != NULL);
439+    CairoLockedFTFace faceLock(fScaledFont);
440+    FT_Face face = faceLock.getFace();
441+
442+    FT_UInt glyphIndex;
443+    SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex);
444+    while (glyphIndex != 0) {
445+        if (glyphIndex == glyph) {
446+            return charCode;
447+        }
448+        charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
449+    }
450+
451+    return 0;
452+}
453+
454+#ifdef SK_BUILD_FOR_ANDROID
455+SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID,
456+                                         SkFontID origFontID) {
457+    return NULL;
458+}
459+#endif
460+
461+///////////////////////////////////////////////////////////////////////////////
462+
463+#include "SkFontMgr.h"
464+
465+SkFontMgr* SkFontMgr::Factory() {
466+    // todo
467+    return NULL;
468+}
469+
470--
4711.7.11.7
472
473