2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2004--2010 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 // Necessary for supporting pango_context_new() and
21 // pango_context_set_font_map() in Pango < 1.22
22 #define PANGO_ENABLE_BACKEND
24 #include <pango/pangoft2.h>
25 #include <freetype/ftxf86.h>
32 #include "pango-font.hh"
33 #include "dimensions.hh"
34 #include "file-name.hh"
35 #include "international.hh"
36 #include "lookup.hh" // debugging
38 #include "string-convert.hh"
40 #include "all-font-metrics.hh"
41 #include "program-option.hh"
46 Pango_font::Pango_font (PangoFT2FontMap
*fontmap
,
47 PangoFontDescription
const *description
,
50 physical_font_tab_
= scm_c_make_hash_table (11);
51 PangoDirection pango_dir
= PANGO_DIRECTION_LTR
;
52 context_
= pango_context_new ();
53 pango_context_set_font_map (context_
, PANGO_FONT_MAP (fontmap
));
55 pango_description_
= pango_font_description_copy (description
);
56 attribute_list_
= pango_attr_list_new ();
58 // urgh. I don't understand this. Why isn't this 1/(scale *
59 // resolution * output_scale)
62 output_scale_
= output_scale
;
64 / (Real (PANGO_SCALE
) * Real (PANGO_RESOLUTION
) * output_scale
);
66 // ugh. Should make this configurable.
67 pango_context_set_language (context_
, pango_language_from_string ("en_US"));
68 pango_context_set_base_dir (context_
, pango_dir
);
69 pango_context_set_font_description (context_
, description
);
72 Pango_font::~Pango_font ()
74 pango_font_description_free (pango_description_
);
75 g_object_unref (context_
);
76 pango_attr_list_unref (attribute_list_
);
80 Pango_font::register_font_file (string filename
,
84 scm_hash_set_x (physical_font_tab_
,
85 ly_string2scm (ps_name
),
86 scm_list_2 (ly_string2scm (filename
),
87 scm_from_int (face_index
)));
91 Pango_font::derived_mark () const
93 scm_gc_mark (physical_font_tab_
);
97 get_glyph_index_name (char *s
,
100 sprintf (s
, "glyphIndex%lX", code
);
104 get_unicode_name (char *s
,
108 sprintf (s
, "u%lX", code
);
110 sprintf (s
, "uni%04lX", code
);
114 Pango_font::pango_item_string_stencil (PangoGlyphItem
const *glyph_item
,
115 bool tight_bbox
) const
117 const int GLYPH_NAME_LEN
= 256;
118 char glyph_name
[GLYPH_NAME_LEN
];
120 PangoAnalysis
const *pa
= &(glyph_item
->item
->analysis
);
121 PangoGlyphString
*pgs
= glyph_item
->glyphs
;
123 PangoRectangle logical_rect
;
124 PangoRectangle ink_rect
;
125 pango_glyph_string_extents (pgs
, pa
->font
, &ink_rect
, &logical_rect
);
127 PangoFcFont
*fcfont
= PANGO_FC_FONT (pa
->font
);
129 FT_Face ftface
= pango_fc_font_lock_face (fcfont
);
131 PangoRectangle
const *which_rect
= tight_bbox
? &ink_rect
134 Box
b (Interval (PANGO_LBEARING (logical_rect
),
135 PANGO_RBEARING (logical_rect
)),
136 Interval (-PANGO_DESCENT (*which_rect
),
137 PANGO_ASCENT (*which_rect
)));
140 char const *ps_name_str0
= FT_Get_Postscript_Name (ftface
);
141 FcPattern
*fcpat
= fcfont
->font_pattern
;
143 FcChar8
*file_name_as_ptr
= 0;
144 FcPatternGetString (fcpat
, FC_FILE
, 0, &file_name_as_ptr
);
146 // due to a bug in FreeType 2.3.7 and earlier we can't use
147 // ftface->face_index; it is always zero for some font formats,
148 // in particular TTCs which we are interested in
150 FcPatternGetInteger (fcpat
, FC_INDEX
, 0, &face_index
);
153 if (file_name_as_ptr
)
154 // Normalize file name.
155 file_name
= File_name ((char const *)file_name_as_ptr
).to_string ();
157 SCM glyph_exprs
= SCM_EOL
;
158 SCM
*tail
= &glyph_exprs
;
160 Index_to_charcode_map
const *cmap
= 0;
161 bool has_glyph_names
= ftface
->face_flags
& FT_FACE_FLAG_GLYPH_NAMES
;
162 if (!has_glyph_names
)
163 cmap
= all_fonts_global
->get_index_to_charcode_map (
164 file_name
, face_index
, ftface
);
166 bool is_ttf
= string (FT_Get_X11_Font_Format (ftface
)) == "TrueType";
167 bool cid_keyed
= false;
169 for (int i
= 0; i
< pgs
->num_glyphs
; i
++)
171 PangoGlyphInfo
*pgi
= pgs
->glyphs
+ i
;
173 PangoGlyph pg
= pgi
->glyph
;
174 PangoGlyphGeometry ggeo
= pgi
->geometry
;
177 Zero-width characters are valid Unicode characters,
178 but glyph lookups need to be skipped.
180 if (!(pg
^ PANGO_GLYPH_EMPTY
))
183 glyph_name
[0] = '\0';
186 int errorcode
= FT_Get_Glyph_Name (ftface
, pg
, glyph_name
,
190 _f ("FT_Get_Glyph_Name () error: %s",
191 freetype_error_string (errorcode
).c_str ()));
194 SCM char_id
= SCM_EOL
;
195 if (glyph_name
[0] == '\0'
198 && cmap
->find (pg
) != cmap
->end ())
200 FT_ULong char_code
= cmap
->find (pg
)->second
;
201 get_unicode_name (glyph_name
, char_code
);
204 if (glyph_name
[0] == '\0' && has_glyph_names
)
207 _f ("Glyph has no name, but font supports glyph naming.\n"
208 "Skipping glyph U+%0X, file %s",
209 pg
, file_name
.c_str ()));
213 if (glyph_name
== string (".notdef") && is_ttf
)
214 glyph_name
[0] = '\0';
216 if (glyph_name
[0] == '\0' && is_ttf
)
217 // Access by glyph index directly.
218 get_glyph_index_name (glyph_name
, pg
);
220 if (glyph_name
[0] == '\0')
224 char_id
= scm_from_uint32 (pg
);
227 char_id
= scm_from_locale_string (glyph_name
);
229 *tail
= scm_cons (scm_list_4 (scm_from_double (ggeo
.width
* scale_
),
230 scm_from_double (ggeo
.x_offset
* scale_
),
231 scm_from_double (ggeo
.y_offset
* scale_
),
234 tail
= SCM_CDRLOC (*tail
);
237 pango_glyph_string_free (pgs
);
239 PangoFontDescription
*descr
= pango_font_describe (pa
->font
);
240 Real size
= pango_font_description_get_size (descr
)
241 / (Real (PANGO_SCALE
));
244 warning (_f ("no PostScript font name for font `%s'", file_name
));
249 && (file_name
.find (".otf") != NPOS
250 || file_name
.find (".cff") != NPOS
))
252 // UGH: kludge a PS name for OTF/CFF fonts.
253 string name
= file_name
;
254 ssize idx
= file_name
.find (".otf");
256 idx
= file_name
.find (".cff");
258 name
= name
.substr (0, idx
);
260 ssize slash_idx
= name
.rfind ('/');
261 if (slash_idx
!= NPOS
)
264 name
= name
.substr (slash_idx
,
265 name
.length () - slash_idx
);
268 string initial
= name
.substr (0, 1);
269 initial
= String_convert::to_upper (initial
);
270 name
= name
.substr (1, name
.length () - 1);
271 name
= String_convert::to_lower (name
);
272 ps_name
= initial
+ name
;
274 else if (ps_name_str0
)
275 ps_name
= ps_name_str0
;
277 if (ps_name
.length ())
279 ((Pango_font
*) this)->register_font_file (file_name
,
282 pango_fc_font_unlock_face (fcfont
);
284 SCM expr
= scm_list_5 (ly_symbol2scm ("glyph-string"),
285 ly_string2scm (ps_name
),
286 scm_from_double (size
),
287 scm_from_bool (cid_keyed
),
288 ly_quote_scm (glyph_exprs
));
290 return Stencil (b
, expr
);
293 warning (_ ("FreeType face has no PostScript font name"));
298 Pango_font::physical_font_tab () const
300 return physical_font_tab_
;
304 Pango_font::word_stencil (string str
, bool music_string
) const
306 return text_stencil (str
, music_string
, true);
310 Pango_font::text_stencil (string str
, bool music_string
) const
312 return text_stencil (str
, music_string
, false);
315 extern bool music_strings_to_paths
;
318 Pango_font::text_stencil (string str
,
323 The text assigned to a PangoLayout is automatically divided
324 into sections and reordered according to the Unicode
325 Bidirectional Algorithm, if necessary.
327 PangoLayout
*layout
= pango_layout_new (context_
);
328 pango_layout_set_text (layout
, str
.c_str (), -1);
329 GSList
*lines
= pango_layout_get_lines (layout
);
334 for (GSList
*l
= lines
; l
; l
= l
->next
)
336 PangoLayoutLine
*line
= (PangoLayoutLine
*) l
->data
;
337 GSList
*layout_runs
= line
->runs
;
339 for (GSList
*p
= layout_runs
; p
; p
= p
->next
)
341 PangoGlyphItem
*item
= (PangoGlyphItem
*) p
->data
;
342 Stencil item_stencil
= pango_item_string_stencil (item
, tight
);
344 item_stencil
.translate_axis (last_x
, X_AXIS
);
345 last_x
= item_stencil
.extent (X_AXIS
)[RIGHT
];
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
);
362 string name
= get_output_backend_name ();
363 string output_mod
= "scm output-" + name
;
364 SCM mod
= scm_c_resolve_module (output_mod
.c_str ());
366 bool has_utf8_string
= false;
368 if (ly_is_module (mod
))
370 SCM utf8_string
= ly_module_lookup (mod
, ly_symbol2scm ("utf-8-string"));
372 has_utf8_string should only be true when utf8_string is a
373 variable that is bound to a *named* procedure, i.e. not a
376 if (utf8_string
!= SCM_BOOL_F
377 && scm_procedure_name (SCM_VARIABLE_REF (utf8_string
)) != SCM_BOOL_F
)
378 has_utf8_string
= true;
381 bool to_paths
= music_strings_to_paths
;
384 Backends with the utf-8-string expression use it when
385 1) the -dmusic-strings-to-paths option is set
386 and `str' is not a music string, or
387 2) the -dmusic-strings-to-paths option is not set.
389 if (has_utf8_string
&& ((to_paths
&& !music_string
) || !to_paths
))
391 // For Pango based backends, we take a shortcut.
392 SCM exp
= scm_list_3 (ly_symbol2scm ("utf-8-string"),
393 ly_string2scm (description_string ()),
394 ly_string2scm (str
));
396 Box
b (Interval (0, 0), Interval (0, 0));
397 b
.unite (dest
.extent_box ());
398 return Stencil (b
, exp
);
405 Pango_font::description_string () const
407 char *descr_string
= pango_font_description_to_string (pango_description_
);
408 string
s (descr_string
);
409 g_free (descr_string
);
414 Pango_font::font_file_name () const
419 #endif // HAVE_PANGO_FT2