basic_engine_shape() at basic-fc.c:340 0x7ffff39b7bbf
pango_shape_full() at shape.c:116 0x7ffff7bb8f7b
shape_run() at pango-layout.c:3,293 0x7ffff7b9c39c
process_item() at pango-layout.c:3,406 0x7ffff7b9c68d
process_line() at pango-layout.c:3,704 0x7ffff7baf78a
pango_layout_check_lines() at pango-layout.c:4,027 0x7ffff7baf78a
pango_layout_get_extents_internal() at pango-layout.c:2,587 0x7ffff7bb1208
pango_layout_get_pixel_extents() at pango-layout.c:2,808 0x7ffff7bb1636
output_body() at viewer-render.c:214 0x404665
do_output() at viewer-render.c:329 0x4051ec
<...more frames...>
3276 static PangoGlyphString *
3277 shape_run (PangoLayoutLine *line,
3278 ParaBreakState *state,
3279 PangoItem *item)
3280 {
3281 PangoLayout *layout = line->layout;
3282 PangoGlyphString *glyphs = pango_glyph_string_new ();
3283
3284 if (layout->text[item->offset] == '\t')
3285 shape_tab (line, glyphs);
3286 else
3287 {
3288 if (state->properties.shape_set)
3289 _pango_shape_shape (layout->text + item->offset, item->num_chars,
3290 state->properties.shape_ink_rect, state->properties.shape_logical_rect,
3291 glyphs);
3292 else
3293 pango_shape_full (layout->text + item->offset, item->length,
3294 layout->text, layout->length,
3295 &item->analysis, glyphs);
3296
3297 if (state->properties.letter_spacing)
3298 {
3299 PangoGlyphItem glyph_item;
3300 int space_left, space_right;
3301
3302 glyph_item.item = item;
3303 glyph_item.glyphs = glyphs;
3304
3305 pango_glyph_item_letter_space (&glyph_item,
3306 layout->text,
3307 layout->log_attrs + state->start_offset,
3308 state->properties.letter_spacing);
3309
3310 distribute_letter_spacing (state->properties.letter_spacing, &space_left, &space_right);
3311
3312 glyphs->glyphs[0].geometry.width += space_left;
3313 glyphs->glyphs[0].geometry.x_offset += space_left;
3314 glyphs->glyphs[glyphs->num_glyphs - 1].geometry.width += space_right;
3315 }
3316 }
3317
3318 return glyphs;
3319}
87 void
88 pango_shape_full (const gchar *item_text,
89 gint item_length,
90 const gchar *paragraph_text,
91 gint paragraph_length,
92 const PangoAnalysis *analysis,
93 PangoGlyphString *glyphs)
94{
95 int i;
96 int last_cluster;
97
98 glyphs->num_glyphs = 0;
99
100 if (item_length == -1)
101 item_length = strlen (item_text);
102
103 if (!paragraph_text)
104 {
105 paragraph_text = item_text;
106 paragraph_length = item_length;
107 }
108 if (paragraph_length == -1)
109 paragraph_length = strlen (paragraph_text);
110
111 g_return_if_fail (paragraph_text <= item_text);
112 g_return_if_fail (paragraph_text + paragraph_length >= item_text + item_length);
113
114 if (G_LIKELY (analysis->shape_engine && analysis->font))
115 {
116 _pango_engine_shape_shape (analysis->shape_engine, analysis->font,
117 item_text, item_length,
118 paragraph_text, paragraph_length,
119 analysis, glyphs);
120
121 if (G_UNLIKELY (glyphs->num_glyphs == 0))
122 {
123
136 GType engine_type = G_OBJECT_TYPE (analysis->shape_engine);
137 GQuark warned_quark = g_type_qname (engine_type);
138
139 if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark))
140 {
141 PangoFontDescription *desc;
142 char *font_name;
143 const char *engine_name;
144
145 desc = pango_font_describe (analysis->font);
146 font_name = pango_font_description_to_string (desc);
147 pango_font_description_free (desc);
148
149 if (!g_object_get_data (G_OBJECT (analysis->shape_engine), font_name))
150 {
151 engine_name = g_type_name (engine_type);
152 if (!engine_name)
153 engine_name = "(unknown)";
154
155 g_warning ("shaping failure, expect ugly output. shape-engine='%s', font='%s', text='%.*s'",
156 engine_name, font_name, item_length, item_text);
157
158 g_object_set_data_full (G_OBJECT (analysis->shape_engine), font_name,
159 GINT_TO_POINTER (1), NULL);
160 }
161
162 g_free (font_name);
163
164 g_object_set_qdata_full (G_OBJECT (analysis->font), warned_quark,
165 GINT_TO_POINTER (1), NULL);
166 }
167 }
168 }
169 else
170 glyphs->num_glyphs = 0;
171
172 if (G_UNLIKELY (!glyphs->num_glyphs))
173 {
174 PangoEngineShape *fallback_engine = _pango_get_fallback_shaper ();
175
176 _pango_engine_shape_shape (fallback_engine, analysis->font,
177 item_text, item_length,
178 paragraph_text, paragraph_length,
179 analysis, glyphs);
180 if (G_UNLIKELY (!glyphs->num_glyphs))
181 return;
182 }
183
184
185 last_cluster = glyphs->log_clusters[0] - 1;
186 for (i = 0; i < glyphs->num_glyphs; i++)
187 {
188
189 if (glyphs->log_clusters[i] != last_cluster)
190 {
191 glyphs->glyphs[i].attr.is_cluster_start = TRUE;
192 last_cluster = glyphs->log_clusters[i];
193 }
194 else
195 glyphs->glyphs[i].attr.is_cluster_start = FALSE;
196
197
198
202 if (glyphs->glyphs[i].geometry.width < 0)
203 {
204 glyphs->glyphs[i].geometry.width = -glyphs->glyphs[i].geometry.width;
205 glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width;
206 }
207 }
208
209
210 if (G_UNLIKELY ((analysis->level & 1) &&
211 glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1]))
212 {
213
214 static GQuark warned_quark = 0;
215
216 if (!warned_quark)
217 warned_quark = g_quark_from_static_string ("pango-shape-warned");
218
219 if (analysis->shape_engine && !g_object_get_qdata (G_OBJECT (analysis->shape_engine), warned_quark))
220 {
221 GType engine_type = G_OBJECT_TYPE (analysis->shape_engine);
222 const char *engine_name = g_type_name (engine_type);
223 if (!engine_name)
224 engine_name = "(unknown)";
225
226 g_warning ("Expected RTL run but shape-engine='%s' returned LTR. Fixing.", engine_name);
227
228 g_object_set_qdata_full (G_OBJECT (analysis->shape_engine), warned_quark,
229 GINT_TO_POINTER (1), NULL);
230 }
231
232
233 pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs);
234 }
235}
304 static void
305 basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
306 PangoFont *font,
307 const char *item_text,
308 unsigned int item_length,
309 const PangoAnalysis *analysis,
310 PangoGlyphString *glyphs,
311 const char *paragraph_text,
312 unsigned int paragraph_length)
313{
314 PangoFcHbContext context;
315 PangoFcFont *fc_font;
316 FT_Face ft_face;
317 hb_face_t *hb_face;
318 hb_font_t *hb_font;
319 hb_buffer_t *hb_buffer;
320 hb_direction_t hb_direction;
321 gboolean free_buffer;
322 gboolean is_hinted;
323 hb_glyph_info_t *hb_glyph;
324 hb_glyph_position_t *hb_position;
325 int last_cluster;
326 guint i, num_glyphs;
327 unsigned int item_offset = item_text - paragraph_text;
328 hb_feature_t features[8];
329 unsigned int num_features = 0;
330
331 g_return_if_fail (font != NULL);
332 g_return_if_fail (analysis != NULL);
333
334 fc_font = PANGO_FC_FONT (font);
335 ft_face = pango_fc_font_lock_face (fc_font);
336 if (!ft_face)
337 return;
338
339 TODO
340 context.ft_face = ft_face;
341 context.fc_font = fc_font;
342 context.vertical = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity);
343 context.improper_sign = PANGO_GRAVITY_IS_IMPROPER (analysis->gravity) ? -1 : +1;
344 hb_face = hb_ft_face_create_cached (ft_face);
345 hb_font = hb_font_create (hb_face);
346 hb_font_set_funcs (hb_font,
347 pango_fc_get_hb_font_funcs (),
348 &context,
349 NULL);
350 hb_font_set_scale (hb_font,
351 XXX
352 context.improper_sign *
353 (((guint64) ft_face->size->metrics.x_scale * ft_face->units_per_EM) >> 12),
354 context.improper_sign *
355 -(((guint64) ft_face->size->metrics.y_scale * ft_face->units_per_EM) >> 12));
356 is_hinted = fc_font->is_hinted;
357 hb_font_set_ppem (hb_font,
358 is_hinted ? ft_face->size->metrics.x_ppem : 0,
359 is_hinted ? ft_face->size->metrics.y_ppem : 0);
360
361 hb_buffer = acquire_buffer (&free_buffer);
362
363 hb_direction = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity) ? HB_DIRECTION_TTB : HB_DIRECTION_LTR;
364 if (analysis->level % 2)
365 hb_direction = HB_DIRECTION_REVERSE (hb_direction);
366 if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
367 hb_direction = HB_DIRECTION_REVERSE (hb_direction);
368
369
370
371 hb_buffer_set_direction (hb_buffer, hb_direction);
372 hb_buffer_set_script (hb_buffer, hb_glib_script_to_script (analysis->script));
373 hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis->language), -1));
374 hb_buffer_set_flags (hb_buffer,
375 (item_offset == 0 ? HB_BUFFER_FLAG_BOT : 0) |
376 (item_offset + item_length == paragraph_length ? HB_BUFFER_FLAG_EOT : 0));
377
378 hb_buffer_add_utf8 (hb_buffer, paragraph_text, paragraph_length, item_offset, item_length);
379
380
381 if (fc_font->font_pattern)
382 {
383 char *s;
384 while (num_features < G_N_ELEMENTS (features) &&
385 FcResultMatch == FcPatternGetString (fc_font->font_pattern,
386 PANGO_FC_FONT_FEATURES,
387 num_features,
388 (FcChar8 **) &s))
389 {
390 features[num_features].tag = hb_tag_from_string (s, -1);
391 features[num_features].value = 1;
392 features[num_features].start = 0;
393 features[num_features].end = (unsigned int) -1;
394 num_features++;
395 }
396 }
397
398 hb_shape (hb_font, hb_buffer, features, num_features);
399
400 if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
401 hb_buffer_reverse (hb_buffer);
402
403
404 num_glyphs = hb_buffer_get_length (hb_buffer);
405 hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL);
406 pango_glyph_string_set_size (glyphs, num_glyphs);
407 last_cluster = -1;
408 for (i = 0; i < num_glyphs; i++)
409 {
410 glyphs->glyphs[i].glyph = hb_glyph->codepoint;
411 glyphs->log_clusters[i] = hb_glyph->cluster - item_offset;
412 glyphs->glyphs[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster;
413 hb_glyph++;
414 last_cluster = glyphs->log_clusters[i];
415 }
416
417 hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL);
418 if (context.vertical)
419 for (i = 0; i < num_glyphs; i++)
420 {
421 unsigned int advance = hb_position->y_advance;
422 if (is_hinted)
423 advance = PANGO_UNITS_ROUND (advance);
424 glyphs->glyphs[i].geometry.width = advance;
425 XXX
426 glyphs->glyphs[i].geometry.x_offset = hb_position->y_offset;
427 glyphs->glyphs[i].geometry.y_offset = -hb_position->x_offset;
428 hb_position++;
429 }
430 else
431 for (i = 0; i < num_glyphs; i++)
432 {
433 unsigned int advance = hb_position->x_advance;
434 if (is_hinted)
435 advance = PANGO_UNITS_ROUND (advance);
436 glyphs->glyphs[i].geometry.width = advance;
437 glyphs->glyphs[i].geometry.x_offset = hb_position->x_offset;
438 glyphs->glyphs[i].geometry.y_offset = hb_position->y_offset;
439 hb_position++;
440 }
441
442 release_buffer (hb_buffer, free_buffer);
443 hb_font_destroy (hb_font);
444 hb_face_destroy (hb_face);
445 pango_fc_font_unlock_face (fc_font);
446}