Пример #1
0
static void
render_tone (PangoFont *font, gunichar tone, PangoGlyphString *glyphs,
             int *n_glyphs, int cluster_offset)
{
  int index;

  index = find_char (font, tone);
  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
  if (index)
    {
      set_glyph_tone (font, glyphs, *n_glyphs, cluster_offset, index);
    }
  else 
    {
      /* fall back : HTONE1(0x302e) => middle-dot, HTONE2(0x302f) => colon */
      index = find_char (font, tone == HTONE1 ? 0x00b7 : 0x003a);
      if (index)
        {
          set_glyph_tone (font, glyphs, *n_glyphs, cluster_offset, index);
        }
      else 
        set_glyph (font, glyphs, *n_glyphs, cluster_offset,
		   get_unknown_glyph (font, tone));
    }
  (*n_glyphs)++;
}
Пример #2
0
/* This is a fallback for when we get a tone mark not preceded
 * by a syllable.
 */
static void
render_isolated_tone (PangoFont *font, gunichar tone, PangoGlyphString *glyphs,
		      int *n_glyphs, int cluster_offset)
{
#if 0 /* FIXME: what kind of hack is it?  it draws dummy glyphs.  */
  /* Find a base character to render the mark on
   */
  int index = find_char (font, 0x25cc);	/* DOTTED CIRCLE */
  if (!index)
    index = find_char (font, 0x25cb);   /* WHITE CIRCLE, in KSC-5601 */
  if (!index)
    index = find_char (font, ' ');      /* Space */
  if (!index)				/* Unknown glyph box with 0000 in it */
    index = find_char (font, PANGO_GET_UNKNOWN_GLYPH (0));

  /* Add the base character
   */
  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
  set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
  (*n_glyphs)++;
#endif

  /* And the tone mark
   */
  render_tone(font, tone, glyphs, n_glyphs, cluster_offset);
}
Пример #3
0
static void
render_basic (PangoFont *font, gunichar wc,
	      PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset)
{
  int index;

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

  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);

  if (pango_is_zero_width (wc))
    set_glyph (font, glyphs, *n_glyphs, cluster_offset, PANGO_GLYPH_EMPTY);
  else
    {
      index = find_char (font, wc);
      if (index)
	set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
      else
	set_glyph (font, glyphs, *n_glyphs, cluster_offset, get_unknown_glyph (font, wc));
    }
  (*n_glyphs)++;
}
Пример #4
0
/* This is a fallback for when we get a tone mark not preceded
 * by a syllable.
 */
static void
render_isolated_tone (PangoFont *font, gunichar tone, PangoGlyphString *glyphs,
		      int *n_glyphs, int cluster_offset)
{
  /* Find a base character to render the mark on
   */
  int index = find_char (font, 0x25cc);	/* DOTTED CIRCLE */
  if (!index)
    index = find_char (font, 0x25cb);   /* WHITE CIRCLE, in KSC-5601 */
  if (!index)
    index = find_char (font, ' ');      /* Space */
  if (!index)				/* Unknown glyph box with 0000 in it */
    index = find_char (font, get_unknown_glyph (font, 0));

  /* Add the base character
   */
  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
  set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
  (*n_glyphs)++;

  /* And the tone mrak
   */
  render_tone(font, tone, glyphs, n_glyphs, cluster_offset);
}
Пример #5
0
static VALUE
rglyph_set_size(VALUE self, VALUE len)
{
    pango_glyph_string_set_size(_SELF(self), NUM2INT(len));
    return self;
}
Пример #6
0
/* analysis->shape_engine has the PangoEngine... */
static void 
indic_engine_shape (PangoEngineShape *engine,
		    PangoFont        *font,
		    const char       *text,
		    gint              length,
		    const PangoAnalysis *analysis,
		    PangoGlyphString *glyphs)
{
  PangoFcFont *fc_font;
  FT_Face face;
  PangoOTRuleset *gsub_ruleset, *gpos_ruleset;
  PangoOTBuffer *buffer;
  glong i, n_chars, n_glyphs;
  gulong *tags = NULL;
  gunichar *wc_in = NULL, *wc_out = NULL;
  glong *utf8_offsets = NULL;
  glong *indices = NULL;
  IndicEngineFc *indic_shape_engine = NULL;
  const PangoIndicInfo *indic_info = NULL;
  MPreFixups *mprefixups;

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

  fc_font = PANGO_FC_FONT (font);
  face = pango_fc_font_lock_face (fc_font);
  if (!face)
    return;

  indic_shape_engine = (IndicEngineFc *) engine;

  indic_info = indic_shape_engine->indicInfo;

  wc_in    = expand_text (text, length, &utf8_offsets, &n_chars);
 
  n_glyphs = indic_ot_reorder (wc_in, utf8_offsets, n_chars, indic_info->classTable, NULL, NULL, NULL, NULL);
  
  wc_out  = g_new (gunichar, n_glyphs);
  indices = g_new (glong,    n_glyphs);
  tags    = g_new (gulong,   n_glyphs);

  n_glyphs  = indic_ot_reorder (wc_in, utf8_offsets, n_chars, indic_info->classTable, wc_out, indices, tags, &mprefixups);
  
  pango_glyph_string_set_size (glyphs, n_glyphs);
  buffer = pango_ot_buffer_new (fc_font);

  set_glyphs(font, wc_out, tags, n_glyphs, buffer,
	     (indic_info->classTable->scriptFlags & SF_PROCESS_ZWJ) != 0);

  /* do gsub processing */
  gsub_ruleset = get_gsub_ruleset (face, indic_info);
  if (gsub_ruleset != NULL)
    pango_ot_ruleset_substitute (gsub_ruleset, buffer);

  /* Fix pre-modifiers for some scripts before base consonant */
  if (mprefixups)
    {
      indic_mprefixups_apply (mprefixups, buffer);
      indic_mprefixups_free (mprefixups);
    }

  /* do gpos processing */
  gpos_ruleset = get_gpos_ruleset (face, indic_info);
  if (gpos_ruleset != NULL)
    pango_ot_ruleset_position (gpos_ruleset, buffer);

  pango_ot_buffer_output (buffer, glyphs);

  /* Get the right log_clusters values */
  for (i = 0; i < glyphs->num_glyphs; i += 1)
    glyphs->log_clusters[i] = indices[glyphs->log_clusters[i]];

  pango_fc_font_unlock_face (fc_font);

  pango_ot_buffer_destroy (buffer);
  g_free (tags);
  g_free (indices);
  g_free (wc_out);
  g_free (wc_in);
  g_free (utf8_offsets);
}
Пример #7
0
static void
render_syllable (PangoFont *font, gunichar *text, int length,
		 PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset)
{
  int n_prev_glyphs = *n_glyphs;
  int index;
  gunichar wc, tone;
  int i, j, composed;

  if (IS_M (text[length - 1]))
    {
      tone = text[length - 1];
      length--;
    }
  else
    tone = 0;

  if (length >= 3 && IS_L_S(text[0]) && IS_V_S(text[1]) && IS_T_S(text[2]))
    composed = 3;
  else if (length >= 2 && IS_L_S(text[0]) && IS_V_S(text[1]))
    composed = 2;
  else
    composed = 0;

  if (composed)
    {
      if (composed == 3)
	wc = S_FROM_LVT(text[0], text[1], text[2]);
      else
	wc = S_FROM_LV(text[0], text[1]);
      index = find_char (font, wc);
      pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
      if (!index)
	set_glyph (font, glyphs, *n_glyphs, cluster_offset,
		   get_unknown_glyph (font, wc));
      else
	set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
      (*n_glyphs)++;
      text += composed;
      length -= composed;
    }

  /* Render the remaining text as uncomposed forms as a fallback.  */
  for (i = 0; i < length; i++)
    {
      int jindex;
      int oldlen;

      if (text[i] == LFILL || text[i] == VFILL)
	continue;

      index = find_char (font, text[i]);
      if (index)
	{
	  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
	  set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
	  (*n_glyphs)++;
	  continue;
	}

      /* This font has no glyphs on the Hangul Jamo area!  Find a
	 fallback from the Hangul Compatibility Jamo area.  */
      jindex = text[i] - LBASE;
      oldlen = *n_glyphs;
      for (j = 0; j < 3 && (__jamo_to_ksc5601[jindex][j] != 0); j++)
	{
	  wc = __jamo_to_ksc5601[jindex][j] - KSC_JAMOBASE + UNI_JAMOBASE;
	  index = (wc >= 0x3131) ? find_char (font, wc) : 0;
	  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
	  if (!index)
	    {
	      *n_glyphs = oldlen;
	      pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
	      set_glyph (font, glyphs, *n_glyphs, cluster_offset,
			 get_unknown_glyph (font, text[i]));
	      (*n_glyphs)++;
	      break;
	    }
	  else
	    set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
	  (*n_glyphs)++;
	}
    }
  if (n_prev_glyphs == *n_glyphs)
    {
      index = find_char (font, 0x3164);
      pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
      if (!index)
	set_glyph (font, glyphs, *n_glyphs, cluster_offset,
		   get_unknown_glyph (font, index));
      else
	set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
      glyphs->log_clusters[*n_glyphs] = cluster_offset;
      (*n_glyphs)++;
    }
  if (tone)
    render_tone(font, tone, glyphs, n_glyphs, cluster_offset);
}
Пример #8
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;
}
Пример #9
0
static void
render_syllable (PangoFont *font, const char *str, int length,
		 PangoGlyphString *glyphs, int *n_glyphs, int cluster_offset)
{
  int n_prev_glyphs = *n_glyphs;
  int index;
  gunichar wc = 0, tone = 0, text[4];
  int i, j, composed = 0;
  const char *p;

  /* Normalize it only when the entire sequence is equivalent to a
   * precomposed syllable. It's usually better than prefix
   * normalization both for poor-featured fonts and for smart fonts.
   * I have seen no smart font which can render S+T as a syllable
   * form.
   */

  if (length == 3 || length == 4)
    {
      p = str;
      text[0] = g_utf8_get_char(p);
      p = g_utf8_next_char(p);
      text[1] = g_utf8_get_char(p);
      p = g_utf8_next_char(p);
      text[2] = g_utf8_get_char(p);

      if (length == 4 && !IS_M(g_utf8_get_char(g_utf8_next_char(p))))
	goto lvt_out;		/* draw the tone mark later */

      if (IS_L_S(text[0]) && IS_V_S(text[1]) &&  IS_T_S(text[2]))
	{
	  composed = 3;
	  wc = S_FROM_LVT(text[0], text[1], text[2]);
	  str = g_utf8_next_char(p);
	  goto normalize_out;
	}
    }
 lvt_out:

  if (length == 2 || length == 3)
    {
      p = str;
      text[0] = g_utf8_get_char(p);
      p = g_utf8_next_char(p);
      text[1] = g_utf8_get_char(p);

      if (length == 3 && !IS_M(g_utf8_get_char(g_utf8_next_char(p))))
	goto lv_out;		/* draw the tone mark later */
      if (IS_L_S(text[0]) && IS_V_S(text[1]))
	{
	  composed = 2;
	  wc = S_FROM_LV(text[0], text[1]);
	  str = g_utf8_next_char(p);
	}
      else if (IS_S(text[0] && !S_HAS_T(text[0]) && IS_T_S(text[1])))
	{
	  composed = 2;
	  wc = text[0] + (text[1] - TBASE);
	  str = g_utf8_next_char(p);
	  goto normalize_out;
	}
    }
 lv_out:
 normalize_out:

  if (composed)
    {
      index = find_char (font, wc);
      pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
      if (!index)
	set_glyph (font, glyphs, *n_glyphs, cluster_offset,
		   PANGO_GET_UNKNOWN_GLYPH (wc));
      else
	set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
      (*n_glyphs)++;
      length -= composed;
    }

  /* Render the remaining text as uncomposed forms as a fallback.  */
  for (i = 0; i < length; i++, str = g_utf8_next_char(str))
    {
      int jindex;
      int oldlen;

      wc = g_utf8_get_char(str);

      if (wc == LFILL || wc == VFILL)
	continue;

      if (IS_M(wc))
	{
	  tone = wc;
	  break;
	}

      if (IS_S(wc))
	{
	  oldlen = *n_glyphs;

	  text[0] = L_FROM_S(wc);
	  text[1] = V_FROM_S(wc);
	  if (S_HAS_T(wc))
	    {
	      text[2] = T_FROM_S(wc);
	      composed = 3;
	    }
	  else
	      composed = 2;

	  for (j = 0; j < composed; j++)
	    {
	      index = find_char (font, text[j]);
	      if (index)
		{
		  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
		  set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
		  (*n_glyphs)++;
		}
	      else
		goto decompose_cancel;
	    }

	  continue;

	decompose_cancel:
	  /* The font doesn't have jamos.  Cancel it. */
	  *n_glyphs = oldlen;
	  pango_glyph_string_set_size (glyphs, *n_glyphs);
	}

      index = find_char (font, wc);
      if (index)
	{
	  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
	  set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
	  (*n_glyphs)++;
	  continue;
	}
      else if (IS_S(wc))
	{
	  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
	  set_glyph (font, glyphs, *n_glyphs, cluster_offset,
		     PANGO_GET_UNKNOWN_GLYPH (wc));
	  (*n_glyphs)++;
	  continue;
	}

      /* This font has no glyphs on the Hangul Jamo area!  Find a
	 fallback from the Hangul Compatibility Jamo area.  */
      jindex = wc - LBASE;
      oldlen = *n_glyphs;
      for (j = 0; j < 3 && (__jamo_to_ksc5601[jindex][j] != 0); j++)
	{
	  wc = __jamo_to_ksc5601[jindex][j] - KSC_JAMOBASE + UNI_JAMOBASE;
	  index = (wc >= 0x3131) ? find_char (font, wc) : 0;
	  pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
	  if (!index)
	    {
	      *n_glyphs = oldlen;
	      pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
	      set_glyph (font, glyphs, *n_glyphs, cluster_offset,
			 PANGO_GET_UNKNOWN_GLYPH (text[i]));
	      (*n_glyphs)++;
	      break;
	    }
	  else
	    set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
	  (*n_glyphs)++;
	}
    }
  if (n_prev_glyphs == *n_glyphs)
    {
      index = find_char (font, 0x3164);	/* U+3164 HANGUL FILLER */
      pango_glyph_string_set_size (glyphs, *n_glyphs + 1);
      if (!index)
	set_glyph (font, glyphs, *n_glyphs, cluster_offset,
		   PANGO_GET_UNKNOWN_GLYPH (index));
      else
	set_glyph (font, glyphs, *n_glyphs, cluster_offset, index);
      glyphs->log_clusters[*n_glyphs] = cluster_offset;
      (*n_glyphs)++;
    }
  if (tone)
    render_tone(font, tone, glyphs, n_glyphs, cluster_offset);
}
Пример #10
0
/**
 * pango_ot_ruleset_shape:
 * @ruleset: a #PangoOTRuleset.
 * @glyphs: a pointer to a #PangoGlyphString.
 * @properties: an array containing one #gulong bitfield for each glyph,
 *   which gives the glyph's properties: If a certain bit is set for a glyph, 
 *   the feature which has the same bit set in its property value is applied.
 *
 * Shapes a string of glyphs with the given properties according to @ruleset.
 **/
void
pango_ot_ruleset_shape (PangoOTRuleset   *ruleset,
			PangoGlyphString *glyphs,
			gulong           *properties)
{
  int i;
  int last_cluster;
  int result;
  
  TTO_GSUB gsub = NULL;
  TTO_GPOS gpos = NULL;
  
  TTO_GSUB_String *in_string = NULL;
  TTO_GSUB_String *out_string = NULL;
  TTO_GSUB_String *result_string = NULL;

  gboolean need_gsub = FALSE;
  gboolean need_gpos = FALSE;

  g_return_if_fail (PANGO_OT_IS_RULESET (ruleset));

  for (i = 0; i < ruleset->rules->len; i++)
    {
      PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);

      if (rule->table_type == PANGO_OT_TABLE_GSUB)
	need_gsub = TRUE;
      else 
	need_gpos = TRUE;
    }

  if (need_gsub)
    {
      gsub = pango_ot_info_get_gsub (ruleset->info);

      if (gsub)
	TT_GSUB_Clear_Features (gsub);
    }

  if (need_gpos)
    {
      gpos = pango_ot_info_get_gpos (ruleset->info);

      if (gpos)
	TT_GPOS_Clear_Features (gpos);
    }

  for (i = 0; i < ruleset->rules->len; i++)
    {
      PangoOTRule *rule = &g_array_index (ruleset->rules, PangoOTRule, i);

      if (rule->table_type == PANGO_OT_TABLE_GSUB)
	{
	  if (gsub)
	    TT_GSUB_Add_Feature (gsub, rule->feature_index, rule->property_bit);
	}
      else
	{
	  if (gpos)
	    TT_GPOS_Add_Feature (gpos, rule->feature_index, rule->property_bit);
	}
    }

  if (!gsub && !gpos)
    return;

  result = TT_GSUB_String_New (ruleset->info->face->memory, &in_string);
  g_assert (result == FT_Err_Ok);

  result = TT_GSUB_String_Set_Length (in_string, glyphs->num_glyphs);
  g_assert (result == FT_Err_Ok);

  for (i = 0; i < glyphs->num_glyphs; i++)
    {
      in_string->string[i] = glyphs->glyphs[i].glyph;
      in_string->properties[i] = properties[i];
      in_string->logClusters[i] = glyphs->log_clusters[i];
    }
  in_string->max_ligID = i;
  
  if (gsub)
    {
      result = TT_GSUB_String_New (ruleset->info->face->memory,
                                   &out_string);
      g_assert (result == FT_Err_Ok);
      result_string = out_string;

      TT_GSUB_Apply_String (gsub, in_string, out_string);
    }
  else
    result_string = in_string;

  if (gpos)
    {
      TTO_GPOS_Data *outgpos = NULL;

      if (!TT_GPOS_Apply_String (ruleset->info->face, gpos, 0, result_string, &outgpos,
				 FALSE /* enable device-dependant values */,
				 FALSE /* Even though this might be r2l text, RTL is handled elsewhere */))
	{
	  for (i = 0; i < result_string->length; i++)
	    {
	      FT_Pos x_pos = outgpos[i].x_pos;
	      FT_Pos y_pos = outgpos[i].y_pos;
	      int back = i;
	      int j;

	      while (outgpos[back].back != 0)
		{
		  back  -= outgpos[back].back;
		  x_pos += outgpos[back].x_pos;
		  y_pos += outgpos[back].y_pos;
		}

	      for (j = back; j < i; j++)
	        glyphs->glyphs[i].geometry.x_offset -= glyphs->glyphs[j].geometry.width;

	      glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos);
	      glyphs->glyphs[i].geometry.y_offset += PANGO_UNITS_26_6(y_pos);

	      if (outgpos[i].new_advance)
		glyphs->glyphs[i].geometry.width  = PANGO_UNITS_26_6(outgpos[i].x_advance);
	      else
		glyphs->glyphs[i].geometry.width += PANGO_UNITS_26_6(outgpos[i].x_advance);
	    }

	  FT_Free(gpos->memory, (void *)outgpos);
	}
    }

  pango_glyph_string_set_size (glyphs, result_string->length);

  last_cluster = -1;
  for (i = 0; i < result_string->length; i++)
    {
      glyphs->glyphs[i].glyph = result_string->string[i];

      glyphs->log_clusters[i] = result_string->logClusters[i];
      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];
    }

  if (in_string)
    TT_GSUB_String_Done (in_string);
  if (out_string)
    TT_GSUB_String_Done (out_string);
}
Пример #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);
}
Пример #12
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;
        }
    }
}
Пример #13
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);
}