|
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 |
}
|