のねのBlog

パソコンやソフト開発で起きた問題など書きます。よろしくお願いします。

hb_shape

	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	  /* If a font has been correctly chosen, but no glyphs are output,
124	   * there's probably something wrong with the shaper, or the font.
125	   *
126	   * Trying to be informative, we print out the font description,
127	   * shaper name, and the text, but to not flood the terminal with
128	   * zillions of the message, we set a flag to only err once per
129	   * font/engine pair.
130	   *
131	   * To do the flag fast, we use the engine qname to qflag the font,
132	   * but also the font description to flag the engine.  This is
133	   * supposed to be fast to check, but also avoid writing out
134	   * duplicate warnings when a new PangoFont is created.
135	   */
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  /* make sure last_cluster is invalid */
185  last_cluster = glyphs->log_clusters[0] - 1;
186  for (i = 0; i < glyphs->num_glyphs; i++)
187    {
188      /* Set glyphs[i].attr.is_cluster_start based on log_clusters[] */
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      /* Shift glyph if width is negative, and negate width.
199       * This is useful for rotated font matrices and shouldn't
200       * harm in normal cases.
201       */
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  /* Make sure glyphstring direction conforms to analysis->level */
210  if (G_UNLIKELY ((analysis->level & 1) &&
211		  glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1]))
212    {
213      /* Warn once per shaper */
214      static GQuark warned_quark = 0; /* MT-safe */
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      /* *Fix* it so we don't crash later */
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: Cache hb_font? */
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 CTM */
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  /* setup buffer */
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  /* Setup features from fontconfig pattern. */
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  /* buffer output */
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 /* horizontal */
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}