1 #include "Draw.h"
2
3 #define LLOG(x) // LOG(x)
4 #define LTIMING(x) // TIMING(x)
5
6 #if !defined(CUSTOM_FONTSYS) && !defined(PLATFORM_COCOA)
7
8 #ifdef PLATFORM_POSIX
9
10 #include <fontconfig/fontconfig.h>
11 #include <fontconfig/fcfreetype.h>
12
13 namespace Upp {
14
15 static FT_Library sFTlib;
16
17 EXITBLOCK
18 {
19 if(sFTlib)
20 FT_Done_FreeType(sFTlib);
21 }
22
23 bool sInitFt(void)
24 {
25 if(sFTlib)
26 return true;
27 return FT_Init_FreeType(&sFTlib) == 0;
28 }
29
CreateFcPattern(Font font)30 FcPattern *CreateFcPattern(Font font)
31 {
32 LTIMING("CreateXftFont");
33 int hg = abs(font.GetHeight());
34 if(hg == 0) hg = 10;
35 String face = font.GetFaceName();
36 FcPattern *p = FcPatternCreate();
37 FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face);
38 FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
39 FcPatternAddInteger(p, FC_PIXEL_SIZE, hg);
40 FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL);
41 FcPatternAddBool(p, FC_MINSPACE, 1);
42 FcConfigSubstitute(0, p, FcMatchPattern);
43 FcDefaultSubstitute(p);
44 FcResult result;
45 FcPattern *m = FcFontMatch(0, p, &result);
46 FcPatternDestroy(p);
47 return m;
48 }
49
CreateFTFace(const FcPattern * pattern,String * rpath)50 FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) {
51 FT_Face face = NULL;
52
53 double dsize;
54 double aspect;
55 FcChar8 *filename;
56
57 if(!sInitFt())
58 return NULL;
59
60 if(FcPatternGetString(pattern, FC_FILE, 0, &filename) != FcResultMatch)
61 return NULL;
62 if(rpath)
63 *rpath = (const char *)filename;
64
65 if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch)
66 dsize = 16;
67
68 if (FcPatternGetDouble(pattern, FC_ASPECT, 0, &aspect) != FcResultMatch)
69 aspect = 1.0;
70
71 FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0);
72 FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0);
73
74 if(FT_New_Face(sFTlib, (const char *)filename, 0, &face))
75 return NULL;
76
77 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
78 return face;
79 }
80
81 #define FONTCACHE 37
82
83 struct FtFaceEntry {
84 Font font;
85 FT_Face face;
86 String path;
87 };
88
89 FT_Face (*FTFaceXft)(Font fnt, String *rpath);
90
FTFace(Font fnt,String * rpath=NULL)91 FT_Face FTFace(Font fnt, String *rpath = NULL)
92 {
93 LTIMING("FTFace");
94 if(FTFaceXft)
95 return (*FTFaceXft)(fnt, rpath);
96 static FtFaceEntry ft_cache[FONTCACHE];
97 ONCELOCK {
98 for(int i = 0; i < FONTCACHE; i++)
99 ft_cache[i].font.Height(-30000);
100 }
101 FtFaceEntry be;
102 be = ft_cache[0];
103 for(int i = 0; i < FONTCACHE; i++) {
104 FtFaceEntry e = ft_cache[i];
105 if(i)
106 ft_cache[i] = be;
107 if(e.font == fnt) {
108 if(rpath)
109 *rpath = e.path;
110 if(i)
111 ft_cache[0] = e;
112 return e.face;
113 }
114 be = e;
115 }
116 LTIMING("FTFace2");
117 if(be.face) {
118 LLOG("Removing " << be.font << " - " << (void *)be.face);
119 FT_Done_Face(be.face);
120 }
121 be.font = fnt;
122 FcPattern *p = CreateFcPattern(fnt);
123 be.face = CreateFTFace(p, &be.path);
124 FcPatternDestroy(p);
125 ft_cache[0] = be;
126 if(rpath)
127 *rpath = be.path;
128 return be.face;
129 }
130
131 CommonFontInfo (*GetFontInfoSysXft)(Font font);
132
GetFontInfoSys(Font font)133 CommonFontInfo GetFontInfoSys(Font font)
134 {
135 sInitFt();
136 if(GetFontInfoSysXft)
137 return (*GetFontInfoSysXft)(font);
138 CommonFontInfo fi;
139 String path;
140 FT_Face face = FTFace(font, &path);
141 if(face) {
142 fi.ascent = face->size->metrics.ascender >> 6;
143 fi.descent = -(face->size->metrics.descender >> 6);
144 fi.external = (face->size->metrics.height >> 6) - fi.ascent - fi.descent;
145 fi.internal = 0;
146 fi.overhang = 0;
147 fi.maxwidth = face->size->metrics.max_advance >> 6;
148 fi.avewidth = fi.maxwidth;
149 fi.default_char = '?';
150 fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH;
151 fi.ttf = path.EndsWith(".ttf") || path.EndsWith(".otf");
152 if(path.GetCount() < 250)
153 strcpy(fi.path, ~path);
154 else
155 *fi.path = 0;
156 }
157 return fi;
158 }
159
160 #define FLOOR(x) ((x) & -64)
161 #define CEIL(x) (((x)+63) & -64)
162 #define TRUNC(x) ((x) >> 6)
163 #define ROUND(x) (((x)+32) & -64)
164
165 GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr);
166
167 #ifdef flagLINUXGL
168 #include <LinuxGl/FontGl.h>
169 #include <LinuxGl/ResGl.h>
GetGlyphInfoSys(Font font,int chr)170 GlyphInfo GetGlyphInfoSys(Font font, int chr)
171 {
172 static GlyphInfo gi;
173 const OpenGLFont& fi = resources.GetFont(font);
174 gi.width = chr < fi.chars.GetCount()
175 ? int(fi.chars[chr].xadvance * fi.scale + 0.5f)
176 : 0;
177 gi.lspc = 0;
178 gi.rspc = 0;
179 return gi;
180 }
181 #else
GetGlyphInfoSys(Font font,int chr)182 GlyphInfo GetGlyphInfoSys(Font font, int chr)
183 {
184 LTIMING("GetGlyphInfoSys");
185 GlyphInfo gi;
186 FT_Face face = FTFace(font, NULL);
187 gi.lspc = gi.rspc = 0;
188 gi.width = 0x8000;
189 LLOG("GetGlyphInfoSys " << font << " " << (char)chr << " " << FormatIntHex(chr));
190 if(face) {
191 LTIMING("GetGlyphInfoSys 2");
192 int glyph_index = FT_Get_Char_Index(face, chr);
193 if(glyph_index) {
194 // if(GetGlyphInfoSysXft)
195 // return (*GetGlyphInfoSysXft)(font, chr);
196 if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP) == 0 ||
197 FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) {
198 FT_Glyph_Metrics& m = face->glyph->metrics;
199 int left = FLOOR(m.horiBearingX);
200 int width = TRUNC(CEIL(m.horiBearingX + m.width) - left);
201 gi.width = TRUNC(ROUND(face->glyph->advance.x));
202 gi.lspc = TRUNC(left);
203 gi.rspc = gi.width - width - gi.lspc;
204 gi.glyphi = glyph_index;
205 }
206 }
207 }
208 return gi;
209 }
210 #endif
211
GetAllFacesSys()212 Vector<FaceInfo> GetAllFacesSys()
213 {
214 static const char *basic_fonts[] = {
215 "sans-serif",
216 "serif",
217 "sans-serif",
218 "monospace",
219 };
220
221 Vector<FaceInfo> list;
222 for(int i = 0; i < __countof(basic_fonts); i++) {
223 FaceInfo& fi = list.Add();
224 fi.name = basic_fonts[i];
225 fi.info = Font::SCALEABLE;
226 if(i == Font::SERIF)
227 fi.info |= Font::SERIFSTYLE;
228 if(i == Font::MONOSPACE)
229 fi.info |= Font::FIXEDPITCH;
230 }
231 FcPattern *p = FcPatternCreate();
232 FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_SPACING, FC_SCALABLE, (void *)0);
233 FcFontSet *fs = FcFontList(NULL, p, os);
234 FcPatternDestroy(p);
235 FcObjectSetDestroy(os);
236 for(int i = 0; i < fs->nfont; i++) {
237 FcChar8 *family = NULL;
238 FcPattern *pt = fs->fonts[i];
239 if(FcPatternGetString(pt, FC_FAMILY, 0, &family) == 0 && family) {
240 FaceInfo& fi = list.Add();
241 fi.name = (const char *)family;
242 fi.info = 0;
243 int iv;
244 if(FcPatternGetInteger(pt, FC_SPACING, 0, &iv) == 0 && iv == FC_MONO)
245 fi.info |= Font::FIXEDPITCH;
246 FcBool bv;
247 if(FcPatternGetBool(pt, FC_SCALABLE, 0, &bv) == 0 && bv)
248 fi.info |= Font::SCALEABLE;
249 String h = ToLower(fi.name);
250 if(h.Find("serif") >= 0 && h.Find("sans") < 0)
251 fi.info |= Font::SERIFSTYLE;
252 if(h.Find("script") >= 0)
253 fi.info |= Font::SCRIPTSTYLE;
254 }
255 }
256 FcFontSetDestroy(fs);
257 return list;
258 }
259
GetFontDataSys(Font font)260 String GetFontDataSys(Font font)
261 {
262 return LoadFile(font.Fi().path);
263 }
264
ft_dbl(int p)265 static inline double ft_dbl(int p)
266 {
267 return double(p) / 64.0;
268 }
269
270 struct ConvertOutlinePoint {
271 bool sheer;
272 double xx;
273 double yy;
274
operator ()Upp::ConvertOutlinePoint275 Pointf operator()(int x, int y) {
276 double fy = ft_dbl(y);
277 return Pointf(ft_dbl(x) + xx + (sheer ? 0.2 * fy : 0), yy - fy);
278 }
279 };
280
RenderOutline(const FT_Outline & outline,FontGlyphConsumer & path,double xx,double yy,bool sheer)281 bool RenderOutline(const FT_Outline& outline, FontGlyphConsumer& path, double xx, double yy, bool sheer)
282 {
283 ConvertOutlinePoint cp;
284 cp.xx = xx;
285 cp.yy = yy;
286 cp.sheer = sheer;
287
288 FT_Vector v_last;
289 FT_Vector v_control;
290 FT_Vector v_start;
291 FT_Vector* point;
292 FT_Vector* limit;
293 char* tags;
294 int n; // index of contour in outline
295 char tag; // current point's state
296 int first = 0; // index of first point in contour
297 for(n = 0; n < outline.n_contours; n++) {
298 int last = outline.contours[n];
299 limit = outline.points + last;
300 v_start = outline.points[first];
301 v_last = outline.points[last];
302 v_control = v_start;
303 point = outline.points + first;
304 tags = outline.tags + first;
305 tag = FT_CURVE_TAG(tags[0]);
306 if(tag == FT_CURVE_TAG_CUBIC) return false;
307 if(tag == FT_CURVE_TAG_CONIC) {
308 if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) {
309 // start at last point if it is on the curve
310 v_start = v_last;
311 limit--;
312 }
313 else {
314 // if both first and last points are conic,
315 // start at their middle and record its position
316 // for closure
317 v_start.x = (v_start.x + v_last.x) / 2;
318 v_start.y = (v_start.y + v_last.y) / 2;
319 v_last = v_start;
320 }
321 point--;
322 tags--;
323 }
324 path.Move(cp(v_start.x, v_start.y));
325 while(point < limit) {
326 point++;
327 tags++;
328
329 tag = FT_CURVE_TAG(tags[0]);
330 switch(tag) {
331 case FT_CURVE_TAG_ON:
332 path.Line(cp(point->x, point->y));
333 continue;
334 case FT_CURVE_TAG_CONIC:
335 v_control.x = point->x;
336 v_control.y = point->y;
337 Do_Conic:
338 if(point < limit) {
339 FT_Vector vec;
340 FT_Vector v_middle;
341 point++;
342 tags++;
343 tag = FT_CURVE_TAG(tags[0]);
344 vec.x = point->x;
345 vec.y = point->y;
346 if(tag == FT_CURVE_TAG_ON) {
347 path.Quadratic(cp(v_control.x, v_control.y), cp(vec.x, vec.y));
348 continue;
349 }
350 if(tag != FT_CURVE_TAG_CONIC) return false;
351 v_middle.x = (v_control.x + vec.x) / 2;
352 v_middle.y = (v_control.y + vec.y) / 2;
353 path.Quadratic(cp(v_control.x, v_control.y), cp(v_middle.x, v_middle.y));
354 v_control = vec;
355 goto Do_Conic;
356 }
357 path.Quadratic(cp(v_control.x, v_control.y), cp(v_start.x, v_start.y));
358 goto Close;
359
360 default:
361 FT_Vector vec1, vec2;
362 if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
363 return false;
364 vec1.x = point[0].x;
365 vec1.y = point[0].y;
366 vec2.x = point[1].x;
367 vec2.y = point[1].y;
368 point += 2;
369 tags += 2;
370 if(point <= limit) {
371 FT_Vector vec;
372 vec.x = point->x;
373 vec.y = point->y;
374 path.Cubic(cp(vec1.x, vec1.y), cp(vec2.x, vec2.y), cp(vec.x, vec.y));
375 continue;
376 }
377 path.Cubic(cp(vec1.x, vec1.y), cp(vec2.x, vec2.y), cp(v_start.x, v_start.y));
378 goto Close;
379 }
380 }
381 Close:
382 path.Close();
383 first = last + 1;
384 }
385 return true;
386 }
387
RenderCharacterSys(FontGlyphConsumer & sw,double x,double y,int ch,Font fnt)388 void RenderCharacterSys(FontGlyphConsumer& sw, double x, double y, int ch, Font fnt)
389 {
390 FT_Face face = FTFace(fnt, NULL);
391 int glyph_index = FT_Get_Char_Index(face, ch);
392 if(glyph_index && FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0)
393 RenderOutline(face->glyph->outline, sw, x, y + fnt.GetAscent(),
394 fnt.IsItalic() && !(face->style_flags & FT_STYLE_FLAG_ITALIC));
395 }
396
397 }
398
399 #endif
400
401 #endif
402