Blame pango/pangofc-shape.c

Packit 0ec9dd
/* Pango
Packit 0ec9dd
 * pangofc-shape.c: Basic shaper for FreeType-based backends
Packit 0ec9dd
 *
Packit 0ec9dd
 * Copyright (C) 2000, 2007, 2009 Red Hat Software
Packit 0ec9dd
 * Authors:
Packit 0ec9dd
 *   Owen Taylor <otaylor@redhat.com>
Packit 0ec9dd
 *   Behdad Esfahbod <behdad@behdad.org>
Packit 0ec9dd
 *
Packit 0ec9dd
 * This library is free software; you can redistribute it and/or
Packit 0ec9dd
 * modify it under the terms of the GNU Library General Public
Packit 0ec9dd
 * License as published by the Free Software Foundation; either
Packit 0ec9dd
 * version 2 of the License, or (at your option) any later version.
Packit 0ec9dd
 *
Packit 0ec9dd
 * This library is distributed in the hope that it will be useful,
Packit 0ec9dd
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 0ec9dd
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
Packit 0ec9dd
 * Library General Public License for more details.
Packit 0ec9dd
 *
Packit 0ec9dd
 * You should have received a copy of the GNU Library General Public
Packit 0ec9dd
 * License along with this library; if not, write to the
Packit 0ec9dd
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 0ec9dd
 * Boston, MA 02111-1307, USA.
Packit 0ec9dd
 */
Packit 0ec9dd
Packit 0ec9dd
#include "config.h"
Packit 0ec9dd
#include <string.h>
Packit 0ec9dd
#include <math.h>
Packit 0ec9dd
Packit 0ec9dd
#include "pangofc-private.h"
Packit 0ec9dd
#include <hb-ft.h>
Packit 0ec9dd
#include <hb-glib.h>
Packit 0ec9dd
Packit 0ec9dd
/* cache a single hb_buffer_t */
Packit 0ec9dd
static hb_buffer_t *cached_buffer = NULL; /* MT-safe */
Packit 0ec9dd
G_LOCK_DEFINE_STATIC (cached_buffer);
Packit 0ec9dd
Packit 0ec9dd
static hb_buffer_t *
Packit 0ec9dd
acquire_buffer (gboolean *free_buffer)
Packit 0ec9dd
{
Packit 0ec9dd
  hb_buffer_t *buffer;
Packit 0ec9dd
Packit 0ec9dd
  if (G_LIKELY (G_TRYLOCK (cached_buffer)))
Packit 0ec9dd
    {
Packit 0ec9dd
      if (G_UNLIKELY (!cached_buffer))
Packit 0ec9dd
	cached_buffer = hb_buffer_create ();
Packit 0ec9dd
Packit 0ec9dd
      buffer = cached_buffer;
Packit 0ec9dd
      *free_buffer = FALSE;
Packit 0ec9dd
    }
Packit 0ec9dd
  else
Packit 0ec9dd
    {
Packit 0ec9dd
      buffer = hb_buffer_create ();
Packit 0ec9dd
      *free_buffer = TRUE;
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  return buffer;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
release_buffer (hb_buffer_t *buffer, gboolean free_buffer)
Packit 0ec9dd
{
Packit 0ec9dd
  if (G_LIKELY (!free_buffer))
Packit 0ec9dd
    {
Packit 0ec9dd
      hb_buffer_reset (buffer);
Packit 0ec9dd
      G_UNLOCK (cached_buffer);
Packit 0ec9dd
    }
Packit 0ec9dd
  else
Packit 0ec9dd
    hb_buffer_destroy (buffer);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
typedef struct _PangoFcHbContext {
Packit 0ec9dd
  FT_Face ft_face;
Packit 0ec9dd
  PangoFcFont *fc_font;
Packit 0ec9dd
  gboolean vertical;
Packit 0ec9dd
  double x_scale, y_scale; /* CTM scales. */
Packit 0ec9dd
} PangoFcHbContext;
Packit 0ec9dd
Packit 0ec9dd
static hb_bool_t
Packit 0ec9dd
pango_fc_hb_font_get_nominal_glyph (hb_font_t *font, void *font_data,
Packit 0ec9dd
				    hb_codepoint_t unicode,
Packit 0ec9dd
				    hb_codepoint_t *glyph,
Packit 0ec9dd
				    void *user_data G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFcHbContext *context = (PangoFcHbContext *) font_data;
Packit 0ec9dd
  PangoFcFont *fc_font = context->fc_font;
Packit 0ec9dd
Packit 0ec9dd
  *glyph = pango_fc_font_get_glyph (fc_font, unicode);
Packit 0ec9dd
  if (G_LIKELY (*glyph))
Packit 0ec9dd
    return TRUE;
Packit 0ec9dd
Packit 0ec9dd
  *glyph = PANGO_GET_UNKNOWN_GLYPH (unicode);
Packit 0ec9dd
Packit 0ec9dd
  /* We draw our own invalid-Unicode shape, so prevent HarfBuzz
Packit 0ec9dd
   * from using REPLACEMENT CHARACTER. */
Packit 0ec9dd
  if (unicode > 0x10FFFF)
Packit 0ec9dd
    return TRUE;
Packit 0ec9dd
Packit 0ec9dd
  return FALSE;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static hb_bool_t
Packit 0ec9dd
pango_fc_hb_font_get_variation_glyph (hb_font_t *font,
Packit 0ec9dd
                                      void *font_data,
Packit 0ec9dd
                                      hb_codepoint_t unicode,
Packit 0ec9dd
                                      hb_codepoint_t variation_selector,
Packit 0ec9dd
                                      hb_codepoint_t *glyph,
Packit 0ec9dd
                                      void *user_data G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFcHbContext *context = (PangoFcHbContext *) font_data;
Packit 0ec9dd
  FT_Face ft_face = context->ft_face;
Packit 0ec9dd
  unsigned int g;
Packit 0ec9dd
Packit 0ec9dd
  g = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
Packit 0ec9dd
Packit 0ec9dd
  if (G_UNLIKELY (!g))
Packit 0ec9dd
    return FALSE;
Packit 0ec9dd
Packit 0ec9dd
  *glyph = g;
Packit 0ec9dd
  return TRUE;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static hb_bool_t
Packit 0ec9dd
pango_fc_hb_font_get_glyph_contour_point (hb_font_t *font, void *font_data,
Packit 0ec9dd
					  hb_codepoint_t glyph, unsigned int point_index,
Packit 0ec9dd
					  hb_position_t *x, hb_position_t *y,
Packit 0ec9dd
					  void *user_data G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
  return FALSE;
Packit 0ec9dd
#if 0
Packit 0ec9dd
  FT_Face ft_face = (FT_Face) font_data;
Packit 0ec9dd
  int load_flags = FT_LOAD_DEFAULT;
Packit 0ec9dd
Packit 0ec9dd
  /* TODO: load_flags, embolden, etc */
Packit 0ec9dd
Packit 0ec9dd
  if (HB_UNLIKELY (FT_Load_Glyph (ft_face, glyph, load_flags)))
Packit 0ec9dd
      return FALSE;
Packit 0ec9dd
Packit 0ec9dd
  if (HB_UNLIKELY (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
Packit 0ec9dd
      return FALSE;
Packit 0ec9dd
Packit 0ec9dd
  if (HB_UNLIKELY (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
Packit 0ec9dd
      return FALSE;
Packit 0ec9dd
Packit 0ec9dd
  *x = ft_face->glyph->outline.points[point_index].x;
Packit 0ec9dd
  *y = ft_face->glyph->outline.points[point_index].y;
Packit 0ec9dd
Packit 0ec9dd
  return TRUE;
Packit 0ec9dd
#endif
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static hb_position_t
Packit 0ec9dd
pango_fc_hb_font_get_glyph_advance (hb_font_t *font, void *font_data,
Packit 0ec9dd
				    hb_codepoint_t glyph,
Packit 0ec9dd
				    void *user_data G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFcHbContext *context = (PangoFcHbContext *) font_data;
Packit 0ec9dd
  PangoFcFont *fc_font = context->fc_font;
Packit 0ec9dd
  PangoRectangle logical;
Packit 0ec9dd
Packit 0ec9dd
  pango_font_get_glyph_extents ((PangoFont *) fc_font, glyph, NULL, &logical);
Packit 0ec9dd
Packit 0ec9dd
  return logical.width;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static hb_bool_t
Packit 0ec9dd
pango_fc_hb_font_get_glyph_extents (hb_font_t *font,  void *font_data,
Packit 0ec9dd
				    hb_codepoint_t glyph,
Packit 0ec9dd
				    hb_glyph_extents_t *extents,
Packit 0ec9dd
				    void *user_data G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFcHbContext *context = (PangoFcHbContext *) font_data;
Packit 0ec9dd
  PangoFcFont *fc_font = context->fc_font;
Packit 0ec9dd
  PangoRectangle ink;
Packit 0ec9dd
Packit 0ec9dd
  pango_font_get_glyph_extents ((PangoFont *) fc_font, glyph, &ink, NULL);
Packit 0ec9dd
Packit 0ec9dd
  if (G_LIKELY (!context->vertical)) {
Packit 0ec9dd
    extents->x_bearing  = ink.x;
Packit 0ec9dd
    extents->y_bearing  = ink.y;
Packit 0ec9dd
    extents->width      = ink.width;
Packit 0ec9dd
    extents->height     = ink.height;
Packit 0ec9dd
  } else {
Packit 0ec9dd
    /* XXX */
Packit 0ec9dd
    extents->x_bearing  = ink.x;
Packit 0ec9dd
    extents->y_bearing  = ink.y;
Packit 0ec9dd
    extents->width      = ink.height;
Packit 0ec9dd
    extents->height     = ink.width;
Packit 0ec9dd
  }
Packit 0ec9dd
Packit 0ec9dd
  return TRUE;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static hb_bool_t
Packit 0ec9dd
pango_fc_hb_font_get_glyph_h_origin (hb_font_t *font, void *font_data,
Packit 0ec9dd
				     hb_codepoint_t glyph,
Packit 0ec9dd
				     hb_position_t *x, hb_position_t *y,
Packit 0ec9dd
				     void *user_data G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFcHbContext *context = (PangoFcHbContext *) font_data;
Packit 0ec9dd
  FT_Face ft_face = context->ft_face;
Packit 0ec9dd
  int load_flags = FT_LOAD_DEFAULT;
Packit 0ec9dd
Packit 0ec9dd
  if (!context->vertical) return TRUE;
Packit 0ec9dd
Packit 0ec9dd
  if (FT_Load_Glyph (ft_face, glyph, load_flags))
Packit 0ec9dd
    return FALSE;
Packit 0ec9dd
Packit 0ec9dd
  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
Packit 0ec9dd
   * have a Y growing upward.  Hence the extra negations. */
Packit 0ec9dd
  *x = -PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX);
Packit 0ec9dd
  *y = +PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY));
Packit 0ec9dd
Packit 0ec9dd
  return TRUE;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static hb_bool_t
Packit 0ec9dd
pango_fc_hb_font_get_glyph_v_origin (hb_font_t *font, void *font_data,
Packit 0ec9dd
				     hb_codepoint_t glyph,
Packit 0ec9dd
				     hb_position_t *x, hb_position_t *y,
Packit 0ec9dd
				     void *user_data G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFcHbContext *context = (PangoFcHbContext *) font_data;
Packit 0ec9dd
  FT_Face ft_face = context->ft_face;
Packit 0ec9dd
  int load_flags = FT_LOAD_DEFAULT;
Packit 0ec9dd
Packit 0ec9dd
  /* pangocairo-fc configures font in vertical origin for vertical writing. */
Packit 0ec9dd
  if (context->vertical) return TRUE;
Packit 0ec9dd
Packit 0ec9dd
  if (FT_Load_Glyph (ft_face, glyph, load_flags))
Packit 0ec9dd
    return FALSE;
Packit 0ec9dd
Packit 0ec9dd
  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
Packit 0ec9dd
   * have a Y growing upward.  Hence the extra negation. */
Packit 0ec9dd
  *x = PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX);
Packit 0ec9dd
  *y = PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY));
Packit 0ec9dd
Packit 0ec9dd
  /* XXX */
Packit 0ec9dd
Packit 0ec9dd
  return TRUE;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
Packit 0ec9dd
static hb_position_t
Packit 0ec9dd
pango_fc_hb_font_get_h_kerning (hb_font_t *font, void *font_data,
Packit 0ec9dd
				hb_codepoint_t left_glyph, hb_codepoint_t right_glyph,
Packit 0ec9dd
				void *user_data G_GNUC_UNUSED)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFcHbContext *context = (PangoFcHbContext *) font_data;
Packit 0ec9dd
  FT_Face ft_face = context->ft_face;
Packit 0ec9dd
  FT_Vector kerning;
Packit 0ec9dd
Packit 0ec9dd
  if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &kerning))
Packit 0ec9dd
    return 0;
Packit 0ec9dd
Packit 0ec9dd
  return PANGO_UNITS_26_6 (kerning.x * context->x_scale);
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static hb_font_funcs_t *
Packit 0ec9dd
pango_fc_get_hb_font_funcs (void)
Packit 0ec9dd
{
Packit 0ec9dd
  static hb_font_funcs_t *funcs;
Packit 0ec9dd
Packit 0ec9dd
  if (G_UNLIKELY (!funcs)) {
Packit 0ec9dd
    funcs = hb_font_funcs_create ();
Packit 0ec9dd
    hb_font_funcs_set_nominal_glyph_func (funcs, pango_fc_hb_font_get_nominal_glyph, NULL, NULL);
Packit 0ec9dd
    hb_font_funcs_set_variation_glyph_func (funcs, pango_fc_hb_font_get_variation_glyph, NULL, NULL);
Packit 0ec9dd
    hb_font_funcs_set_glyph_h_advance_func (funcs, pango_fc_hb_font_get_glyph_advance, NULL, NULL);
Packit 0ec9dd
    hb_font_funcs_set_glyph_v_advance_func (funcs, pango_fc_hb_font_get_glyph_advance, NULL, NULL);
Packit 0ec9dd
    hb_font_funcs_set_glyph_h_origin_func (funcs, pango_fc_hb_font_get_glyph_h_origin, NULL, NULL);
Packit 0ec9dd
    hb_font_funcs_set_glyph_v_origin_func (funcs, pango_fc_hb_font_get_glyph_v_origin, NULL, NULL);
Packit 0ec9dd
    hb_font_funcs_set_glyph_h_kerning_func (funcs, pango_fc_hb_font_get_h_kerning, NULL, NULL);
Packit 0ec9dd
    /* Don't need v_kerning. */
Packit 0ec9dd
    hb_font_funcs_set_glyph_extents_func (funcs, pango_fc_hb_font_get_glyph_extents, NULL, NULL);
Packit 0ec9dd
    hb_font_funcs_set_glyph_contour_point_func (funcs, pango_fc_hb_font_get_glyph_contour_point, NULL, NULL);
Packit 0ec9dd
    /* Don't need glyph_name / glyph_from_name */
Packit 0ec9dd
  }
Packit 0ec9dd
Packit 0ec9dd
  return funcs;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
static void
Packit 0ec9dd
parse_variations (const char      *variations,
Packit 0ec9dd
                  hb_variation_t **hb_variations,
Packit 0ec9dd
                  guint           *n_variations)
Packit 0ec9dd
{
Packit 0ec9dd
  guint n;
Packit 0ec9dd
  hb_variation_t *var;
Packit 0ec9dd
  int i;
Packit 0ec9dd
  const char *p;
Packit 0ec9dd
Packit 0ec9dd
  n = 1;
Packit 0ec9dd
  for (i = 0; variations[i]; i++)
Packit 0ec9dd
    {
Packit 0ec9dd
      if (variations[i] == ',')
Packit 0ec9dd
        n++;
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  var = g_new (hb_variation_t, n);
Packit 0ec9dd
Packit 0ec9dd
  p = variations;
Packit 0ec9dd
  n = 0;
Packit 0ec9dd
  while (p && *p)
Packit 0ec9dd
    {
Packit 0ec9dd
      char *end = strchr (p, ',');
Packit 0ec9dd
      if (hb_variation_from_string (p, end ? end - p: -1, &var[n]))
Packit 0ec9dd
        n++;
Packit 0ec9dd
      p = end ? end + 1 : NULL;
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  *hb_variations = var;
Packit 0ec9dd
  *n_variations = n;
Packit 0ec9dd
}
Packit 0ec9dd
Packit 0ec9dd
void
Packit 0ec9dd
_pango_fc_shape (PangoFont           *font,
Packit 0ec9dd
		 const char          *item_text,
Packit 0ec9dd
		 unsigned int         item_length,
Packit 0ec9dd
		 const PangoAnalysis *analysis,
Packit 0ec9dd
		 PangoGlyphString    *glyphs,
Packit 0ec9dd
		 const char          *paragraph_text,
Packit 0ec9dd
		 unsigned int         paragraph_length)
Packit 0ec9dd
{
Packit 0ec9dd
  PangoFcHbContext context;
Packit 0ec9dd
  PangoFcFont *fc_font;
Packit 0ec9dd
  PangoFcFontKey *key;
Packit 0ec9dd
  FT_Face ft_face;
Packit 0ec9dd
  hb_face_t *hb_face;
Packit 0ec9dd
  hb_font_t *hb_font;
Packit 0ec9dd
  hb_buffer_t *hb_buffer;
Packit 0ec9dd
  hb_direction_t hb_direction;
Packit 0ec9dd
  gboolean free_buffer;
Packit 0ec9dd
  hb_glyph_info_t *hb_glyph;
Packit 0ec9dd
  hb_glyph_position_t *hb_position;
Packit 0ec9dd
  int last_cluster;
Packit 0ec9dd
  guint i, num_glyphs;
Packit 0ec9dd
  unsigned int item_offset = item_text - paragraph_text;
Packit 0ec9dd
  hb_feature_t features[32];
Packit 0ec9dd
  unsigned int num_features = 0;
Packit 0ec9dd
  double x_scale_inv, y_scale_inv;
Packit 0ec9dd
  PangoGlyphInfo *infos;
Packit 0ec9dd
  const char *variations;
Packit 0ec9dd
Packit 0ec9dd
  g_return_if_fail (font != NULL);
Packit 0ec9dd
  g_return_if_fail (analysis != NULL);
Packit 0ec9dd
Packit 0ec9dd
  fc_font = PANGO_FC_FONT (font);
Packit 0ec9dd
  ft_face = pango_fc_font_lock_face (fc_font);
Packit 0ec9dd
  if (!ft_face)
Packit 0ec9dd
    return;
Packit 0ec9dd
Packit 0ec9dd
  /* TODO: Cache hb_font? */
Packit 0ec9dd
Packit 0ec9dd
  x_scale_inv = y_scale_inv = 1.0;
Packit 0ec9dd
  key = _pango_fc_font_get_font_key (fc_font);
Packit 0ec9dd
  if (key)
Packit 0ec9dd
  {
Packit 0ec9dd
    const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key);
Packit 0ec9dd
    pango_matrix_get_font_scale_factors (matrix, &x_scale_inv, &y_scale_inv);
Packit 0ec9dd
  }
Packit 0ec9dd
  if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
Packit 0ec9dd
  {
Packit 0ec9dd
    x_scale_inv = -x_scale_inv;
Packit 0ec9dd
    y_scale_inv = -y_scale_inv;
Packit 0ec9dd
  }
Packit 0ec9dd
  context.x_scale = 1. / x_scale_inv;
Packit 0ec9dd
  context.y_scale = 1. / y_scale_inv;
Packit 0ec9dd
  context.ft_face = ft_face;
Packit 0ec9dd
  context.fc_font = fc_font;
Packit 0ec9dd
  context.vertical = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity);
Packit 0ec9dd
  hb_face = hb_ft_face_create_cached (ft_face);
Packit 0ec9dd
  hb_font = hb_font_create (hb_face);
Packit 0ec9dd
  hb_font_set_funcs (hb_font,
Packit 0ec9dd
		     pango_fc_get_hb_font_funcs (),
Packit 0ec9dd
		     &context,
Packit 0ec9dd
		     NULL);
Packit 0ec9dd
  hb_font_set_scale (hb_font,
Packit 0ec9dd
		     +(((gint64) ft_face->size->metrics.x_scale * ft_face->units_per_EM) >> 12) * context.x_scale,
Packit 0ec9dd
		     -(((gint64) ft_face->size->metrics.y_scale * ft_face->units_per_EM) >> 12) * context.y_scale);
Packit 0ec9dd
  hb_font_set_ppem (hb_font,
Packit 0ec9dd
		    fc_font->is_hinted ? ft_face->size->metrics.x_ppem : 0,
Packit 0ec9dd
		    fc_font->is_hinted ? ft_face->size->metrics.y_ppem : 0);
Packit 0ec9dd
Packit Service 7d211e
  if (key)
Packit Service 7d211e
  {
Packit Service 7d211e
    variations = pango_fc_font_key_get_variations (key);
Packit Service 7d211e
    if (variations)
Packit 0ec9dd
    {
Packit 0ec9dd
      guint n_variations;
Packit 0ec9dd
      hb_variation_t *hb_variations;
Packit 0ec9dd
Packit 0ec9dd
      parse_variations (variations, &hb_variations, &n_variations);
Packit 0ec9dd
      hb_font_set_variations (hb_font, hb_variations, n_variations);
Packit 0ec9dd
Packit 0ec9dd
      g_free (hb_variations);
Packit 0ec9dd
    }
Packit Service 7d211e
  }
Packit 0ec9dd
Packit 0ec9dd
  hb_buffer = acquire_buffer (&free_buffer);
Packit 0ec9dd
Packit 0ec9dd
  hb_direction = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity) ? HB_DIRECTION_TTB : HB_DIRECTION_LTR;
Packit 0ec9dd
  if (analysis->level % 2)
Packit 0ec9dd
    hb_direction = HB_DIRECTION_REVERSE (hb_direction);
Packit 0ec9dd
  if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
Packit 0ec9dd
    hb_direction = HB_DIRECTION_REVERSE (hb_direction);
Packit 0ec9dd
Packit 0ec9dd
  /* setup buffer */
Packit 0ec9dd
Packit 0ec9dd
  hb_buffer_set_direction (hb_buffer, hb_direction);
Packit 0ec9dd
  hb_buffer_set_script (hb_buffer, hb_glib_script_to_script (analysis->script));
Packit 0ec9dd
  hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis->language), -1));
Packit 0ec9dd
#if HB_VERSION_ATLEAST(1,0,3)
Packit 0ec9dd
  hb_buffer_set_cluster_level (hb_buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
Packit 0ec9dd
#endif
Packit 0ec9dd
  hb_buffer_set_flags (hb_buffer, HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
Packit 0ec9dd
Packit 0ec9dd
  hb_buffer_add_utf8 (hb_buffer, paragraph_text, paragraph_length, item_offset, item_length);
Packit 0ec9dd
Packit 0ec9dd
  /* Setup features from fontconfig pattern. */
Packit 0ec9dd
  if (fc_font->font_pattern)
Packit 0ec9dd
    {
Packit 0ec9dd
      char *s;
Packit 0ec9dd
      while (num_features < G_N_ELEMENTS (features) &&
Packit 0ec9dd
	     FcResultMatch == FcPatternGetString (fc_font->font_pattern,
Packit 0ec9dd
						  PANGO_FC_FONT_FEATURES,
Packit 0ec9dd
						  num_features,
Packit 0ec9dd
						  (FcChar8 **) &s))
Packit 0ec9dd
	{
Packit 0ec9dd
	  gboolean ret = hb_feature_from_string (s, -1, &features[num_features]);
Packit 0ec9dd
	  features[num_features].start = 0;
Packit 0ec9dd
	  features[num_features].end   = (unsigned int) -1;
Packit 0ec9dd
	  if (ret)
Packit 0ec9dd
	    num_features++;
Packit 0ec9dd
	}
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  if (analysis->extra_attrs)
Packit 0ec9dd
    {
Packit 0ec9dd
      GSList *tmp_attrs;
Packit 0ec9dd
Packit 0ec9dd
      for (tmp_attrs = analysis->extra_attrs; tmp_attrs && num_features < G_N_ELEMENTS (features); tmp_attrs = tmp_attrs->next)
Packit 0ec9dd
       {
Packit 0ec9dd
	 if (((PangoAttribute *) tmp_attrs->data)->klass->type == PANGO_ATTR_FONT_FEATURES)
Packit 0ec9dd
	   {
Packit 0ec9dd
	     const PangoAttrFontFeatures *fattr = (const PangoAttrFontFeatures *) tmp_attrs->data;
Packit 0ec9dd
	      const gchar *feat;
Packit 0ec9dd
	      const gchar *end;
Packit 0ec9dd
	      int len;
Packit 0ec9dd
Packit 0ec9dd
	      feat = fattr->features;
Packit 0ec9dd
Packit 0ec9dd
	      while (feat != NULL && num_features < G_N_ELEMENTS (features))
Packit 0ec9dd
		{
Packit 0ec9dd
		  end = strchr (feat, ',');
Packit 0ec9dd
		  if (end)
Packit 0ec9dd
		    len = end - feat;
Packit 0ec9dd
		  else
Packit 0ec9dd
		    len = -1;
Packit 0ec9dd
Packit 0ec9dd
		  if (hb_feature_from_string (feat, len, &features[num_features]))
Packit 0ec9dd
		    num_features++;
Packit 0ec9dd
Packit 0ec9dd
		  if (end == NULL)
Packit 0ec9dd
		    break;
Packit 0ec9dd
Packit 0ec9dd
		  feat = end + 1;
Packit 0ec9dd
		}
Packit 0ec9dd
	   }
Packit 0ec9dd
       }
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  hb_shape (hb_font, hb_buffer, features, num_features);
Packit 0ec9dd
Packit 0ec9dd
  if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
Packit 0ec9dd
    hb_buffer_reverse (hb_buffer);
Packit 0ec9dd
Packit 0ec9dd
  /* buffer output */
Packit 0ec9dd
  num_glyphs = hb_buffer_get_length (hb_buffer);
Packit 0ec9dd
  hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL);
Packit 0ec9dd
  pango_glyph_string_set_size (glyphs, num_glyphs);
Packit 0ec9dd
  infos = glyphs->glyphs;
Packit 0ec9dd
  last_cluster = -1;
Packit 0ec9dd
  for (i = 0; i < num_glyphs; i++)
Packit 0ec9dd
    {
Packit 0ec9dd
      infos[i].glyph = hb_glyph->codepoint;
Packit 0ec9dd
      glyphs->log_clusters[i] = hb_glyph->cluster - item_offset;
Packit 0ec9dd
      infos[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster;
Packit 0ec9dd
      hb_glyph++;
Packit 0ec9dd
      last_cluster = glyphs->log_clusters[i];
Packit 0ec9dd
    }
Packit 0ec9dd
Packit 0ec9dd
  hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL);
Packit 0ec9dd
  if (context.vertical)
Packit 0ec9dd
    for (i = 0; i < num_glyphs; i++)
Packit 0ec9dd
      {
Packit 0ec9dd
        /* 90 degrees rotation counter-clockwise. */
Packit 0ec9dd
	infos[i].geometry.width    =  hb_position->y_advance;
Packit 0ec9dd
	infos[i].geometry.x_offset =  hb_position->y_offset;
Packit 0ec9dd
	infos[i].geometry.y_offset = -hb_position->x_offset;
Packit 0ec9dd
	hb_position++;
Packit 0ec9dd
      }
Packit 0ec9dd
  else /* horizontal */
Packit 0ec9dd
    for (i = 0; i < num_glyphs; i++)
Packit 0ec9dd
      {
Packit 0ec9dd
	infos[i].geometry.width    = hb_position->x_advance;
Packit 0ec9dd
	infos[i].geometry.x_offset = hb_position->x_offset;
Packit 0ec9dd
	infos[i].geometry.y_offset = hb_position->y_offset;
Packit 0ec9dd
	hb_position++;
Packit 0ec9dd
      }
Packit 0ec9dd
Packit 0ec9dd
  if (fc_font->is_hinted)
Packit 0ec9dd
  {
Packit 0ec9dd
    if (context.x_scale == 1.0 && context.y_scale == 1.0)
Packit 0ec9dd
      {
Packit 0ec9dd
	for (i = 0; i < num_glyphs; i++)
Packit 0ec9dd
	  infos[i].geometry.width = PANGO_UNITS_ROUND (infos[i].geometry.width);
Packit 0ec9dd
      }
Packit 0ec9dd
    else
Packit 0ec9dd
      {
Packit 0ec9dd
#if 0
Packit 0ec9dd
	if (context.vertical)
Packit 0ec9dd
	  {
Packit 0ec9dd
	    /* XXX */
Packit 0ec9dd
	    double tmp = x_scale;
Packit 0ec9dd
	    x_scale = y_scale;
Packit 0ec9dd
	    y_scale = -tmp;
Packit 0ec9dd
	  }
Packit 0ec9dd
#endif
Packit 0ec9dd
#define HINT(value, scale_inv, scale) (PANGO_UNITS_ROUND ((int) ((value) * scale)) * scale_inv)
Packit 0ec9dd
#define HINT_X(value) HINT ((value), context.x_scale, x_scale_inv)
Packit 0ec9dd
#define HINT_Y(value) HINT ((value), context.y_scale, y_scale_inv)
Packit 0ec9dd
	for (i = 0; i < num_glyphs; i++)
Packit 0ec9dd
	  {
Packit 0ec9dd
	    infos[i].geometry.width    = HINT_X (infos[i].geometry.width);
Packit 0ec9dd
	    infos[i].geometry.x_offset = HINT_X (infos[i].geometry.x_offset);
Packit 0ec9dd
	    infos[i].geometry.y_offset = HINT_Y (infos[i].geometry.y_offset);
Packit 0ec9dd
	  }
Packit 0ec9dd
#undef HINT_Y
Packit 0ec9dd
#undef HINT_X
Packit 0ec9dd
#undef HINT
Packit 0ec9dd
      }
Packit 0ec9dd
  }
Packit 0ec9dd
Packit 0ec9dd
  release_buffer (hb_buffer, free_buffer);
Packit 0ec9dd
  hb_font_destroy (hb_font);
Packit 0ec9dd
  hb_face_destroy (hb_face);
Packit 0ec9dd
  pango_fc_font_unlock_face (fc_font);
Packit 0ec9dd
}