Esempio n. 1
0
static VALUE
rg_get_glyph_extents(VALUE self, VALUE glyph)
{
    PangoRectangle ink_rect, logical_rect;
    pango_font_get_glyph_extents(_SELF(self),
                                 NUM2UINT(glyph),
                                 &ink_rect, &logical_rect);

    return rb_assoc_new(PANGORECTANGLE2RVAL(&ink_rect),
                        PANGORECTANGLE2RVAL(&logical_rect));

}
Esempio n. 2
0
static void
set_glyph (PangoFont *font, PangoGlyphString *glyphs, int i, int offset, PangoGlyph glyph)
{
  PangoRectangle logical_rect;

  glyphs->glyphs[i].glyph = glyph;
  glyphs->glyphs[i].geometry.x_offset = 0;
  glyphs->glyphs[i].geometry.y_offset = 0;
  glyphs->log_clusters[i] = offset;

  pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect);
  glyphs->glyphs[i].geometry.width = logical_rect.width;
}
Esempio n. 3
0
static void
set_glyph_tone (PangoFont *font, PangoGlyphString *glyphs, int i,
		            int offset, PangoGlyph glyph)
{
  PangoRectangle logical_rect, ink_rect;
  PangoRectangle logical_rect_cluster;

  glyphs->glyphs[i].glyph = glyph;
  glyphs->glyphs[i].geometry.y_offset = 0;
  glyphs->log_clusters[i] = offset;

  pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, 
				&ink_rect, &logical_rect);

  /* tone mark is not the first in a glyph string. We have info. on the 
   * preceding glyphs in a glyph string 
   */
    {
      int j = i - 1;
      /* search for the beg. of the preceding cluster */
      while (j >= 0 && glyphs->log_clusters[j] == glyphs->log_clusters[i - 1]) 
	j--;

      /* In .._extents_range(...,start,end,...), to my surprise  start is 
       * inclusive but end is exclusive !! 
       */
      pango_glyph_string_extents_range (glyphs, j + 1, i, font, 
					NULL, &logical_rect_cluster); 

      /* logical_rect_cluster.width is all the offset we need so that the
       * inherent x_offset in the glyph (ink_rect.x) should be canceled out.
       */
      glyphs->glyphs[i].geometry.x_offset = - logical_rect_cluster.width
					    - ink_rect.x ; 
					    

      /* make an additional room for a tone mark if it has a spacing glyph
       * because that's likely to be an indication that glyphs for other 
       * characters in the font are not designed for combining with tone marks.
       */
      if (logical_rect.width)
	{
	  glyphs->glyphs[i].geometry.x_offset -= ink_rect.width;
          glyphs->glyphs[j + 1].geometry.width += ink_rect.width;
          glyphs->glyphs[j + 1].geometry.x_offset += ink_rect.width;
	}
    }

  glyphs->glyphs[i].geometry.width = 0;
}
void
_pango_cairo_font_private_get_glyph_extents (PangoCairoFontPrivate *cf_priv,
					     PangoGlyph             glyph,
					     PangoRectangle        *ink_rect,
					     PangoRectangle        *logical_rect)
{
  PangoCairoFontGlyphExtentsCacheEntry *entry;

  if (!cf_priv ||
      (cf_priv->glyph_extents_cache == NULL &&
       !_pango_cairo_font_private_glyph_extents_cache_init (cf_priv)))
    {
      /* Get generic unknown-glyph extents. */
      pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect);
      return;
    }

  if (glyph == PANGO_GLYPH_EMPTY)
    {
      if (ink_rect)
	ink_rect->x = ink_rect->y = ink_rect->width = ink_rect->height = 0;
      if (logical_rect)
	*logical_rect = cf_priv->font_extents;
      return;
    }
  else if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
    {
      _pango_cairo_font_private_get_glyph_extents_missing(cf_priv, glyph, ink_rect, logical_rect);
      return;
    }

  entry = _pango_cairo_font_private_get_glyph_extents_cache_entry (cf_priv, glyph);

  if (ink_rect)
    *ink_rect = entry->ink_rect;
  if (logical_rect)
    {
      *logical_rect = cf_priv->font_extents;
      logical_rect->width = entry->width;
    }
}
static void
_pango_cairo_font_private_get_glyph_extents_missing (PangoCairoFontPrivate *cf_priv,
						     PangoGlyph             glyph,
						     PangoRectangle        *ink_rect,
						     PangoRectangle        *logical_rect)
{
  PangoCairoFontHexBoxInfo *hbi;
  gunichar ch;
  gint rows, cols;

  hbi = _pango_cairo_font_private_get_hex_box_info (cf_priv);
  if (!hbi)
    {
      pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect);
      return;
    }

  ch = glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;

  rows = hbi->rows;
  if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF))
    cols = 1;
  else
    cols = ((glyph & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0xffff ? 6 : 4) / rows;

  if (ink_rect)
    {
      ink_rect->x = PANGO_SCALE * hbi->pad_x;
      ink_rect->y = PANGO_SCALE * (hbi->box_descent - hbi->box_height);
      ink_rect->width = PANGO_SCALE * (3 * hbi->pad_x + cols * (hbi->digit_width + hbi->pad_x));
      ink_rect->height = PANGO_SCALE * hbi->box_height;
    }

  if (logical_rect)
    {
      logical_rect->x = 0;
      logical_rect->y = PANGO_SCALE * (hbi->box_descent - (hbi->box_height + hbi->pad_y));
      logical_rect->width = PANGO_SCALE * (5 * hbi->pad_x + cols * (hbi->digit_width + hbi->pad_x));
      logical_rect->height = PANGO_SCALE * (hbi->box_height + 2 * hbi->pad_y);
    }
}
Esempio n. 6
0
bool PangoFontInfo::GetSpacingProperties(const string& utf8_char,
                                         int* x_bearing, int* x_advance) const {
  // Convert to equivalent PangoFont structure
  PangoFont* font = ToPangoFont();
  // Find the glyph index in the font for the supplied utf8 character.
  int total_advance = 0;
  int min_bearing = 0;
  // Handle multi-unicode strings by reporting the left-most position of the
  // x-bearing, and right-most position of the x-advance if the string were to
  // be rendered.
  const UNICHAR::const_iterator it_begin = UNICHAR::begin(utf8_char.c_str(),
                                                          utf8_char.length());
  const UNICHAR::const_iterator it_end = UNICHAR::end(utf8_char.c_str(),
                                                      utf8_char.length());
  for (UNICHAR::const_iterator it = it_begin; it != it_end; ++it) {
    PangoGlyph glyph_index = pango_fc_font_get_glyph(
        reinterpret_cast<PangoFcFont*>(font), *it);
    if (!glyph_index) {
      // Glyph for given unicode character doesn't exist in font.
      return false;
    }
    // Find the ink glyph extents for the glyph
    PangoRectangle ink_rect, logical_rect;
    pango_font_get_glyph_extents(font, glyph_index, &ink_rect, &logical_rect);
    pango_extents_to_pixels(&ink_rect, NULL);
    pango_extents_to_pixels(&logical_rect, NULL);

    int bearing = total_advance + PANGO_LBEARING(ink_rect);
    if (it == it_begin || bearing < min_bearing) {
      min_bearing = bearing;
    }
    total_advance += PANGO_RBEARING(logical_rect);
  }
  *x_bearing = min_bearing;
  *x_advance = total_advance;
  return true;
}
Esempio n. 7
0
/**
 * pango_glyph_string_extents_range:
 * @glyphs:   a #PangoGlyphString
 * @start:    start index
 * @end:      end index (the range is the set of bytes with
	      indices such that start <= index < end)
 * @font:     a #PangoFont
 * @ink_rect: rectangle used to store the extents of the glyph string range as drawn
 *            or %NULL to indicate that the result is not needed.
 * @logical_rect: rectangle used to store the logical extents of the glyph string range
 *            or %NULL to indicate that the result is not needed.
 *
 * Computes the extents of a sub-portion of a glyph string. The extents are
 * relative to the start of the glyph string range (the origin of their
 * coordinate system is at the start of the range, not at the start of the entire
 * glyph string).
 **/
void
pango_glyph_string_extents_range (PangoGlyphString *glyphs,
				  int               start,
				  int               end,
				  PangoFont        *font,
				  PangoRectangle   *ink_rect,
				  PangoRectangle   *logical_rect)
{
  int x_pos = 0;
  int i;

  /* Note that the handling of empty rectangles for ink
   * and logical rectangles is different. A zero-height ink
   * rectangle makes no contribution to the overall ink rect,
   * while a zero-height logical rect still reserves horizontal
   * width. Also, we may return zero-width, positive height
   * logical rectangles, while we'll never do that for the
   * ink rect.
   */
  g_return_if_fail (start <= end);

  if (G_UNLIKELY (!ink_rect && !logical_rect))
    return;

  if (ink_rect)
    {
      ink_rect->x = 0;
      ink_rect->y = 0;
      ink_rect->width = 0;
      ink_rect->height = 0;
    }

  if (logical_rect)
    {
      logical_rect->x = 0;
      logical_rect->y = 0;
      logical_rect->width = 0;
      logical_rect->height = 0;
    }

  for (i = start; i < end; i++)
    {
      PangoRectangle glyph_ink;
      PangoRectangle glyph_logical;

      PangoGlyphGeometry *geometry = &glyphs->glyphs[i].geometry;

      pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph,
				    ink_rect ? &glyph_ink : NULL,
				    logical_rect ? &glyph_logical : NULL);

      if (ink_rect && glyph_ink.width != 0 && glyph_ink.height != 0)
	{
	  if (ink_rect->width == 0 || ink_rect->height == 0)
	    {
	      ink_rect->x = x_pos + glyph_ink.x + geometry->x_offset;
	      ink_rect->width = glyph_ink.width;
	      ink_rect->y = glyph_ink.y + geometry->y_offset;
	      ink_rect->height = glyph_ink.height;
	    }
	  else
	    {
	      int new_x, new_y;

	      new_x = MIN (ink_rect->x, x_pos + glyph_ink.x + geometry->x_offset);
	      ink_rect->width = MAX (ink_rect->x + ink_rect->width,
				     x_pos + glyph_ink.x + glyph_ink.width + geometry->x_offset) - new_x;
	      ink_rect->x = new_x;

	      new_y = MIN (ink_rect->y, glyph_ink.y + geometry->y_offset);
	      ink_rect->height = MAX (ink_rect->y + ink_rect->height,
				      glyph_ink.y + glyph_ink.height + geometry->y_offset) - new_y;
	      ink_rect->y = new_y;
	    }
	}

      if (logical_rect)
	{
	  logical_rect->width += geometry->width;

	  if (i == start)
	    {
	      logical_rect->y = glyph_logical.y;
	      logical_rect->height = glyph_logical.height;
	    }
	  else
	    {
	      int new_y = MIN (logical_rect->y, glyph_logical.y);
	      logical_rect->height = MAX (logical_rect->y + logical_rect->height,
					  glyph_logical.y + glyph_logical.height) - new_y;
	      logical_rect->y = new_y;
	    }
	}

      x_pos += geometry->width;
    }
}
Esempio n. 8
0
TGlyphInfo *glyph_cache_get_info(TGlyphCache *cache, gunichar glyph) {
	TGlyphInfo *gfi;
	XftFont *xftfont;
	PangoFont *font;
	PangoGlyph pglyph;
	PangoRectangle ink, logical;
	gint ascent, descent;
	gint x_offset;
	gint nominal_width;
	double scale_y, scale_x;

	if (!cache->hash)
		return NULL;

	gfi = g_hash_table_lookup(cache->hash, GINT_TO_POINTER(glyph));
	if (gfi)
		return gfi;

	font = pango_fontset_get_font(cache->font_set, glyph);

	pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph);
	if (!pglyph) {
		fprintf (stderr, "Error: Unable to find glyph %d.\n", glyph);
		if (!pglyph)
			pglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), glyph);
		if (!pglyph)
			pglyph = PANGO_GET_UNKNOWN_GLYPH (glyph);
		if (!pglyph)
			return NULL;
	}
	pango_font_get_glyph_extents(font, pglyph, &ink, &logical);

	ascent = PANGO_ASCENT(logical);
	descent = PANGO_DESCENT(logical);

	xftfont = pango_xft_font_get_font(font);

	x_offset = 0;

	nominal_width = cache->width;
	if (g_unichar_iswide(glyph))
		nominal_width *= 2;

	scale_x = scale_y = 1.0;

	if (logical.width > nominal_width) {
		if (logical.width)
			scale_x = (double)nominal_width / (double)logical.width;
		else
			scale_x = 1.0;
	}

	if (logical.height != cache->height) {
		double scale;

		if (ascent) {
			scale_y = (double)cache->ascent / (double)ascent;
		} else {
			scale_y = 1.0;
		}
		if (descent) {
			scale = (double)cache->descent / (double)descent;
			if (scale < scale_y)
				scale_y = scale;
		}
	}

	if (scale_x >= 1.0) {
		scale_x = 1.0;
		x_offset += (nominal_width - logical.width) / 2;
	}

	if (scale_x < 1.0 || scale_y != 1.0) {
		FcBool scalable;

		FcPatternGetBool(xftfont->pattern, FC_SCALABLE, 0, &scalable);
		if (!scalable) {
			/* Bah. Need better handling of non-scalable fonts */
			if (scale_x < 1.0) scale_x = 1.0;
			scale_y = 1.0;
		} else if (scale_x < 1.0 || scale_y != 1.0) {
			FcPattern *pattern;
			FcMatrix mat;

			pattern = FcPatternDuplicate(xftfont->pattern);

			FcMatrixInit (&mat);

			FcMatrixScale(&mat, scale_x, scale_y);

			FcPatternDel (pattern, FC_MATRIX);
			FcPatternAddMatrix(pattern, FC_MATRIX, &mat);

			xftfont = XftFontOpenPattern(
				GDK_DISPLAY_XDISPLAY(cache->display),
				pattern
			);
		}

		ascent = ascent * scale_y;
	}

	g_object_unref(font);

//	gfi = calloc(sizeof(TGlyphInfo), 1);
	gfi = g_slice_new(TGlyphInfo);
	gfi->font = xftfont;

	gfi->x_offset = PANGO_PIXELS(x_offset);

	gfi->y_offset = cache->ascent + (cache->ascent - ascent);
	gfi->y_offset = PANGO_PIXELS(gfi->y_offset);

	g_hash_table_insert(cache->hash, GINT_TO_POINTER(glyph), gfi);

	return gfi;
}
Esempio n. 9
0
static gboolean
itemize_shape_and_place (PangoFont           *font,
			 HDC                  hdc,
			 wchar_t             *wtext,
			 int                  wlen,
			 const PangoAnalysis *analysis,
			 PangoGlyphString    *glyphs)
{
  int i;
  int item, nitems, item_step;
  int itemlen, glyphix, nglyphs;
  SCRIPT_CONTROL control;
  SCRIPT_STATE state;
  SCRIPT_ITEM items[100];
  double scale = pango_win32_font_get_metrics_factor (font);
  HFONT hfont = _pango_win32_font_get_hfont (font);
  static GHashTable *script_cache_hash = NULL;

  if (!script_cache_hash)
    script_cache_hash = g_hash_table_new (g_int64_hash, g_int64_equal);

  memset (&control, 0, sizeof (control));
  memset (&state, 0, sizeof (state));

  control.uDefaultLanguage = make_langid (analysis->language);
  state.uBidiLevel = analysis->level;

#ifdef BASIC_WIN32_DEBUGGING
  if (pango_win32_debug)
    g_print (G_STRLOC ": ScriptItemize: uDefaultLanguage:%04x uBidiLevel:%d\n",
	     control.uDefaultLanguage, state.uBidiLevel);
#endif
  if (ScriptItemize (wtext, wlen, G_N_ELEMENTS (items), &control, NULL,
		     items, &nitems))
    {
#ifdef BASIC_WIN32_DEBUGGING
      if (pango_win32_debug)
	g_print ("ScriptItemize failed\n");
#endif
      return FALSE;
    }

#ifdef BASIC_WIN32_DEBUGGING
  if (pango_win32_debug)
    g_print ("%d items:\n", nitems);
#endif

  if (analysis->level % 2)
    {
      item = nitems - 1;
      item_step = -1;
    }
  else
    {
      item = 0;
      item_step = 1;
    }

  for (i = 0; i < nitems; i++, item += item_step)
    {
      WORD iglyphs[1000];
      WORD log_clusters[1000];
      SCRIPT_VISATTR visattrs[1000];
      int advances[1000];
      GOFFSET offsets[1000];
      ABC abc;
      gint32 script = items[item].a.eScript;
      int ng;
      int char_offset;
      SCRIPT_CACHE *script_cache;
      gint64 font_and_script_key;

      memset (advances, 0, sizeof (advances));
      memset (offsets, 0, sizeof (offsets));
      memset (&abc, 0, sizeof (abc));

      /* Note that itemlen is number of wchar_t's i.e. surrogate pairs
       * count as two!
       */
      itemlen = items[item+1].iCharPos - items[item].iCharPos;
      char_offset = items[item].iCharPos;

#ifdef BASIC_WIN32_DEBUGGING
      if (pango_win32_debug)
	g_print ("  Item %d: iCharPos=%d eScript=%d (%s) %s%s%s%s%s%s%s wchar_t %d--%d (%d)\n",
		 item, items[item].iCharPos, script,
		 lang_name (scripts[script]->langid),
		 scripts[script]->fComplex ? "complex" : "simple",
		 items[item].a.fRTL ? " fRTL" : "",
		 items[item].a.fLayoutRTL ? " fLayoutRTL" : "",
		 items[item].a.fLinkBefore ? " fLinkBefore" : "",
		 items[item].a.fLinkAfter ? " fLinkAfter" : "",
		 items[item].a.fLogicalOrder ? " fLogicalOrder" : "",
		 items[item].a.fNoGlyphIndex ? " fNoGlyphIndex" : "",
		 items[item].iCharPos, items[item+1].iCharPos-1, itemlen);
#endif
      /* Create a hash key based on hfont and script engine */
      font_and_script_key = (((gint64) ((gint32) hfont)) << 32) | script;

      /* Get the script cache for this hfont and script */
      script_cache = g_hash_table_lookup (script_cache_hash, &font_and_script_key);
      if (!script_cache)
	{
	  gint64 *key_n;
	  SCRIPT_CACHE *new_script_cache;

	  key_n = g_new (gint64, 1);
	  *key_n = font_and_script_key;

	  new_script_cache = g_new0 (SCRIPT_CACHE, 1);
	  script_cache = new_script_cache;

	  /* Insert the new value */
	  g_hash_table_insert (script_cache_hash, key_n, new_script_cache);

#ifdef BASIC_WIN32_DEBUGGING
	  if (pango_win32_debug)
	    g_print ("  New SCRIPT_CACHE for font %p and script %d\n", hfont, script);
#endif
	}

      items[item].a.fRTL = analysis->level % 2;
      if (ScriptShape (hdc, script_cache,
		       wtext + items[item].iCharPos, itemlen,
		       G_N_ELEMENTS (iglyphs),
		       &items[item].a,
		       iglyphs,
		       log_clusters,
		       visattrs,
		       &nglyphs))
	{
#ifdef BASIC_WIN32_DEBUGGING
	  if (pango_win32_debug)
	    g_print ("pango-basic-win32: ScriptShape failed\n");
#endif
	  return FALSE;
	}

#ifdef BASIC_WIN32_DEBUGGING
      dump_glyphs_and_log_clusters (items[item].a.fRTL, itemlen,
				    items[item].iCharPos, log_clusters,
				    iglyphs, nglyphs);
#endif

      ng = glyphs->num_glyphs;
      pango_glyph_string_set_size (glyphs, ng + nglyphs);

      set_up_pango_log_clusters (wtext + items[item].iCharPos,
				 items[item].a.fRTL, itemlen, log_clusters,
				 nglyphs, glyphs->log_clusters + ng,
				 char_offset);

      if (ScriptPlace (hdc, script_cache, iglyphs, nglyphs,
		       visattrs, &items[item].a,
		       advances, offsets, &abc))
	{
#ifdef BASIC_WIN32_DEBUGGING
	  if (pango_win32_debug)
	    g_print ("pango-basic-win32: ScriptPlace failed\n");
#endif
	  return FALSE;
	}

      for (glyphix = 0; glyphix < nglyphs; glyphix++)
	{
	  if (iglyphs[glyphix] != 0)
	    {
	      glyphs->glyphs[ng+glyphix].glyph = iglyphs[glyphix];
	      glyphs->glyphs[ng+glyphix].geometry.width = floor (0.5 + scale * advances[glyphix]);
	      glyphs->glyphs[ng+glyphix].geometry.x_offset = floor (0.5 + scale * offsets[glyphix].du);
	      glyphs->glyphs[ng+glyphix].geometry.y_offset = floor (0.5 + scale * offsets[glyphix].dv);
	    }
	  else
	    {
	      PangoRectangle logical_rect;
	      /* Should pass actual char that was not found to
	       * PANGO_GET_UNKNOWN_GLYPH(), but a bit hard to
	       * find out that at this point, so cheat and use 0.
	       */
	      PangoGlyph unk = PANGO_GET_UNKNOWN_GLYPH (0);

	      glyphs->glyphs[ng+glyphix].glyph = unk;
	      pango_font_get_glyph_extents (font, unk, NULL, &logical_rect);
	      glyphs->glyphs[ng+glyphix].geometry.width = logical_rect.width;
	      glyphs->glyphs[ng+glyphix].geometry.x_offset = 0;
	      glyphs->glyphs[ng+glyphix].geometry.y_offset = 0;
	    }
	}
    }

#ifdef BASIC_WIN32_DEBUGGING
  if (pango_win32_debug)
    {
      g_print ("  Pango log_clusters (level:%d), char index:", analysis->level);
      for (glyphix = 0; glyphix < glyphs->num_glyphs; glyphix++)
	g_print ("%d ", glyphs->log_clusters[glyphix]);
      g_print ("\n");
    }
#endif

  return TRUE;
}
Esempio n. 10
0
void doDrawGlyphs(PangoRenderer* renderer, PangoFont* font, PangoGlyphString* glyphs, int px, int py) {
    Renderer* ren = RENDERER(renderer);
    if (!ren->m_runs) return;
    std::vector<ViewdoTextRun>& runs = *(ren->m_runs);
    const float s = ren->m_scale;

    PangoColor* fg = pango_renderer_get_color(renderer, PANGO_RENDER_PART_FOREGROUND);
    //PangoColor* bg = pango_renderer_get_color(renderer, PANGO_RENDER_PART_BACKGROUND);

    float red = !fg ? 0.0f : fg->red / 65536.0f;
    float green = !fg ? 0.0f : fg->green / 65536.0f;
    float blue = !fg ? 0.0f : fg->blue / 65536.0f;

    PangoFontDescription* desc = pango_font_describe(font);
    unsigned int fontHash = pango_font_description_hash(desc);
    pango_font_description_free(desc);

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

    PangoGlyphUnit layoutX = px;
    PangoGlyphUnit layoutY = py;
    ViewdoGlyphCache& cache = ViewdoGlyphCache::instance();

    for (int i = 0; i < glyphs->num_glyphs; i++) {
        PangoGlyphInfo* gi = glyphs->glyphs + i;

        if (gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG) {
            // XXX: Draw the fallback square.
            continue;
        }

        unsigned int glyph = gi->glyph;
        PangoRectangle r;
        
        pango_font_get_glyph_extents(font, glyph, &r, 0);
        pango_extents_to_pixels(&r, 0);

        float w = r.width;
        float h = r.height;

        if (w <= 0.f && h <= 0.f) {
            // Space.
            layoutX += gi->geometry.width;
            continue;
        }

        // Load and render the glyph. We probably need to just tell the font to cache it
        // and then grab the coordinates of it.
        const ViewdoGlyph& cachedGlyph = cache.findOrCreate(gi->glyph, fontHash, face);
        
        // Walk our existing runs and try to find one with the same color and page.
        // XXX: Fastpath try and use the run from the last glyph.
        ViewdoTextRun* run = nullptr;
        for (auto i = runs.begin(); i != runs.end(); i++) {
            if (i->m_page == cachedGlyph.m_page && i->m_red == red && i->m_green == green && i->m_blue == blue) {
                run = &(*i);
                break;
            }
        }
        if (!run) {
            runs.push_back(ViewdoTextRun(cachedGlyph.m_page, red, green, blue));
            run = &(runs[runs.size() - 1]);
        }

        float x = PANGO_PIXELS(layoutX + gi->geometry.x_offset) + cachedGlyph.m_offsetLeft;
        float y = PANGO_PIXELS(layoutY + gi->geometry.y_offset) - cachedGlyph.m_offsetTop;

        // Append ourselves onto this run.
        addPoint(run->m_geometry,
            x, y,
            cachedGlyph.m_x0, cachedGlyph.m_y0,
            s);

        addPoint(run->m_geometry,
            x + cachedGlyph.m_width, y,
            cachedGlyph.m_x1, cachedGlyph.m_y0,
            s);

        addPoint(run->m_geometry,
            x, y + cachedGlyph.m_height,
            cachedGlyph.m_x0, cachedGlyph.m_y1,
            s);

        // Triangle 2.
        addPoint(run->m_geometry,
            x + cachedGlyph.m_width, y,
            cachedGlyph.m_x1, cachedGlyph.m_y0,
            s);

        addPoint(run->m_geometry,
            x, y + cachedGlyph.m_height,
            cachedGlyph.m_x0, cachedGlyph.m_y1,
            s);

        addPoint(run->m_geometry,
            x + cachedGlyph.m_width, y + cachedGlyph.m_height,
            cachedGlyph.m_x1, cachedGlyph.m_y1,
            s);

        layoutX += gi->geometry.width;
    }

    pango_fc_font_unlock_face((PangoFcFont*) font);
}
Esempio n. 11
0
/**
 * pango_ot_buffer_output
 * @buffer: a #PangoOTBuffer
 * @glyphs: a #PangoGlyphString
 *
 * Exports the glyphs in a #PangoOTBuffer into a #PangoGlyphString.  This is
 * typically used after the OpenType layout processing is over, to convert the
 * resulting glyphs into a generic Pango glyph string.
 *
 * Since: 1.4
 **/ 
void
pango_ot_buffer_output (PangoOTBuffer    *buffer,
			PangoGlyphString *glyphs)
{
  FT_Face face;
  PangoOTInfo *info;
  HB_GDEF gdef = NULL;
  unsigned int i;
  int last_cluster;

  face = pango_fc_font_lock_face (buffer->font);
  g_assert (face);
  
  /* Copy glyphs into output glyph string */
  pango_glyph_string_set_size (glyphs, buffer->buffer->in_length);

  last_cluster = -1;
  for (i = 0; i < buffer->buffer->in_length; i++)
    {
      HB_GlyphItem item = &buffer->buffer->in_string[i];
      
      glyphs->glyphs[i].glyph = item->gindex;

      glyphs->log_clusters[i] = item->cluster;
      if (glyphs->log_clusters[i] != last_cluster)
	glyphs->glyphs[i].attr.is_cluster_start = 1;
      else
	glyphs->glyphs[i].attr.is_cluster_start = 0;

      last_cluster = glyphs->log_clusters[i];
    }

  info = pango_ot_info_get (face);
  gdef = pango_ot_info_get_gdef (info);
  
  /* Apply default positioning */
  for (i = 0; i < (unsigned int)glyphs->num_glyphs; i++)
    {
      if (glyphs->glyphs[i].glyph)
	{
	  PangoRectangle logical_rect;
	  
	  FT_UShort property;

	  if (buffer->zero_width_marks &&
	      gdef &&
	      HB_GDEF_Get_Glyph_Property (gdef, glyphs->glyphs[i].glyph, &property) == FT_Err_Ok &&
	      (property == HB_GDEF_MARK || (property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS) != 0))
	    {
	      glyphs->glyphs[i].geometry.width = 0;
	    }
	  else
	    {
	      pango_font_get_glyph_extents ((PangoFont *)buffer->font, glyphs->glyphs[i].glyph, NULL, &logical_rect);
	      glyphs->glyphs[i].geometry.width = logical_rect.width;
	    }
	}
      else
	glyphs->glyphs[i].geometry.width = 0;
  
      glyphs->glyphs[i].geometry.x_offset = 0;
      glyphs->glyphs[i].geometry.y_offset = 0;
    }

  if (buffer->rtl)
    {
      /* Swap all glyphs */
      swap_range (glyphs, 0, glyphs->num_glyphs);
    }

  if (buffer->applied_gpos)
    {
      if (buffer->rtl)
	apply_gpos_rtl (glyphs, buffer->buffer->positions);
      else
	apply_gpos_ltr (glyphs, buffer->buffer->positions);
    }
  else
    pango_fc_font_kern_glyphs (buffer->font, glyphs);

  pango_fc_font_unlock_face (buffer->font);
}
static PangoClutterGlyphCacheValue *
pango_clutter_renderer_get_cached_glyph (PangoRenderer *renderer,
					 PangoFont     *font,
					 PangoGlyph     glyph)
{
  PangoClutterRenderer *priv = PANGO_CLUTTER_RENDERER (renderer);
  PangoClutterGlyphCacheValue *value;
  PangoClutterGlyphCache *glyph_cache;

  glyph_cache = priv->use_mipmapping
    ? priv->mipmapped_glyph_cache : priv->glyph_cache;

  if ((value = pango_clutter_glyph_cache_lookup (glyph_cache,
						 font,
						 glyph)) == NULL)
    {
      cairo_surface_t *surface;
      cairo_t *cr;
      cairo_scaled_font_t *scaled_font;
      PangoRectangle ink_rect;
      cairo_glyph_t cairo_glyph;

      pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
      pango_extents_to_pixels (&ink_rect, NULL);

      surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
					    ink_rect.width,
					    ink_rect.height);
      cr = cairo_create (surface);

      scaled_font = pango_cairo_font_get_scaled_font (PANGO_CAIRO_FONT (font));
      cairo_set_scaled_font (cr, scaled_font);

      cairo_glyph.x = -ink_rect.x;
      cairo_glyph.y = -ink_rect.y;
      /* The PangoCairo glyph numbers directly map to Cairo glyph
	 numbers */
      cairo_glyph.index = glyph;
      cairo_show_glyphs (cr, &cairo_glyph, 1);

      cairo_destroy (cr);
      cairo_surface_flush (surface);

      /* Copy the glyph to the cache */
      value = pango_clutter_glyph_cache_set
	(glyph_cache, font, glyph,
	 cairo_image_surface_get_data (surface),
	 cairo_image_surface_get_width (surface),
	 cairo_image_surface_get_height (surface),
	 cairo_image_surface_get_stride (surface),
	 ink_rect.x, ink_rect.y);

      cairo_surface_destroy (surface);

      CLUTTER_NOTE (PANGO, "cache fail    %i", glyph);
    }
  else
    CLUTTER_NOTE (PANGO, "cache success %i", glyph);

  return value;
}
Esempio n. 13
0
CoglPangoGlyphCacheValue *
cogl_pango_glyph_cache_lookup (CoglPangoGlyphCache *cache,
                               CoglBool             create,
                               PangoFont           *font,
                               PangoGlyph           glyph)
{
  CoglPangoGlyphCacheKey lookup_key;
  CoglPangoGlyphCacheValue *value;

  lookup_key.font = font;
  lookup_key.glyph = glyph;

  value = g_hash_table_lookup (cache->hash_table, &lookup_key);

  if (create && value == NULL)
    {
      CoglPangoGlyphCacheKey *key;
      PangoRectangle ink_rect;

      value = g_slice_new (CoglPangoGlyphCacheValue);
      value->texture = NULL;

      pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
      pango_extents_to_pixels (&ink_rect, NULL);

      value->draw_x = ink_rect.x;
      value->draw_y = ink_rect.y;
      value->draw_width = ink_rect.width;
      value->draw_height = ink_rect.height;

      /* If the glyph is zero-sized then we don't need to reserve any
         space for it and we can just avoid painting anything */
      if (ink_rect.width < 1 || ink_rect.height < 1)
        value->dirty = FALSE;
      else
        {
          /* Try adding the glyph to the global atlas... */
          if (!cogl_pango_glyph_cache_add_to_global_atlas (cache,
                                                           font,
                                                           glyph,
                                                           value) &&
              /* If it fails try the local atlas */
              !cogl_pango_glyph_cache_add_to_local_atlas (cache,
                                                          font,
                                                          glyph,
                                                          value))
            {
              cogl_pango_glyph_cache_value_free (value);
              return NULL;
            }

          value->dirty = TRUE;
          cache->has_dirty_glyphs = TRUE;
        }

      key = g_slice_new (CoglPangoGlyphCacheKey);
      key->font = g_object_ref (font);
      key->glyph = glyph;

      g_hash_table_insert (cache->hash_table, key, value);
    }

  return value;
}
Esempio n. 14
0
static void
basic_engine_shape (PangoEngineShape *engine,
                    PangoFont        *font,
                    const char       *text,
                    gint              length,
                    PangoAnalysis    *analysis,
                    PangoGlyphString *glyphs)
{
    int n_chars;
    int i;
    const char *p;

    g_return_if_fail (font != NULL);
    g_return_if_fail (text != NULL);
    g_return_if_fail (length >= 0);
    g_return_if_fail (analysis != NULL);

#ifdef HAVE_USP10_H

    if (have_uniscribe &&
            !text_is_simple (text, length) &&
            uniscribe_shape (font, text, length, analysis, glyphs))
        return;

#endif

    n_chars = g_utf8_strlen (text, length);

    pango_glyph_string_set_size (glyphs, n_chars);

    p = text;
    for (i = 0; i < n_chars; i++)
    {
        gunichar wc;
        gunichar mirrored_ch;
        PangoGlyph index;

        wc = g_utf8_get_char (p);

        if (analysis->level % 2)
            if (pango_get_mirror_char (wc, &mirrored_ch))
                wc = mirrored_ch;

        if (wc == 0xa0)	/* non-break-space */
            wc = 0x20;

        if (pango_is_zero_width (wc))
        {
            set_glyph (font, glyphs, i, p - text, PANGO_GLYPH_EMPTY);
        }
        else
        {
            index = find_char (font, wc);
            if (index)
            {
                set_glyph (font, glyphs, i, p - text, index);

                if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK)
                {
                    if (i > 0)
                    {
                        PangoRectangle logical_rect, ink_rect;

                        glyphs->glyphs[i].geometry.width = MAX (glyphs->glyphs[i-1].geometry.width,
                                                                glyphs->glyphs[i].geometry.width);
                        glyphs->glyphs[i-1].geometry.width = 0;
                        glyphs->log_clusters[i] = glyphs->log_clusters[i-1];

                        /* Some heuristics to try to guess how overstrike glyphs are
                         * done and compensate
                         */
                        /* FIXME: (alex) Is this double call to get_glyph_extents really necessary? */
                        pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, &ink_rect, &logical_rect);
                        if (logical_rect.width == 0 && ink_rect.x == 0)
                            glyphs->glyphs[i].geometry.x_offset = (glyphs->glyphs[i].geometry.width - ink_rect.width) / 2;
                    }
                }
            }
            else
                set_glyph (font, glyphs, i, p - text, PANGO_GET_UNKNOWN_GLYPH (wc));
        }

        p = g_utf8_next_char (p);
    }

    /* Simple bidi support... may have separate modules later */

    if (analysis->level % 2)
    {
        int start, end;

        /* Swap all glyphs */
        swap_range (glyphs, 0, n_chars);

        /* Now reorder glyphs within each cluster back to LTR */
        for (start = 0; start < n_chars;)
        {
            end = start;
            while (end < n_chars &&
                    glyphs->log_clusters[end] == glyphs->log_clusters[start])
                end++;

            swap_range (glyphs, start, end);
            start = end;
        }
    }
}
Esempio n. 15
0
static void
basic_engine_shape (PangoEngineShape    *engine,
		    PangoFont           *font,
		    const char          *text,
		    gint                 length,
		    const PangoAnalysis *analysis,
		    PangoGlyphString    *glyphs)
{
  const char *p;
  char *copy;
  CTLineRef line;
  CFStringRef cstr;
  CFDictionaryRef attributes;
  CFAttributedStringRef attstr;
  PangoCoreTextFont *cfont = PANGO_CORE_TEXT_FONT (font);
  PangoCoverage *coverage;
  CFArrayRef runs;
  CTRunRef run;
  CTRunStatus run_status;
  CFIndex i, glyph_count;
  const CGGlyph *cgglyphs;

  CFTypeRef keys[] = {
      (CFTypeRef) kCTFontAttributeName
  };

  CFTypeRef values[] = {
      pango_core_text_font_get_ctfont (cfont)
  };

  attributes = CFDictionaryCreate (kCFAllocatorDefault,
                                   (const void **)keys,
                                   (const void **)values,
                                   1,
                                   &kCFCopyStringDictionaryKeyCallBacks,
                                   &kCFTypeDictionaryValueCallBacks);

  copy = g_strndup (text, length + 1);
  copy[length] = 0;

  cstr = CFStringCreateWithCString (kCFAllocatorDefault, copy,
                                    kCFStringEncodingUTF8);
  g_free (copy);

  attstr = CFAttributedStringCreate (kCFAllocatorDefault,
                                     cstr,
                                     attributes);

  line = CTLineCreateWithAttributedString (attstr);

  runs = CTLineGetGlyphRuns (line);

  /* Since Pango divides things into runs already, we assume there is
   * only a single run in this line.
   */
  run = CFArrayGetValueAtIndex (runs, 0);
  run_status = CTRunGetStatus (run);
  glyph_count = CTRunGetGlyphCount (run);
  cgglyphs = CTRunGetGlyphsPtr (run);

  p = text;
  pango_glyph_string_set_size (glyphs, glyph_count);
  coverage = pango_font_get_coverage (PANGO_FONT (cfont),
                                      analysis->language);

  for (i = 0; i < glyph_count; i++)
    {
      CFIndex real_i, prev_i;
      gunichar wc;
      gunichar mirrored_ch;

      wc = g_utf8_get_char (p);

      if (analysis->level % 2)
	if (pango_get_mirror_char (wc, &mirrored_ch))
	  wc = mirrored_ch;

      if (run_status & kCTRunStatusRightToLeft)
        {
          real_i = glyph_count - i - 1;
          prev_i = real_i + 1;
        }
      else
        {
          real_i = i;
          prev_i = real_i - 1;
        }

      if (wc == 0xa0)	/* non-break-space */
	wc = 0x20;

      if (pango_is_zero_width (wc))
	{
	  set_glyph (font, glyphs, real_i, p - text, PANGO_GLYPH_EMPTY);
	}
      else
	{
          PangoCoverageLevel result;

          result = pango_coverage_get (coverage, wc);

          if (result != PANGO_COVERAGE_NONE)
            {
              set_glyph (font, glyphs, real_i, p - text, cgglyphs[real_i]);

              if (g_unichar_type (wc) == G_UNICODE_NON_SPACING_MARK)
                {
                  if (i > 0)
                    {
                      PangoRectangle logical_rect, ink_rect;

                      glyphs->glyphs[real_i].geometry.width = MAX (glyphs->glyphs[prev_i].geometry.width,
                                                                   glyphs->glyphs[prev_i].geometry.width);
                      glyphs->glyphs[prev_i].geometry.width = 0;
                      glyphs->log_clusters[real_i] = glyphs->log_clusters[prev_i];

                      /* Some heuristics to try to guess how overstrike glyphs are
                       * done and compensate
                       */
                      pango_font_get_glyph_extents (font, glyphs->glyphs[real_i].glyph, &ink_rect, &logical_rect);
                      if (logical_rect.width == 0 && ink_rect.x == 0)
                        glyphs->glyphs[real_i].geometry.x_offset = (glyphs->glyphs[real_i].geometry.width - ink_rect.width) / 2;
                    }
                }
            }
          else
            {
              set_glyph (font, glyphs, real_i, p - text,
                         PANGO_GET_UNKNOWN_GLYPH (wc));
            }
        }

      p = g_utf8_next_char (p);
    }

  CFRelease (line);
  CFRelease (attstr);
  CFRelease (cstr);
  CFRelease (attributes);
  pango_coverage_unref (coverage);
}
JNIEXPORT jobject JNICALL
Java_gnu_java_awt_peer_gtk_GdkFontPeer_getGlyphVector
  (JNIEnv *env, jobject self, 
   jstring chars,
   jobject font, 
   jobject fontRenderContext)
{
  struct peerfont *pfont = NULL;
  GList *items = NULL, *i = NULL;
  gchar *str = NULL;
  int len, j;
  double *native_extents;
  int *native_codes;
  jintArray java_codes = NULL;
  jdoubleArray java_extents = NULL;

  gdk_threads_enter ();

  pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, self);
  g_assert (pfont != NULL);

  len = (*gdk_env())->GetStringUTFLength (env, chars);  
  str = (gchar *)(*env)->GetStringUTFChars (env, chars, NULL);
  g_assert (str != NULL);

  if (attrs == NULL)
    attrs = pango_attr_list_new ();

  if (len > 0 && str[len-1] == '\0')
    len--;
  
  items = pango_itemize (pfont->ctx, str, 0, len, attrs, NULL);

  i = g_list_first (items);

  if (i == NULL)       
    {
      java_extents = (*env)->NewDoubleArray (env, 0);
      java_codes = (*env)->NewIntArray (env, 0);
    }
  else
    { 
      PangoGlyphString *glyphs;
      PangoItem *item = (PangoItem *)i->data;

      pango_context_set_font_description (pfont->ctx, pfont->desc);
      pango_context_set_language (pfont->ctx, gtk_get_default_language());
      pango_context_load_font (pfont->ctx, pfont->desc);

      glyphs = pango_glyph_string_new ();
      g_assert (glyphs != NULL);

      pango_shape (str + item->offset, item->length, 
		   &(item->analysis), glyphs);

      if (glyphs->num_glyphs > 0)
	{
	  int x = 0;
	  double scale = ((double) PANGO_SCALE);

	  java_extents = (*env)->NewDoubleArray (env, glyphs->num_glyphs * NUM_GLYPH_METRICS);
	  java_codes = (*env)->NewIntArray (env, glyphs->num_glyphs);
	  native_extents = (*env)->GetDoubleArrayElements (env, java_extents, NULL);
	  native_codes = (*env)->GetIntArrayElements (env, java_codes, NULL);

	  for (j = 0; j < glyphs->num_glyphs; ++j)
	    {
	      PangoRectangle ink;
	      PangoRectangle logical;
	      PangoGlyphGeometry *geom = &glyphs->glyphs[j].geometry;

	      pango_font_get_glyph_extents (pfont->font, 
					    glyphs->glyphs[j].glyph,
					    &ink, &logical);

	      native_codes[j] = glyphs->glyphs[j].glyph;

	      native_extents[ GLYPH_LOG_X(j)      ] = (logical.x)      / scale;
	      native_extents[ GLYPH_LOG_Y(j)      ] = (- logical.y)    / scale;
	      native_extents[ GLYPH_LOG_WIDTH(j)  ] = (logical.width)  / scale;
	      native_extents[ GLYPH_LOG_HEIGHT(j) ] = (logical.height) / scale;

	      native_extents[ GLYPH_INK_X(j)      ] = (ink.x)       / scale;
	      native_extents[ GLYPH_INK_Y(j)      ] = (- ink.y)     / scale;
	      native_extents[ GLYPH_INK_WIDTH(j)  ] = (ink.width)   / scale;
	      native_extents[ GLYPH_INK_HEIGHT(j) ] = (ink.height)  / scale;

	      native_extents[ GLYPH_POS_X(j)      ] = (x + geom->x_offset)  / scale;
	      native_extents[ GLYPH_POS_Y(j)      ] = (  - geom->y_offset)  / scale;

	      x += geom->width;
	    }
	  (*env)->ReleaseDoubleArrayElements (env, java_extents, native_extents, 0);
	  (*env)->ReleaseIntArrayElements (env, java_codes, native_codes, 0);
	}

      pango_glyph_string_free (glyphs);
    }

  (*env)->ReleaseStringUTFChars (env, chars, str);
  
  for (i = g_list_first (items); i != NULL; i = g_list_next (i))
    g_free (i->data);
  
  g_list_free (items);

  gdk_threads_leave ();

  return (*env)->NewObject (env, 
			    glyphVector_class, 
			    glyphVector_ctor, 
			    java_extents, java_codes,
			    font, fontRenderContext);
}