2 pango-font.cc -- implement Pango_font
4 source file of the GNU LilyPond music typesetter
6 (c) 2004--2007 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #define PANGO_ENABLE_BACKEND // ugh, why necessary?
10 #include <pango/pangoft2.h>
11 #include <freetype/ftxf86.h>
17 #include "pango-font.hh"
18 #include "dimensions.hh"
19 #include "file-name.hh"
20 #include "international.hh"
21 #include "lookup.hh" // debugging
23 #include "string-convert.hh"
25 #include "all-font-metrics.hh"
26 #include "program-option.hh"
31 Pango_font::Pango_font (PangoFT2FontMap
*fontmap
,
32 PangoFontDescription
const *description
,
37 physical_font_tab_
= scm_c_make_hash_table (11);
38 PangoDirection pango_dir
= PANGO_DIRECTION_LTR
;
40 = pango_ft2_get_context (PANGO_RESOLUTION
, PANGO_RESOLUTION
);
42 pango_description_
= pango_font_description_copy (description
);
43 attribute_list_
= pango_attr_list_new ();
46 urgh. I don't understand this. Why isn't this 1/(scale *
47 resolution * output_scale)
51 output_scale_
= output_scale
;
52 scale_
= INCH_TO_BP
/ (Real (PANGO_SCALE
) * Real (PANGO_RESOLUTION
) * output_scale
);
55 ugh. Should make this configurable.
57 pango_context_set_language (context_
, pango_language_from_string ("en_US"));
58 pango_context_set_base_dir (context_
, pango_dir
);
59 pango_context_set_font_description (context_
, description
);
62 Pango_font::~Pango_font ()
64 pango_font_description_free (pango_description_
);
65 g_object_unref (context_
);
66 pango_attr_list_unref (attribute_list_
);
70 Pango_font::register_font_file (string filename
, string ps_name
)
72 scm_hash_set_x (physical_font_tab_
,
73 ly_string2scm (ps_name
),
74 ly_string2scm (filename
));
78 Pango_font::derived_mark () const
80 scm_gc_mark (physical_font_tab_
);
85 get_glyph_index_name (char *s
, FT_ULong code
)
87 sprintf (s
, "glyphIndex%lX", code
);
91 get_unicode_name (char*s
, FT_ULong code
)
94 sprintf (s
, "u%lX", code
);
96 sprintf (s
, "uni%04lX", code
);
101 Pango_font::pango_item_string_stencil (PangoItem
const *item
, string str
,
102 bool tight_bbox
) const
104 const int GLYPH_NAME_LEN
= 256;
105 char glyph_name
[GLYPH_NAME_LEN
];
106 PangoAnalysis
const *pa
= &(item
->analysis
);
107 PangoGlyphString
*pgs
= pango_glyph_string_new ();
109 pango_shape (str
.c_str () + item
->offset
,
110 item
->length
, (PangoAnalysis
*) pa
, pgs
);
112 PangoRectangle logical_rect
;
113 PangoRectangle ink_rect
;
114 pango_glyph_string_extents (pgs
, pa
->font
, &ink_rect
, &logical_rect
);
116 PangoFcFont
*fcfont
= G_TYPE_CHECK_INSTANCE_CAST (pa
->font
,
120 FT_Face ftface
= pango_fc_font_lock_face (fcfont
);
122 PangoRectangle
const *which_rect
127 Box
b (Interval (PANGO_LBEARING (logical_rect
),
128 PANGO_RBEARING (logical_rect
)),
129 Interval (-PANGO_DESCENT (*which_rect
),
130 PANGO_ASCENT (*which_rect
)));
133 char const *ps_name_str0
= FT_Get_Postscript_Name (ftface
);
134 FcPattern
*fcpat
= fcfont
->font_pattern
;
135 FcChar8
*file_name_as_ptr
= 0;
136 FcPatternGetString (fcpat
, FC_FILE
, 0, &file_name_as_ptr
);
139 if (file_name_as_ptr
)
141 /* Normalize file name. */
142 file_name
= File_name ((char const *)file_name_as_ptr
).to_string ();
145 SCM glyph_exprs
= SCM_EOL
;
146 SCM
*tail
= &glyph_exprs
;
148 Index_to_charcode_map
const *cmap
= 0;
149 bool has_glyph_names
= ftface
->face_flags
& FT_FACE_FLAG_GLYPH_NAMES
;
150 if (! has_glyph_names
)
151 cmap
= all_fonts_global
->get_index_to_charcode_map (file_name
, ftface
);
153 bool is_ttf
= string (FT_Get_X11_Font_Format (ftface
)) == "TrueType";
154 bool cid_keyed
= false;
155 for (int i
= 0; i
< pgs
->num_glyphs
; i
++)
157 PangoGlyphInfo
*pgi
= pgs
->glyphs
+ i
;
159 PangoGlyph pg
= pgi
->glyph
;
160 PangoGlyphGeometry ggeo
= pgi
->geometry
;
162 glyph_name
[0] = '\0';
165 int errorcode
= FT_Get_Glyph_Name (ftface
, pg
, glyph_name
, GLYPH_NAME_LEN
);
167 programming_error (_f ("FT_Get_Glyph_Name () error: %s",
168 freetype_error_string (errorcode
).c_str ()
172 SCM char_id
= SCM_EOL
;
173 if (glyph_name
[0] == '\0'
176 && cmap
->find (pg
) != cmap
->end ())
178 FT_ULong char_code
= cmap
->find (pg
)->second
;
179 get_unicode_name (glyph_name
, char_code
);
182 if (glyph_name
[0] == '\0' && has_glyph_names
)
184 programming_error (_f ("Glyph has no name, but font supports glyph naming.\n"
185 "Skipping glyph U+%0X, file %s",
187 file_name
.c_str ()));
192 if (glyph_name
== string (".notdef") && is_ttf
)
193 glyph_name
[0] = '\0';
195 if (glyph_name
[0] == '\0' && is_ttf
)
197 // access by glyph index directly.
198 get_glyph_index_name (glyph_name
, pg
);
201 if (glyph_name
[0] == '\0')
207 char_id
= scm_from_uint32 (pg
);
210 char_id
= scm_from_locale_string (glyph_name
);
212 *tail
= scm_cons (scm_list_4 (scm_from_double (ggeo
.width
* scale_
),
213 scm_from_double (ggeo
.x_offset
* scale_
),
214 scm_from_double (ggeo
.y_offset
* scale_
),
218 tail
= SCM_CDRLOC (*tail
);
221 pango_glyph_string_free (pgs
);
223 PangoFontDescription
*descr
= pango_font_describe (pa
->font
);
224 Real size
= pango_font_description_get_size (descr
)
225 / (Real (PANGO_SCALE
));
229 warning (_f ("no PostScript font name for font `%s'", file_name
));
234 && (file_name
.find (".otf") != NPOS
235 || file_name
.find (".cff") != NPOS
))
238 /* UGH: kludge a PS name for OTF/CFF fonts. */
239 string name
= file_name
;
240 ssize idx
= file_name
.find (".otf");
242 idx
= file_name
.find (".cff");
244 name
= name
.substr (0, idx
);
246 ssize slash_idx
= name
.rfind ('/');
247 if (slash_idx
!= NPOS
)
250 name
= name
.substr (slash_idx
,
251 name
.length () - slash_idx
);
254 string initial
= name
.substr (0, 1);
255 initial
= String_convert::to_upper (initial
);
256 name
= name
.substr (1, name
.length () - 1);
257 name
= String_convert::to_lower (name
);
258 ps_name
= initial
+ name
;
260 else if (ps_name_str0
)
261 ps_name
= ps_name_str0
;
263 if (ps_name
.length ())
265 ((Pango_font
*) this)->register_font_file (file_name
, ps_name
);
266 pango_fc_font_unlock_face (fcfont
);
268 SCM expr
= scm_list_5 (ly_symbol2scm ("glyph-string"),
269 ly_string2scm (ps_name
),
270 scm_from_double (size
),
271 scm_from_bool (cid_keyed
),
272 ly_quote_scm (glyph_exprs
));
274 return Stencil (b
, expr
);
277 warning (_ ("FreeType face has no PostScript font name"));
282 Pango_font::physical_font_tab () const
284 return physical_font_tab_
;
289 Pango_font::word_stencil (string str
) const
291 return text_stencil (str
, true);
295 Pango_font::text_stencil (string str
) const
297 return text_stencil (str
, false);
301 Pango_font::text_stencil (string str
, bool tight
) const
304 = pango_itemize (context_
,
306 0, str
.length (), attribute_list_
,
313 Direction text_dir
= RIGHT
;
314 for (GList
*p
= items
; p
; p
= p
->next
)
316 PangoItem
*item
= (PangoItem
*) p
->data
;
317 if (item
->analysis
.level
== PANGO_DIRECTION_RTL
)
321 for (GList
*ptr
= items
; ptr
; ptr
= ptr
->next
)
323 PangoItem
*item
= (PangoItem
*) ptr
->data
;
325 Stencil item_stencil
= pango_item_string_stencil (item
, str
, tight
);
327 if (text_dir
== RIGHT
)
329 item_stencil
.translate_axis (last_x
, X_AXIS
);
330 last_x
= item_stencil
.extent (X_AXIS
)[RIGHT
];
332 else if (text_dir
== LEFT
)
334 dest
.translate_axis (item_stencil
.extent (X_AXIS
)[RIGHT
], X_AXIS
);
337 #if 0 /* Check extents. */
338 if (!item_stencil
.extent_box ()[X_AXIS
].is_empty ())
340 Stencil frame
= Lookup::frame (item_stencil
.extent_box (), 0.1, 0.1);
343 Stencil
dimless_frame (empty
, frame
.expr ());
344 dest
.add_stencil (frame
);
348 dest
.add_stencil (item_stencil
);
352 UGH. Should have flags per output format signifying supported
355 string name
= get_output_backend_name ();
356 if (name
!= "ps" && name
!= "eps")
359 For Pango based backends, we take a shortcut.
362 = scm_list_3 (ly_symbol2scm ("utf-8-string"),
363 ly_string2scm (description_string ()),
364 ly_string2scm (str
));
366 Box
b (Interval (0, 0), Interval (0, 0));
367 b
.unite (dest
.extent_box ());
368 return Stencil (b
, exp
);
377 Pango_font::description_string () const
379 char *descr_string
= pango_font_description_to_string (pango_description_
);
380 string
s (descr_string
);
381 g_free (descr_string
);
387 Pango_font::font_file_name () const