2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2004--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #define PANGO_ENABLE_BACKEND // ugh, why necessary?
21 #include <pango/pangoft2.h>
22 #include <freetype/ftxf86.h>
29 #include "pango-font.hh"
30 #include "dimensions.hh"
31 #include "file-name.hh"
32 #include "international.hh"
33 #include "lookup.hh" // debugging
35 #include "string-convert.hh"
37 #include "all-font-metrics.hh"
38 #include "program-option.hh"
43 Pango_font::Pango_font (PangoFT2FontMap
* /* fontmap */,
44 PangoFontDescription
const *description
,
47 physical_font_tab_
= scm_c_make_hash_table (11);
48 PangoDirection pango_dir
= PANGO_DIRECTION_LTR
;
49 context_
= pango_ft2_get_context (PANGO_RESOLUTION
,
52 pango_description_
= pango_font_description_copy (description
);
53 attribute_list_
= pango_attr_list_new ();
55 // urgh. I don't understand this. Why isn't this 1/(scale *
56 // resolution * output_scale)
59 output_scale_
= output_scale
;
61 / (Real (PANGO_SCALE
) * Real (PANGO_RESOLUTION
) * output_scale
);
63 // ugh. Should make this configurable.
64 pango_context_set_language (context_
, pango_language_from_string ("en_US"));
65 pango_context_set_base_dir (context_
, pango_dir
);
66 pango_context_set_font_description (context_
, description
);
69 Pango_font::~Pango_font ()
71 pango_font_description_free (pango_description_
);
72 g_object_unref (context_
);
73 pango_attr_list_unref (attribute_list_
);
77 Pango_font::register_font_file (string filename
,
81 scm_hash_set_x (physical_font_tab_
,
82 ly_string2scm (ps_name
),
83 scm_list_2 (ly_string2scm (filename
),
84 scm_from_int (face_index
)));
88 Pango_font::derived_mark () const
90 scm_gc_mark (physical_font_tab_
);
94 get_glyph_index_name (char *s
,
97 sprintf (s
, "glyphIndex%lX", code
);
101 get_unicode_name (char *s
,
105 sprintf (s
, "u%lX", code
);
107 sprintf (s
, "uni%04lX", code
);
111 Pango_font::pango_item_string_stencil (PangoItem
const *item
,
113 bool tight_bbox
) const
115 const int GLYPH_NAME_LEN
= 256;
116 char glyph_name
[GLYPH_NAME_LEN
];
117 PangoAnalysis
const *pa
= &(item
->analysis
);
118 PangoGlyphString
*pgs
= pango_glyph_string_new ();
120 pango_shape (str
.c_str () + item
->offset
,
121 item
->length
, (PangoAnalysis
*) pa
, pgs
);
123 PangoRectangle logical_rect
;
124 PangoRectangle ink_rect
;
125 pango_glyph_string_extents (pgs
, pa
->font
, &ink_rect
, &logical_rect
);
127 PangoFcFont
*fcfont
= G_TYPE_CHECK_INSTANCE_CAST (pa
->font
,
131 FT_Face ftface
= pango_fc_font_lock_face (fcfont
);
133 PangoRectangle
const *which_rect
= tight_bbox
? &ink_rect
136 Box
b (Interval (PANGO_LBEARING (logical_rect
),
137 PANGO_RBEARING (logical_rect
)),
138 Interval (-PANGO_DESCENT (*which_rect
),
139 PANGO_ASCENT (*which_rect
)));
142 char const *ps_name_str0
= FT_Get_Postscript_Name (ftface
);
143 FcPattern
*fcpat
= fcfont
->font_pattern
;
145 FcChar8
*file_name_as_ptr
= 0;
146 FcPatternGetString (fcpat
, FC_FILE
, 0, &file_name_as_ptr
);
148 // due to a bug in FreeType 2.3.7 and earlier we can't use
149 // ftface->face_index; it is always zero for some font formats,
150 // in particular TTCs which we are interested in
152 FcPatternGetInteger (fcpat
, FC_INDEX
, 0, &face_index
);
155 if (file_name_as_ptr
)
156 // Normalize file name.
157 file_name
= File_name ((char const *)file_name_as_ptr
).to_string ();
159 SCM glyph_exprs
= SCM_EOL
;
160 SCM
*tail
= &glyph_exprs
;
162 Index_to_charcode_map
const *cmap
= 0;
163 bool has_glyph_names
= ftface
->face_flags
& FT_FACE_FLAG_GLYPH_NAMES
;
164 if (!has_glyph_names
)
165 cmap
= all_fonts_global
->get_index_to_charcode_map (
166 file_name
, face_index
, ftface
);
168 bool is_ttf
= string (FT_Get_X11_Font_Format (ftface
)) == "TrueType";
169 bool cid_keyed
= false;
171 for (int i
= 0; i
< pgs
->num_glyphs
; i
++)
173 PangoGlyphInfo
*pgi
= pgs
->glyphs
+ i
;
175 PangoGlyph pg
= pgi
->glyph
;
176 PangoGlyphGeometry ggeo
= pgi
->geometry
;
178 glyph_name
[0] = '\0';
181 int errorcode
= FT_Get_Glyph_Name (ftface
, pg
, glyph_name
,
185 _f ("FT_Get_Glyph_Name () error: %s",
186 freetype_error_string (errorcode
).c_str ()));
189 SCM char_id
= SCM_EOL
;
190 if (glyph_name
[0] == '\0'
193 && cmap
->find (pg
) != cmap
->end ())
195 FT_ULong char_code
= cmap
->find (pg
)->second
;
196 get_unicode_name (glyph_name
, char_code
);
199 if (glyph_name
[0] == '\0' && has_glyph_names
)
202 _f ("Glyph has no name, but font supports glyph naming.\n"
203 "Skipping glyph U+%0X, file %s",
204 pg
, file_name
.c_str ()));
208 if (glyph_name
== string (".notdef") && is_ttf
)
209 glyph_name
[0] = '\0';
211 if (glyph_name
[0] == '\0' && is_ttf
)
212 // Access by glyph index directly.
213 get_glyph_index_name (glyph_name
, pg
);
215 if (glyph_name
[0] == '\0')
219 char_id
= scm_from_uint32 (pg
);
222 char_id
= scm_from_locale_string (glyph_name
);
224 *tail
= scm_cons (scm_list_4 (scm_from_double (ggeo
.width
* scale_
),
225 scm_from_double (ggeo
.x_offset
* scale_
),
226 scm_from_double (ggeo
.y_offset
* scale_
),
229 tail
= SCM_CDRLOC (*tail
);
232 pango_glyph_string_free (pgs
);
234 PangoFontDescription
*descr
= pango_font_describe (pa
->font
);
235 Real size
= pango_font_description_get_size (descr
)
236 / (Real (PANGO_SCALE
));
239 warning (_f ("no PostScript font name for font `%s'", file_name
));
244 && (file_name
.find (".otf") != NPOS
245 || file_name
.find (".cff") != NPOS
))
247 // UGH: kludge a PS name for OTF/CFF fonts.
248 string name
= file_name
;
249 ssize idx
= file_name
.find (".otf");
251 idx
= file_name
.find (".cff");
253 name
= name
.substr (0, idx
);
255 ssize slash_idx
= name
.rfind ('/');
256 if (slash_idx
!= NPOS
)
259 name
= name
.substr (slash_idx
,
260 name
.length () - slash_idx
);
263 string initial
= name
.substr (0, 1);
264 initial
= String_convert::to_upper (initial
);
265 name
= name
.substr (1, name
.length () - 1);
266 name
= String_convert::to_lower (name
);
267 ps_name
= initial
+ name
;
269 else if (ps_name_str0
)
270 ps_name
= ps_name_str0
;
272 if (ps_name
.length ())
274 ((Pango_font
*) this)->register_font_file (file_name
,
277 pango_fc_font_unlock_face (fcfont
);
279 SCM expr
= scm_list_5 (ly_symbol2scm ("glyph-string"),
280 ly_string2scm (ps_name
),
281 scm_from_double (size
),
282 scm_from_bool (cid_keyed
),
283 ly_quote_scm (glyph_exprs
));
285 return Stencil (b
, expr
);
288 warning (_ ("FreeType face has no PostScript font name"));
293 Pango_font::physical_font_tab () const
295 return physical_font_tab_
;
299 Pango_font::word_stencil (string str
, bool feta
) const
301 return text_stencil (str
, feta
, true);
305 Pango_font::text_stencil (string str
, bool feta
) const
307 return text_stencil (str
, feta
, false);
311 Pango_font::text_stencil (string str
,
316 = pango_itemize (context_
,
318 0, str
.length (), attribute_list_
,
325 Direction text_dir
= RIGHT
;
326 for (GList
*p
= items
; p
; p
= p
->next
)
328 PangoItem
*item
= (PangoItem
*) p
->data
;
329 if (item
->analysis
.level
== PANGO_DIRECTION_RTL
)
333 for (GList
*ptr
= items
; ptr
; ptr
= ptr
->next
)
335 PangoItem
*item
= (PangoItem
*) ptr
->data
;
337 Stencil item_stencil
= pango_item_string_stencil (item
, str
, tight
);
339 if (text_dir
== RIGHT
)
341 item_stencil
.translate_axis (last_x
, X_AXIS
);
342 last_x
= item_stencil
.extent (X_AXIS
)[RIGHT
];
344 else if (text_dir
== LEFT
)
345 dest
.translate_axis (item_stencil
.extent (X_AXIS
)[RIGHT
], X_AXIS
);
347 #if 0 // Check extents.
348 if (!item_stencil
.extent_box ()[X_AXIS
].is_empty ())
350 Stencil frame
= Lookup::frame (item_stencil
.extent_box (), 0.1, 0.1);
353 Stencil
dimless_frame (empty
, frame
.expr ());
354 dest
.add_stencil (frame
);
358 dest
.add_stencil (item_stencil
);
361 string name
= get_output_backend_name ();
362 string output_mod
= "scm output-" + name
;
363 SCM mod
= scm_c_resolve_module (output_mod
.c_str ());
365 bool has_utf8_string
= false;
367 if (ly_is_module (mod
))
369 SCM utf8_string
= ly_module_lookup (mod
, ly_symbol2scm ("utf-8-string"));
371 has_utf8_string should only be true when utf8_string is a
372 variable that is bound to a *named* procedure.
374 if (utf8_string
!= SCM_BOOL_F
375 && scm_procedure_name (SCM_VARIABLE_REF (utf8_string
)) != SCM_BOOL_F
)
376 has_utf8_string
= true;
380 The SVG backend only uses utf-8-string for the non-music
381 fonts, hence the check here. --pmccarty
383 TODO: use a program option (-dmusic-strings-to-paths) here
384 instead that is enabled only when -dbackend=svg.
386 if ((name
== "svg" && !feta
) || (name
!= "svg" && has_utf8_string
))
388 // For Pango based backends, we take a shortcut.
389 SCM exp
= scm_list_3 (ly_symbol2scm ("utf-8-string"),
390 ly_string2scm (description_string ()),
391 ly_string2scm (str
));
393 Box
b (Interval (0, 0), Interval (0, 0));
394 b
.unite (dest
.extent_box ());
395 return Stencil (b
, exp
);
404 Pango_font::description_string () const
406 char *descr_string
= pango_font_description_to_string (pango_description_
);
407 string
s (descr_string
);
408 g_free (descr_string
);
413 Pango_font::font_file_name () const
418 #endif // HAVE_PANGO_FT2