2 pango-font.cc -- implement Pango_font
4 source file of the GNU LilyPond music typesetter
6 (c) 2004--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #define PANGO_ENABLE_BACKEND // ugh, why necessary?
10 #include <pango/pangoft2.h>
13 #include "pango-font.hh"
15 #include "dimensions.hh"
16 #include "file-name.hh"
17 #include "international.hh"
20 #include "string-convert.hh"
26 Pango_font::Pango_font (PangoFT2FontMap
*fontmap
,
27 PangoFontDescription
*description
,
31 physical_font_tab_
= scm_c_make_hash_table (11);
32 PangoDirection pango_dir
= PANGO_DIRECTION_LTR
;
34 = pango_ft2_get_context (PANGO_RESOLUTION
, PANGO_RESOLUTION
);
35 // context_ = pango_ft2_font_map_create_context (fontmap);
37 pango_description_
= pango_font_description_copy (description
);
38 attribute_list_
= pango_attr_list_new ();
41 urgh. I don't understand this. Why isn't this 1/(scale *
42 resolution * output_scale)
46 output_scale_
= output_scale
;
47 scale_
= INCH_TO_BP
/ (Real (PANGO_SCALE
) * Real (PANGO_RESOLUTION
) * output_scale
);
50 ugh. Should make this configurable.
52 pango_context_set_language (context_
, pango_language_from_string ("en_US"));
53 pango_context_set_base_dir (context_
, pango_dir
);
54 pango_context_set_font_description (context_
, description
);
57 Pango_font::~Pango_font ()
59 pango_font_description_free (pango_description_
);
60 g_object_unref (context_
);
61 pango_attr_list_unref (attribute_list_
);
65 Pango_font::register_font_file (string filename
, string ps_name
)
67 scm_hash_set_x (physical_font_tab_
,
68 scm_makfrom0str (ps_name
.c_str ()),
69 scm_makfrom0str (filename
.c_str ()));
73 Pango_font::derived_mark () const
75 scm_gc_mark (physical_font_tab_
);
79 Index_to_charcode_map
const *
80 Pango_font::get_index_to_charcode_map (string key
, FT_Face face
)
82 if (charcode_maps_
.find (key
) == charcode_maps_
.end ())
83 charcode_maps_
[key
] = make_index_to_charcode_map (face
);
85 if (charcode_maps_
.find (key
) == charcode_maps_
.end ())
88 return &charcode_maps_
[key
];
92 get_unicode_name (char*s
, FT_ULong code
)
95 sprintf (s
, "u%lX", code
);
97 sprintf (s
, "uni%04lX", code
);
102 Pango_font::pango_item_string_stencil (PangoItem
const *item
, string str
) 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
);
121 Box
b (Interval (PANGO_LBEARING (ink_rect
),
122 PANGO_RBEARING (ink_rect
)),
123 Interval (-PANGO_DESCENT (ink_rect
),
124 PANGO_ASCENT (ink_rect
)));
127 char const *ps_name_str0
= FT_Get_Postscript_Name (ftface
);
128 FcPattern
*fcpat
= fcfont
->font_pattern
;
129 char *file_name_as_ptr
= 0;
130 FcPatternGetString (fcpat
, FC_FILE
, 0, (FcChar8
**) & file_name_as_ptr
);
133 if (file_name_as_ptr
)
135 /* Normalize file name. */
136 file_name
= File_name (file_name_as_ptr
).to_string ();
139 SCM glyph_exprs
= SCM_EOL
;
140 SCM
*tail
= &glyph_exprs
;
142 Index_to_charcode_map
const *cmap
= 0;
143 bool has_glyph_names
= ftface
->face_flags
& FT_FACE_FLAG_GLYPH_NAMES
;
144 if (! has_glyph_names
)
145 cmap
= ((Pango_font
*)this)->get_index_to_charcode_map (file_name
, ftface
);
147 bool cid_keyed
= false;
148 for (int i
= 0; i
< pgs
->num_glyphs
; i
++)
150 PangoGlyphInfo
*pgi
= pgs
->glyphs
+ i
;
152 PangoGlyph pg
= pgi
->glyph
;
153 PangoGlyphGeometry ggeo
= pgi
->geometry
;
155 glyph_name
[0] = '\0';
158 int errorcode
= FT_Get_Glyph_Name (ftface
, pg
, glyph_name
, GLYPH_NAME_LEN
);
160 programming_error ("FT_Get_Glyph_Name returns error");
163 SCM char_id
= SCM_EOL
;
164 if (glyph_name
[0] == '\0'
167 /* Ugh should ask FreeType about font type. */
168 && (file_name
.find (".ttf") != NPOS
169 || file_name
.find (".TTF") != NPOS
))
171 FT_ULong char_code
= cmap
->find (pg
)->second
;
172 get_unicode_name (glyph_name
, char_code
);
175 if (glyph_name
[0] == '\0' && has_glyph_names
)
177 programming_error ("Glyph has no name, but font supports glyph naming. Skipping glyph.");
181 if (glyph_name
[0] == '\0')
187 char_id
= scm_from_uint32 (pg
);
190 char_id
= scm_makfrom0str (glyph_name
);
192 *tail
= scm_cons (scm_list_4 (scm_from_double (ggeo
.width
* scale_
),
193 scm_from_double (ggeo
.x_offset
* scale_
),
194 scm_from_double (ggeo
.y_offset
* scale_
),
198 tail
= SCM_CDRLOC (*tail
);
201 PangoFontDescription
*descr
= pango_font_describe (pa
->font
);
202 Real size
= pango_font_description_get_size (descr
)
203 / (Real (PANGO_SCALE
));
207 warning (_f ("no PostScript font name for font `%s'", file_name
));
212 && (file_name
.find (".otf") != NPOS
213 || file_name
.find (".cff") != NPOS
))
216 /* UGH: kludge a PS name for OTF/CFF fonts. */
217 string name
= file_name
;
218 ssize idx
= file_name
.find (".otf");
220 idx
= file_name
.find (".cff");
222 name
= name
.substr (0, idx
);
224 ssize slash_idx
= name
.rfind ('/');
225 if (slash_idx
!= NPOS
)
228 name
= name
.substr (slash_idx
,
229 name
.length () - slash_idx
);
232 string initial
= name
.substr (0, 1);
233 initial
= String_convert::to_upper (initial
);
234 name
= name
.substr (1, name
.length () - 1);
235 name
= String_convert::to_lower (name
);
236 ps_name
= initial
+ name
;
238 else if (ps_name_str0
)
239 ps_name
= ps_name_str0
;
241 if (ps_name
.length ())
243 ((Pango_font
*) this)->register_font_file (file_name
, ps_name
);
244 pango_fc_font_unlock_face (fcfont
);
246 SCM expr
= scm_list_5 (ly_symbol2scm ("glyph-string"),
247 scm_makfrom0str (ps_name
.c_str ()),
248 scm_from_double (size
),
249 scm_from_bool (cid_keyed
),
250 ly_quote_scm (glyph_exprs
));
252 return Stencil (b
, expr
);
255 warning (_ ("FreeType face has no PostScript font name"));
260 Pango_font::physical_font_tab () const
262 return physical_font_tab_
;
266 Pango_font::text_stencil (string str
) const
269 = pango_itemize (context_
,
271 0, str
.length (), attribute_list_
,
278 Direction text_dir
= RIGHT
;
279 for (GList
*p
= items
; p
; p
= p
->next
)
281 PangoItem
*item
= (PangoItem
*) p
->data
;
282 if (item
->analysis
.level
== PANGO_DIRECTION_RTL
)
286 for (GList
*ptr
= items
; ptr
; ptr
= ptr
->next
)
288 PangoItem
*item
= (PangoItem
*) ptr
->data
;
290 Stencil item_stencil
= pango_item_string_stencil (item
, str
);
292 if (text_dir
== RIGHT
)
294 item_stencil
.translate_axis (last_x
, X_AXIS
);
295 last_x
= item_stencil
.extent (X_AXIS
)[RIGHT
];
297 else if (text_dir
== LEFT
)
299 dest
.translate_axis (item_stencil
.extent (X_AXIS
)[RIGHT
], X_AXIS
);
302 #if 0 /* Check extents. */
303 if (!item_stencil
.extent_box ()[X_AXIS
].is_empty ())
305 Stencil frame
= Lookup::frame (item_stencil
.extent_box (), 0.1, 0.1);
308 Stencil
dimless_frame (empty
, frame
.expr ());
309 dest
.add_stencil (frame
);
313 dest
.add_stencil (item_stencil
);
317 UGH. Should have flags per output format signifying supported
320 if (output_backend_global
!= "ps"
321 && output_backend_global
!= "eps")
324 For Pango based backends, we take a shortcut.
326 char *descr_string
= pango_font_description_to_string (pango_description_
);
328 = scm_list_3 (ly_symbol2scm ("utf-8-string"),
329 scm_makfrom0str (descr_string
),
330 scm_makfrom0str (str
.c_str ()));
332 g_free (descr_string
);
334 Box
b (Interval (0, 0), Interval (0, 0));
335 b
.unite (dest
.extent_box ());
336 return Stencil (b
, exp
);
344 Pango_font::font_file_name () const