のねのBlog

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

pango PangoAnalysis

void
pango_shape (const gchar      *text,
	     gint              length,
	     const PangoAnalysis *analysis,
	     PangoGlyphString *glyphs)
{
  pango_shape_full (text, length, text, length, analysis, glyphs);
}
void
pango_shape_full (const gchar      *item_text,
		  gint              item_length,
		  const gchar      *paragraph_text,
		  gint              paragraph_length,
		  const PangoAnalysis *analysis,
		  PangoGlyphString *glyphs)
{
  int i;
  int last_cluster;

  glyphs->num_glyphs = 0;

  if (item_length == -1)
    item_length = strlen (item_text);

  if (!paragraph_text)
    {
      paragraph_text = item_text;
      paragraph_length = item_length;
    }
  if (paragraph_length == -1)
    paragraph_length = strlen (paragraph_text);

  g_return_if_fail (paragraph_text <= item_text);
  g_return_if_fail (paragraph_text + paragraph_length >= item_text + item_length);

  if (G_LIKELY (analysis->shape_engine && analysis->font))
    {
      _pango_engine_shape_shape (analysis->shape_engine, analysis->font,
				 item_text, item_length,
				 paragraph_text, paragraph_length,
				 analysis, glyphs);

      if (G_UNLIKELY (glyphs->num_glyphs == 0))
	{
	  /* If a font has been correctly chosen, but no glyphs are output,
	   * there's probably something wrong with the shaper, or the font.
	   *
	   * Trying to be informative, we print out the font description,
	   * shaper name, and the text, but to not flood the terminal with
	   * zillions of the message, we set a flag to only err once per
	   * font/engine pair.
	   *
	   * To do the flag fast, we use the engine qname to qflag the font,
	   * but also the font description to flag the engine.  This is
	   * supposed to be fast to check, but also avoid writing out
	   * duplicate warnings when a new PangoFont is created.
	   */
	  GType engine_type = G_OBJECT_TYPE (analysis->shape_engine);
	  GQuark warned_quark = g_type_qname (engine_type);

	  if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark))
	    {
	      PangoFontDescription *desc;
	      char *font_name;
	      const char *engine_name;

	      desc = pango_font_describe (analysis->font);
	      font_name = pango_font_description_to_string (desc);
	      pango_font_description_free (desc);

	      if (!g_object_get_data (G_OBJECT (analysis->shape_engine), font_name))
	        {
		  engine_name = g_type_name (engine_type);
		  if (!engine_name)
		    engine_name = "(unknown)";

		  g_warning ("shaping failure, expect ugly output. shape-engine='%s', font='%s', text='%.*s'",
			     engine_name, font_name, item_length, item_text);

		  g_object_set_data_full (G_OBJECT (analysis->shape_engine), font_name,
					  GINT_TO_POINTER (1), NULL);
	        }

	      g_free (font_name);

	      g_object_set_qdata_full (G_OBJECT (analysis->font), warned_quark,
				       GINT_TO_POINTER (1), NULL);
	    }
	}
    }
  else
    glyphs->num_glyphs = 0;

  if (G_UNLIKELY (!glyphs->num_glyphs))
    {
      PangoEngineShape *fallback_engine = _pango_get_fallback_shaper ();

      _pango_engine_shape_shape (fallback_engine, analysis->font,
				 item_text, item_length,
				 paragraph_text, paragraph_length,
				 analysis, glyphs);
      if (G_UNLIKELY (!glyphs->num_glyphs))
        return;
    }

  /* make sure last_cluster is invalid */
  last_cluster = glyphs->log_clusters[0] - 1;
  for (i = 0; i < glyphs->num_glyphs; i++)
    {
      /* Set glyphs[i].attr.is_cluster_start based on log_clusters[] */
      if (glyphs->log_clusters[i] != last_cluster)
	{
	  glyphs->glyphs[i].attr.is_cluster_start = TRUE;
	  last_cluster = glyphs->log_clusters[i];
	}
      else
	glyphs->glyphs[i].attr.is_cluster_start = FALSE;


      /* Shift glyph if width is negative, and negate width.
       * This is useful for rotated font matrices and shouldn't
       * harm in normal cases.
       */
      if (glyphs->glyphs[i].geometry.width < 0)
	{
	  glyphs->glyphs[i].geometry.width = -glyphs->glyphs[i].geometry.width;
	  glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[i].geometry.width;
	}
    }

  /* Make sure glyphstring direction conforms to analysis->level */
  if (G_UNLIKELY ((analysis->level & 1) &&
		  glyphs->log_clusters[0] < glyphs->log_clusters[glyphs->num_glyphs - 1]))
    {
      /* Warn once per shaper */
      static GQuark warned_quark = 0; /* MT-safe */

      if (!warned_quark)
	warned_quark = g_quark_from_static_string ("pango-shape-warned");

      if (analysis->shape_engine && !g_object_get_qdata (G_OBJECT (analysis->shape_engine), warned_quark))
	{
	  GType engine_type = G_OBJECT_TYPE (analysis->shape_engine);
	  const char *engine_name = g_type_name (engine_type);
	  if (!engine_name)
	    engine_name = "(unknown)";

	  g_warning ("Expected RTL run but shape-engine='%s' returned LTR. Fixing.", engine_name);

	  g_object_set_qdata_full (G_OBJECT (analysis->shape_engine), warned_quark,
				   GINT_TO_POINTER (1), NULL);
	}

      /* *Fix* it so we don't crash later */
      pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs);
    }
}


Example

int main (int argc, char **argv)
{
  PangoFontMap    * fontmap   = pango_win32_font_map_for_display();
  PangoContext    * context;
  PangoCoverage   * coverage  = NULL;
  PangoFont       * font      = NULL;
  PangoFontFamily ** families = NULL;
  PangoFontFace   ** faces    = NULL;
  int nb, i;
  gchar* family_name = NULL;
  PangoLanguage *lang = pango_language_from_string (g_win32_getlocale ());
  HDC hdc = NULL;
  int line = 0;
  GTimeVal tv0, tv1;
  int my_font_size = 12;

  printf ("# Pango Font Test\n"
	  "# Language: %s\n"
	  "#\n", pango_language_to_string (lang));
  /* this wasn't necessary with previous version
   *
   * force initialization of built-in engines, otherwise
   * the rendering get's really fast - too fast to work :-(
   */
  context = pango_win32_get_context ();

  if (argc == 1)		/* No arguments given */
    {
      char *std_fonts[] = {"Sans 12", "Serif 12", "Monospace 12"};

      /* try to load some fonts often hardcoded */
      for (i = 0; i < G_N_ELEMENTS (std_fonts); i++)
	{
	  PangoFontDescription *desc = pango_font_description_from_string(std_fonts[i]);

	  /* spits warnings if font cannot be loaded */
	  font = pango_font_map_load_font (fontmap, context, desc);

	  g_object_unref (font);
	}
    }
  else
    {
      PangoFontDescription *desc = NULL;
      GString *s;

      s = g_string_new (argv[1]);
      for (i = 2; i < argc; i++)
	{
	  s = g_string_append_c (s, ' ');
	  s = g_string_append (s, argv[i]);

	  if (0 != atoi (argv[i]))
	    my_font_size = atoi (argv[i]);
	}

      desc = pango_font_description_from_string(s->str);
      family_name = g_strdup (pango_font_description_get_family (desc));

      font = pango_font_map_load_font (fontmap, context, desc);

      coverage = pango_font_get_coverage (font, lang);

      /* ... */

      pango_coverage_unref (coverage);
      pango_font_description_free (desc);
      g_object_unref (font);
    }
  pango_font_map_list_families (fontmap, &families, &nb);

  if (!family_name)
    {
      qsort (families, nb, sizeof (PangoFontFamily*), compare_font_family);
    }
  else
    {
      /* Get on the family faces. No simple way ? */
      for (i = 0; i < nb; i++)
	{
	  if (0 == g_ascii_strcasecmp (pango_font_family_get_name (families[i]), family_name))
	    {
	      pango_font_family_list_faces (families[i], &faces, &nb);
	      /* now nb is the number of faces */
	      break;
	    }
	}
      g_free (families);
      families = NULL;
      g_free (family_name);
      family_name = NULL;
    }

  hdc = pre_render(my_font_size * 64, 3 * my_font_size * nb / 2);

  for (i = 0; i < nb; i++)
    {
      PangoFontDescription *desc;
      const char *f_name;
      PangoWeight weight;
      PangoStyle  style;

      if (families)
	{
	  desc = pango_font_description_new ();

	  f_name =  pango_font_family_get_name (families[i]);
	  pango_font_description_set_family (desc, f_name);
	}
      else
	{
	  desc = pango_font_face_describe (faces[i]);
	  /* this is _not_ the family name from above */
	  f_name = pango_font_description_get_family (desc);
	}
      weight = pango_font_description_get_weight (desc);
      style  = pango_font_description_get_style  (desc);

      g_print ("%s; Style: %d; Weight: %d\n",
	       f_name, style, weight);

      /* give it an arbitray size to load it */
      pango_font_description_set_size (desc, my_font_size * PANGO_SCALE);

      g_get_current_time (&tv0);
      font = pango_font_map_load_font (fontmap, context, desc);
      g_get_current_time (&tv1);
      g_print ("\tpango_font_map_load_font took %.3f sec\n", calc_duration (&tv1, &tv0));

      if (font)
	{
	  PangoItem     *item;
	  PangoGlyphString * glyphs;
	  char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		     "abcdefghijklmnopqrstuvwxyz"
		     "1234567890 -+*/!\xc2\xa7$%&()[]{}<>|#=?@";

	  g_get_current_time (&tv0);
	  coverage = pango_font_get_coverage (font, lang);

	  g_get_current_time (&tv1);
	  g_print ("\tpango_font_get_coverage took %.3f sec\n", calc_duration (&tv1, &tv0));

	  /* ... */
	  pango_context_set_language (context, lang);
	  pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
	  pango_context_set_font_description (context, desc);

	  glyphs = pango_glyph_string_new ();
	  item = pango_item_new ();

	  item->analysis.shape_engine = pango_font_find_shaper (font, lang, s[0]);
	  item->analysis.font         = g_object_ref (font);

	  pango_shape ( s, sizeof(s), &(item->analysis), glyphs); <======================

	  if (hdc)
	    {
	      /* the positioning isn't correct */
	      char* name = g_strdup_printf ("%s (%s%s)",
		    f_name,
		    weight == PANGO_WEIGHT_NORMAL ? "n" :
		   (weight == PANGO_WEIGHT_HEAVY ? "h" :
		   (weight > PANGO_WEIGHT_NORMAL ? "b" : "l")),
		    style == PANGO_STYLE_OBLIQUE ? "o" :
		   (style == PANGO_STYLE_ITALIC ? "i" : "n"));

	      TextOut (hdc, 0, line, name, strlen(name));
	      g_get_current_time (&tv0);

	      pango_win32_render (hdc, font, glyphs, 200, line);

	      g_get_current_time (&tv1);
	      g_print ("\tpango_win32_render took %.3f sec\n",
		       calc_duration (&tv1, &tv0));
	      line += (3 * my_font_size / 2);
	      g_free(name);
	    }

	  /* free glyphs, ... */
	  pango_glyph_string_free (glyphs);
	  pango_item_free (item);

	  pango_coverage_unref (coverage);
	  g_object_unref (font);
	}
      pango_font_description_free (desc);
    }

  if (hdc)
    post_render (hdc, "pango-fonts.bmp");

  g_free (families);
  g_free (faces);

  return 0;
}

pango/pangowin32tobmp.c at master · GNOME/pango · GitHub