]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | ******************************************************************************* | |
3 | * | |
4 | * © 2016 and later: Unicode, Inc. and others. | |
5 | * License & terms of use: http://www.unicode.org/copyright.html#License | |
6 | * | |
7 | ******************************************************************************* | |
8 | ******************************************************************************* | |
9 | * | |
10 | * Copyright (C) 1999-2007, International Business Machines | |
11 | * Corporation and others. All Rights Reserved. | |
12 | * | |
13 | ******************************************************************************* | |
14 | * file name: GnomeFontInstance.cpp | |
15 | * | |
16 | * created on: 08/30/2001 | |
17 | * created by: Eric R. Mader | |
18 | */ | |
19 | ||
20 | #include <gnome.h> | |
21 | #include <ft2build.h> | |
22 | #include FT_FREETYPE_H | |
23 | #include FT_GLYPH_H | |
24 | #include FT_RENDER_H | |
25 | #include FT_TRUETYPE_TABLES_H | |
26 | #include <cairo.h> | |
27 | #include <cairo-ft.h> | |
28 | ||
29 | #include "layout/LETypes.h" | |
30 | #include "layout/LESwaps.h" | |
31 | ||
32 | #include "GnomeFontInstance.h" | |
33 | #include "sfnt.h" | |
34 | #include "cmaps.h" | |
35 | ||
36 | GnomeSurface::GnomeSurface(GtkWidget *theWidget) | |
37 | : fWidget(theWidget) | |
38 | { | |
39 | fCairo = gdk_cairo_create(fWidget->window); | |
40 | } | |
41 | ||
42 | GnomeSurface::~GnomeSurface() | |
43 | { | |
44 | cairo_destroy(fCairo); | |
45 | } | |
46 | ||
47 | void GnomeSurface::drawGlyphs(const LEFontInstance *font, const LEGlyphID *glyphs, le_int32 count, | |
48 | const float *positions, le_int32 x, le_int32 y, le_int32 /*width*/, le_int32 /*height*/) | |
49 | { | |
50 | GnomeFontInstance *gFont = (GnomeFontInstance *) font; | |
51 | ||
52 | gFont->rasterizeGlyphs(fCairo, glyphs, count, positions, x, y); | |
53 | } | |
54 | ||
55 | GnomeFontInstance::GnomeFontInstance(FT_Library engine, const char *fontPathName, le_int16 pointSize, LEErrorCode &status) | |
56 | : FontTableCache(), fPointSize(pointSize), fUnitsPerEM(0), fAscent(0), fDescent(0), fLeading(0), | |
57 | fDeviceScaleX(1), fDeviceScaleY(1), fMapper(NULL) | |
58 | { | |
59 | FT_Error error; | |
60 | ||
61 | fFace = NULL; | |
62 | fCairoFace = NULL; | |
63 | ||
64 | error = FT_New_Face(engine, fontPathName, 0, &fFace); | |
65 | ||
66 | if (error != 0) { | |
67 | printf("OOPS! Got error code %d\n", error); | |
68 | status = LE_FONT_FILE_NOT_FOUND_ERROR; | |
69 | return; | |
70 | } | |
71 | ||
72 | // FIXME: what about the display resolution? | |
73 | fDeviceScaleX = ((float) 96) / 72; | |
74 | fDeviceScaleY = ((float) 96) / 72; | |
75 | ||
76 | error = FT_Set_Char_Size(fFace, 0, pointSize << 6, 92, 92); | |
77 | ||
78 | fCairoFace = cairo_ft_font_face_create_for_ft_face(fFace, 0); | |
79 | ||
80 | fUnitsPerEM = fFace->units_per_EM; | |
81 | ||
82 | fAscent = (le_int32) (yUnitsToPoints(fFace->ascender) * fDeviceScaleY); | |
83 | fDescent = (le_int32) -(yUnitsToPoints(fFace->descender) * fDeviceScaleY); | |
84 | fLeading = (le_int32) (yUnitsToPoints(fFace->height) * fDeviceScaleY) - fAscent - fDescent; | |
85 | ||
86 | // printf("Face = %s, unitsPerEM = %d, ascent = %d, descent = %d\n", fontPathName, fUnitsPerEM, fAscent, fDescent); | |
87 | ||
88 | if (error != 0) { | |
89 | status = LE_MEMORY_ALLOCATION_ERROR; | |
90 | return; | |
91 | } | |
92 | ||
93 | status = initMapper(); | |
94 | } | |
95 | ||
96 | GnomeFontInstance::~GnomeFontInstance() | |
97 | { | |
98 | cairo_font_face_destroy(fCairoFace); | |
99 | ||
100 | if (fFace != NULL) { | |
101 | FT_Done_Face(fFace); | |
102 | } | |
103 | } | |
104 | ||
105 | LEErrorCode GnomeFontInstance::initMapper() | |
106 | { | |
107 | LETag cmapTag = LE_CMAP_TABLE_TAG; | |
108 | const CMAPTable *cmap = (const CMAPTable *) readFontTable(cmapTag); | |
109 | ||
110 | if (cmap == NULL) { | |
111 | return LE_MISSING_FONT_TABLE_ERROR; | |
112 | } | |
113 | ||
114 | fMapper = CMAPMapper::createUnicodeMapper(cmap); | |
115 | ||
116 | if (fMapper == NULL) { | |
117 | return LE_MISSING_FONT_TABLE_ERROR; | |
118 | } | |
119 | ||
120 | return LE_NO_ERROR; | |
121 | } | |
122 | ||
123 | const void *GnomeFontInstance::getFontTable(LETag tableTag) const | |
124 | { | |
125 | return FontTableCache::find(tableTag); | |
126 | } | |
127 | ||
128 | const void *GnomeFontInstance::readFontTable(LETag tableTag) const | |
129 | { | |
130 | FT_ULong len = 0; | |
131 | FT_Byte *result = NULL; | |
132 | ||
133 | FT_Load_Sfnt_Table(fFace, tableTag, 0, NULL, &len); | |
134 | ||
135 | if (len > 0) { | |
136 | result = LE_NEW_ARRAY(FT_Byte, len); | |
137 | FT_Load_Sfnt_Table(fFace, tableTag, 0, result, &len); | |
138 | } | |
139 | ||
140 | return result; | |
141 | } | |
142 | ||
143 | void GnomeFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const | |
144 | { | |
145 | advance.fX = 0; | |
146 | advance.fY = 0; | |
147 | ||
148 | if (glyph >= 0xFFFE) { | |
149 | return; | |
150 | } | |
151 | ||
152 | FT_Error error; | |
153 | ||
154 | error = FT_Load_Glyph(fFace, glyph, FT_LOAD_DEFAULT); | |
155 | ||
156 | if (error != 0) { | |
157 | return; | |
158 | } | |
159 | ||
160 | advance.fX = fFace->glyph->metrics.horiAdvance >> 6; | |
161 | return; | |
162 | } | |
163 | ||
164 | le_bool GnomeFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const | |
165 | { | |
166 | FT_Error error; | |
167 | ||
168 | error = FT_Load_Glyph(fFace, glyph, FT_LOAD_DEFAULT); | |
169 | ||
170 | if (error != 0) { | |
171 | return FALSE; | |
172 | } | |
173 | ||
174 | if (pointNumber >= fFace->glyph->outline.n_points) { | |
175 | return FALSE; | |
176 | } | |
177 | ||
178 | point.fX = fFace->glyph->outline.points[pointNumber].x >> 6; | |
179 | point.fY = fFace->glyph->outline.points[pointNumber].y >> 6; | |
180 | ||
181 | return TRUE; | |
182 | } | |
183 | ||
184 | void GnomeFontInstance::rasterizeGlyphs(cairo_t *cairo, const LEGlyphID *glyphs, le_int32 glyphCount, const float *positions, | |
185 | le_int32 x, le_int32 y) const | |
186 | { | |
187 | cairo_glyph_t *glyph_t = LE_NEW_ARRAY(cairo_glyph_t, glyphCount); | |
188 | le_int32 in, out; | |
189 | ||
190 | for (in = 0, out = 0; in < glyphCount; in += 1) { | |
191 | TTGlyphID glyph = LE_GET_GLYPH(glyphs[in]); | |
192 | ||
193 | if (glyph < 0xFFFE) { | |
194 | glyph_t[out].index = glyph; | |
195 | glyph_t[out].x = x + positions[in*2]; | |
196 | glyph_t[out].y = y + positions[in*2 + 1]; | |
197 | ||
198 | out += 1; | |
199 | } | |
200 | } | |
201 | ||
202 | cairo_set_font_face(cairo, fCairoFace); | |
203 | cairo_set_font_size(cairo, getXPixelsPerEm() * getScaleFactorX()); | |
204 | cairo_show_glyphs(cairo, glyph_t, out); | |
205 | ||
206 | LE_DELETE_ARRAY(glyph_t); | |
207 | } |