Ejemplo n.º 1
0
void text_widget_set_text ( struct TEXT_WIDGET_HANDLE handle,
			    const char* text, int length )
{
  if ( handle.d == NULL || handle.d->layout == NULL )
    return;

  pango_layout_set_markup( handle.d->layout, text, length );

  // The idea here is to make sure that the VGFont contains
  // all the glyphs at the proper size so that when we want
  // to draw, we can can just call vgDrawGlyphs (well, maybe
  // not since PangoGlyphInfo is not an array of glyph
  // indexes; aww).
  PangoLayoutIter* li = pango_layout_get_iter( handle.d->layout );
  do {
    PangoLayoutRun* run = pango_layout_iter_get_run( li );
    if ( run == NULL )
      continue;
    PangoFont* font = run->item->analysis.font;
    // Well, you can see how C is not the most ideal language for
    // abstraction. Have to read the documentation to discover
    // that this font is a PangoFcFont.
    FT_Face face = pango_fc_font_lock_face( (PangoFcFont*)font );
    if ( face != NULL ) {
      struct VG_DATA* vg_data = face->size->generic.data;
      if ( vg_data == NULL ) {
	vg_data = vg_data_new();
	face->size->generic.data = vg_data;
	face->size->generic.finalizer = vg_data_free;
      }
      int g;
      for ( g = 0; g < run->glyphs->num_glyphs; g++ ) {
	int byte = run->glyphs->glyphs[g].glyph / 8;
	int bit  = 1 << ( run->glyphs->glyphs[g].glyph & 0x7 );
	if ( ! ( vg_data->cmap[byte] & bit  ) ) {
	  vg_data->cmap[byte] |= bit;
	  add_char( vg_data->font, face, run->glyphs->glyphs[g].glyph );
	}
      }
      pango_fc_font_unlock_face( (PangoFcFont*)font );
    }
  } while ( pango_layout_iter_next_run( li ) );

  pango_layout_iter_free( li );
}
Ejemplo n.º 2
0
static gboolean
layout_is_ellipsized(PangoLayout *layout)
{
    /* pango_layout_is_ellipsized() is a new function in Pango-1.16; we
     * emulate it here by trying to look for the ellipsis run
     */
    PangoLogAttr *log_attrs;
    int n_attrs;
    PangoLayoutIter *iter;
    gboolean result = FALSE;

    /* Short circuit when we aren't ellipsizing at all */
    if (pango_layout_get_ellipsize(layout) == PANGO_ELLIPSIZE_NONE)
        return FALSE;
    
    pango_layout_get_log_attrs(layout, &log_attrs, &n_attrs);
    
    iter = pango_layout_get_iter(layout);
    do {
        PangoGlyphItem *run;
        int n_glyphs;
        int start_index;
        int n_graphemes;
        int i;

        run = pango_layout_iter_get_run(iter);
        if (!run)
            continue;

        n_glyphs = run->glyphs->num_glyphs;
        start_index = pango_layout_iter_get_index(iter);
        
        /* Check the number of clusters in the run ... if it is greater
         * than 1, then it isn't an ellipsis
         */
        if (run->glyphs->log_clusters[0] != run->glyphs->log_clusters[n_glyphs - 1])
            continue;

        /* Now check the number of graphemes in the run ... if it is less
         * than 3, it's probably an isolated 'fi' ligature or something
         * like that rather than an ellipsis.
         */
        n_graphemes = 0;
        for (i = 0; i < run->item->num_chars && i + start_index < n_attrs; i++)
            if (log_attrs[i + start_index].is_cursor_position)
                n_graphemes++;

        if (n_graphemes < 3)
            continue;

        /* OK, at this point it is probably an ellipsis; it's possible that
         * the text consists of just the letters 'ffi' and the font has a ligature
         * for that or something, but it's not too likely.
         */
        result = TRUE;
        break;
                
    } while (pango_layout_iter_next_run(iter));

    pango_layout_iter_free(iter);

    g_free(log_attrs);

    return result;
}
Ejemplo n.º 3
0
void text_widget_draw_text ( struct TEXT_WIDGET_HANDLE handle )
{
  if ( handle.d == NULL || handle.d->layout == NULL )
    return;

  vgSetPaint( handle.d->foreground, VG_FILL_PATH );

  vgSeti( VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE );
  vgLoadIdentity();
#if 0
  // Overscan (in dots, evidently).
  vgTranslate( 14.f, 8.f );
#endif
  // Offset in mm.
  vgScale( handle.d->dpmm_x, handle.d->dpmm_y );
  // Move to the corner.
  vgTranslate( handle.d->x_mm, handle.d->y_mm );
  // Back to dots.
  vgScale( 1.f/handle.d->dpmm_x, 1.f/handle.d->dpmm_y );

  int height = PANGO_PIXELS( pango_layout_get_height( handle.d->layout ) );

  PangoLayoutIter* li = pango_layout_get_iter( handle.d->layout );
  do {
    PangoLayoutRun* run = pango_layout_iter_get_run( li );
    if ( run == NULL )
      continue;

    PangoRectangle logical_rect;
    int baseline_pango = pango_layout_iter_get_baseline( li );
    int baseline_pixel = PANGO_PIXELS( baseline_pango );
    pango_layout_iter_get_run_extents( li, NULL, &logical_rect );
    int x_pixel = PANGO_PIXELS( logical_rect.x );

    PangoFont* pg_font = run->item->analysis.font;

    FT_Face face = pango_fc_font_lock_face( (PangoFcFont*)pg_font );

    if ( face != NULL ) {

      struct VG_DATA* vg_data = face->size->generic.data;
      if ( vg_data != NULL ) {
	// About the only extra attribute we can manage is the foreground
	// color. But, it might be nice to render a background color
	// to see just how badly the text is fitted into the widget
	// box.
	GSList* attr_item = run->item->analysis.extra_attrs;
	while ( attr_item ) {
	  PangoAttribute* attr = attr_item->data;
	  switch ( attr->klass->type ) {
	  case PANGO_ATTR_FOREGROUND:
	    {
	      PangoColor color = ((PangoAttrColor*)attr)->color;
	      VGfloat new_color[] = { (float)color.red / 65535.f,
				      (float)color.green / 65535.f,
				      (float)color.blue / 65535.f, 1.f };
	      VGPaint new_paint = vgCreatePaint();
	      vgSetParameterfv( new_paint, VG_PAINT_COLOR, 4, new_color );
	      vgSetPaint( new_paint, VG_FILL_PATH );
	      vgDestroyPaint( new_paint );
	    }
	    break;
	  default:
	    printf( "\tHmm. Unknown attribute: %d\n", attr->klass->type );
	  }
	  attr_item = attr_item->next;
	}

	// Note: inverted Y coordinate
	VGfloat point[2] = { x_pixel, height - baseline_pixel };
	vgSetfv( VG_GLYPH_ORIGIN, 2, point );
	VGFont vg_font = vg_data->font;
	int g;
	for ( g = 0; g < run->glyphs->num_glyphs; g++ ) {
	  vgDrawGlyph( vg_font, run->glyphs->glyphs[g].glyph, VG_FILL_PATH,
		       VG_TRUE );
	}

	if ( vgGetPaint( VG_FILL_PATH ) != handle.d->foreground ) {
	  vgSetPaint( handle.d->foreground, VG_FILL_PATH );
	}
      }
      pango_fc_font_unlock_face( (PangoFcFont*)pg_font );
    }
  } while ( pango_layout_iter_next_run( li ) );
  // Iterators are not free.
  pango_layout_iter_free( li);
}
Ejemplo n.º 4
0
bool PangoFontInfo::CanRenderString(const char* utf8_word, int len,
                                    vector<string>* graphemes) const {
  if (graphemes) graphemes->clear();
  // We check for font coverage of the text first, as otherwise Pango could
  // (undesirably) fall back to another font that does have the required
  // coverage.
  if (!CoversUTF8Text(utf8_word, len)) {
    return false;
  }
  // U+25CC dotted circle character that often (but not always) gets rendered
  // when there is an illegal grapheme sequence.
  const char32 kDottedCircleGlyph = 9676;
  bool bad_glyph = false;
  PangoFontMap* font_map = pango_cairo_font_map_get_default();
  PangoContext* context = pango_context_new();
  pango_context_set_font_map(context, font_map);
  PangoLayout* layout;
  {
    // Pango is not relasing the cached layout.
    DISABLE_HEAP_LEAK_CHECK;
    layout = pango_layout_new(context);
  }
  if (desc_) {
    pango_layout_set_font_description(layout, desc_);
  } else {
    PangoFontDescription *desc = pango_font_description_from_string(
        DescriptionName().c_str());
    pango_layout_set_font_description(layout, desc);
    pango_font_description_free(desc);
  }
  pango_layout_set_text(layout, utf8_word, len);
  PangoLayoutIter* run_iter = NULL;
  { // Fontconfig caches some information here that is not freed before exit.
    DISABLE_HEAP_LEAK_CHECK;
    run_iter = pango_layout_get_iter(layout);
  }
  do {
    PangoLayoutRun* run = pango_layout_iter_get_run_readonly(run_iter);
    if (!run) {
      tlog(2, "Found end of line NULL run marker\n");
      continue;
    }
    PangoGlyph dotted_circle_glyph;
    PangoFont* font = run->item->analysis.font;
    dotted_circle_glyph = pango_fc_font_get_glyph(
        reinterpret_cast<PangoFcFont*>(font), kDottedCircleGlyph);
    if (TLOG_IS_ON(2)) {
      PangoFontDescription* desc = pango_font_describe(font);
      char* desc_str = pango_font_description_to_string(desc);
      tlog(2, "Desc of font in run: %s\n", desc_str);
      g_free(desc_str);
      pango_font_description_free(desc);
    }

    PangoGlyphItemIter cluster_iter;
    gboolean have_cluster;
    for (have_cluster = pango_glyph_item_iter_init_start(&cluster_iter,
                                                         run, utf8_word);
         have_cluster && !bad_glyph;
         have_cluster = pango_glyph_item_iter_next_cluster(&cluster_iter)) {
      const int start_byte_index = cluster_iter.start_index;
      const int end_byte_index = cluster_iter.end_index;
      int start_glyph_index = cluster_iter.start_glyph;
      int end_glyph_index = cluster_iter.end_glyph;
      string cluster_text = string(utf8_word + start_byte_index,
                                   end_byte_index - start_byte_index);
      if (graphemes) graphemes->push_back(cluster_text);
      if (IsUTF8Whitespace(cluster_text.c_str())) {
        tlog(2, "Skipping whitespace\n");
        continue;
      }
      if (TLOG_IS_ON(2)) {
        printf("start_byte=%d end_byte=%d start_glyph=%d end_glyph=%d ",
               start_byte_index, end_byte_index,
               start_glyph_index, end_glyph_index);
      }
      for (int i = start_glyph_index,
               step = (end_glyph_index > start_glyph_index) ? 1 : -1;
           !bad_glyph && i != end_glyph_index; i+= step) {
        const bool unknown_glyph =
            (cluster_iter.glyph_item->glyphs->glyphs[i].glyph &
             PANGO_GLYPH_UNKNOWN_FLAG);
        const bool illegal_glyph =
            (cluster_iter.glyph_item->glyphs->glyphs[i].glyph ==
             dotted_circle_glyph);
        bad_glyph = unknown_glyph || illegal_glyph;
        if (TLOG_IS_ON(2)) {
          printf("(%d=%d)", cluster_iter.glyph_item->glyphs->glyphs[i].glyph,
                 bad_glyph ? 1 : 0);
        }
      }
      if (TLOG_IS_ON(2)) {
        printf("  '%s'\n", cluster_text.c_str());
      }
      if (bad_glyph)
        tlog(1, "Found illegal glyph!\n");
    }
  } while (!bad_glyph && pango_layout_iter_next_run(run_iter));

  pango_layout_iter_free(run_iter);
  g_object_unref(context);
  g_object_unref(layout);
  if (bad_glyph && graphemes) graphemes->clear();
  return !bad_glyph;
}
Ejemplo n.º 5
0
static void
dump_runs (PangoLayout *layout, GString *string)
{
  PangoLayoutIter *iter;
  PangoLayoutRun *run;
  PangoItem *item;
  const gchar *text;
  gint index, index2;
  gboolean has_more;
  gchar *char_str;
  gint i;
  gchar *font;

  text = pango_layout_get_text (layout);
  iter = pango_layout_get_iter (layout);

  has_more = TRUE;
  index = pango_layout_iter_get_index (iter);
  i = 0;
  while (has_more)
    {
      run = pango_layout_iter_get_run (iter);
      has_more = pango_layout_iter_next_run (iter);
      i++;

      if (has_more)
        {
          index2 = pango_layout_iter_get_index (iter);
          char_str = g_strndup (text + index, index2 - index);          
        }
      else
        {
          char_str = g_strdup (text + index);
        }

      if (run)
        {
          item = ((PangoGlyphItem*)run)->item;
          font = font_name (item->analysis.font);
          g_string_append_printf (string, "i=%d, index=%d, chars=%d, level=%d, gravity=%s, flags=%d, font=%s, script=%s, language=%s, '%s'\n",
                                  i, index, item->num_chars, item->analysis.level,
                                  gravity_name (item->analysis.gravity),
                                  item->analysis.flags,
                                  "OMITTED", /* for some reason, this fails on build.gnome.org, so leave it out */
                                  script_name (item->analysis.script),
                                  pango_language_to_string (item->analysis.language),
                                  char_str);
          dump_extra_attrs (item->analysis.extra_attrs, string);
          g_free (font);
        }
      else
        {
          g_string_append_printf (string, "i=%d, index=%d, no run, line end\n",
                                  i, index);
        }

      g_free (char_str);
      index = index2;
    }
  pango_layout_iter_free (iter);
}
Ejemplo n.º 6
0
static VALUE
layout_iter_next_run(VALUE self)
{
    return CBOOL2RVAL(pango_layout_iter_next_run(_SELF(self)));
}