/* Pango
* pangofc-font.c: Shared interfaces for fontconfig-based backends
*
* Copyright (C) 2003 Red Hat Software
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:pangofc-font
* @short_description:Base font class for Fontconfig-based backends
* @title:PangoFcFont
* @see_also:
* #PangoFcFontMap The base class for font maps; creating a new
* Fontconfig-based backend involves deriving from both
* #PangoFcFontMap and #PangoFcFont.
*
* #PangoFcFont is a base class for font implementation using the
* Fontconfig and FreeType libraries. It is used in the
* Xft and
* FreeType
* backends shipped with Pango, but can also be used when creating
* new backends. Any backend deriving from this base class will
* take advantage of the wide range of shapers implemented using
* FreeType that come with Pango.
*/
#include "config.h"
#include "pangofc-font.h"
#include "pangofc-fontmap.h"
#include "pangofc-private.h"
#include "pango-engine.h"
#include "pango-layout.h"
#include "pango-impl-utils.h"
#include
#include FT_TRUETYPE_TABLES_H
enum {
PROP_0,
PROP_PATTERN,
PROP_FONTMAP
};
typedef struct _PangoFcFontPrivate PangoFcFontPrivate;
struct _PangoFcFontPrivate
{
PangoFcDecoder *decoder;
PangoFcFontKey *key;
PangoFcCmapCache *cmap_cache;
};
static gboolean pango_fc_font_real_has_char (PangoFcFont *font,
gunichar wc);
static guint pango_fc_font_real_get_glyph (PangoFcFont *font,
gunichar wc);
static void pango_fc_font_finalize (GObject *object);
static void pango_fc_font_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void pango_fc_font_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static PangoEngineShape * pango_fc_font_find_shaper (PangoFont *font,
PangoLanguage *language,
guint32 ch);
static PangoCoverage * pango_fc_font_get_coverage (PangoFont *font,
PangoLanguage *language);
static PangoFontMetrics * pango_fc_font_get_metrics (PangoFont *font,
PangoLanguage *language);
static PangoFontMap * pango_fc_font_get_font_map (PangoFont *font);
static PangoFontDescription *pango_fc_font_describe (PangoFont *font);
static PangoFontDescription *pango_fc_font_describe_absolute (PangoFont *font);
#define PANGO_FC_FONT_LOCK_FACE(font) (PANGO_FC_FONT_GET_CLASS (font)->lock_face (font))
#define PANGO_FC_FONT_UNLOCK_FACE(font) (PANGO_FC_FONT_GET_CLASS (font)->unlock_face (font))
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PangoFcFont, pango_fc_font, PANGO_TYPE_FONT,
G_ADD_PRIVATE (PangoFcFont))
static void
pango_fc_font_class_init (PangoFcFontClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
PangoFontClass *font_class = PANGO_FONT_CLASS (class);
class->has_char = pango_fc_font_real_has_char;
class->get_glyph = pango_fc_font_real_get_glyph;
class->get_unknown_glyph = NULL;
object_class->finalize = pango_fc_font_finalize;
object_class->set_property = pango_fc_font_set_property;
object_class->get_property = pango_fc_font_get_property;
font_class->describe = pango_fc_font_describe;
font_class->describe_absolute = pango_fc_font_describe_absolute;
font_class->find_shaper = pango_fc_font_find_shaper;
font_class->get_coverage = pango_fc_font_get_coverage;
font_class->get_metrics = pango_fc_font_get_metrics;
font_class->get_font_map = pango_fc_font_get_font_map;
g_object_class_install_property (object_class, PROP_PATTERN,
g_param_spec_pointer ("pattern",
"Pattern",
"The fontconfig pattern for this font",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_FONTMAP,
g_param_spec_object ("fontmap",
"Font Map",
"The PangoFc font map this font is associated with (Since: 1.26)",
PANGO_TYPE_FC_FONT_MAP,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
}
static void
pango_fc_font_init (PangoFcFont *fcfont)
{
fcfont->priv = pango_fc_font_get_instance_private (fcfont);
}
static void
free_metrics_info (PangoFcMetricsInfo *info)
{
pango_font_metrics_unref (info->metrics);
g_slice_free (PangoFcMetricsInfo, info);
}
static void
pango_fc_font_finalize (GObject *object)
{
PangoFcFont *fcfont = PANGO_FC_FONT (object);
PangoFcFontPrivate *priv = fcfont->priv;
PangoFcFontMap *fontmap;
g_slist_foreach (fcfont->metrics_by_lang, (GFunc)free_metrics_info, NULL);
g_slist_free (fcfont->metrics_by_lang);
fontmap = g_weak_ref_get ((GWeakRef *) &fcfont->fontmap);
if (fontmap)
{
_pango_fc_font_map_remove (PANGO_FC_FONT_MAP (fcfont->fontmap), fcfont);
g_weak_ref_clear ((GWeakRef *) &fcfont->fontmap);
g_object_unref (fontmap);
}
FcPatternDestroy (fcfont->font_pattern);
pango_font_description_free (fcfont->description);
if (priv->decoder)
_pango_fc_font_set_decoder (fcfont, NULL);
if (priv->cmap_cache)
_pango_fc_cmap_cache_unref (priv->cmap_cache);
G_OBJECT_CLASS (pango_fc_font_parent_class)->finalize (object);
}
static gboolean
pattern_is_hinted (FcPattern *pattern)
{
FcBool hinting;
if (FcPatternGetBool (pattern,
FC_HINTING, 0, &hinting) != FcResultMatch)
hinting = FcTrue;
return hinting;
}
static gboolean
pattern_is_transformed (FcPattern *pattern)
{
FcMatrix *fc_matrix;
if (FcPatternGetMatrix (pattern, FC_MATRIX, 0, &fc_matrix) == FcResultMatch)
{
FT_Matrix ft_matrix;
ft_matrix.xx = 0x10000L * fc_matrix->xx;
ft_matrix.yy = 0x10000L * fc_matrix->yy;
ft_matrix.xy = 0x10000L * fc_matrix->xy;
ft_matrix.yx = 0x10000L * fc_matrix->yx;
return ((ft_matrix.xy | ft_matrix.yx) != 0 ||
ft_matrix.xx != 0x10000L ||
ft_matrix.yy != 0x10000L);
}
else
return FALSE;
}
static void
pango_fc_font_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PangoFcFont *fcfont = PANGO_FC_FONT (object);
switch (prop_id)
{
case PROP_PATTERN:
{
FcPattern *pattern = g_value_get_pointer (value);
g_return_if_fail (pattern != NULL);
g_return_if_fail (fcfont->font_pattern == NULL);
FcPatternReference (pattern);
fcfont->font_pattern = pattern;
fcfont->description = pango_fc_font_description_from_pattern (pattern, TRUE);
fcfont->is_hinted = pattern_is_hinted (pattern);
fcfont->is_transformed = pattern_is_transformed (pattern);
}
goto set_decoder;
case PROP_FONTMAP:
{
PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (g_value_get_object (value));
g_return_if_fail (fcfont->fontmap == NULL);
g_weak_ref_set ((GWeakRef *) &fcfont->fontmap, fcfontmap);
}
goto set_decoder;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
return;
}
set_decoder:
/* set decoder if both pattern and fontmap are set now */
if (fcfont->font_pattern && fcfont->fontmap)
_pango_fc_font_set_decoder (fcfont,
pango_fc_font_map_find_decoder ((PangoFcFontMap *) fcfont->fontmap,
fcfont->font_pattern));
}
static void
pango_fc_font_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_PATTERN:
{
PangoFcFont *fcfont = PANGO_FC_FONT (object);
g_value_set_pointer (value, fcfont->font_pattern);
}
break;
case PROP_FONTMAP:
{
PangoFcFont *fcfont = PANGO_FC_FONT (object);
PangoFontMap *fontmap = g_weak_ref_get ((GWeakRef *) &fcfont->fontmap);
g_value_take_object (value, fontmap);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static PangoFontDescription *
pango_fc_font_describe (PangoFont *font)
{
PangoFcFont *fcfont = (PangoFcFont *)font;
return pango_font_description_copy (fcfont->description);
}
static PangoFontDescription *
pango_fc_font_describe_absolute (PangoFont *font)
{
PangoFcFont *fcfont = (PangoFcFont *)font;
PangoFontDescription *desc = pango_font_description_copy (fcfont->description);
double size;
if (FcPatternGetDouble (fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
pango_font_description_set_absolute_size (desc, size * PANGO_SCALE);
return desc;
}
/* Wrap shaper in PangoEngineShape to pass it through old API,
* from times when there were modules and engines. */
typedef PangoEngineShape PangoFcShapeEngine;
typedef PangoEngineShapeClass PangoFcShapeEngineClass;
static GType pango_fc_shape_engine_get_type (void) G_GNUC_CONST;
G_DEFINE_TYPE (PangoFcShapeEngine, pango_fc_shape_engine, PANGO_TYPE_ENGINE_SHAPE);
static void
_pango_fc_shape_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
PangoFont *font,
const char *item_text,
unsigned int item_length,
const PangoAnalysis *analysis,
PangoGlyphString *glyphs,
const char *paragraph_text,
unsigned int paragraph_length)
{
_pango_fc_shape (font, item_text, item_length, analysis, glyphs,
paragraph_text, paragraph_length);
}
static void
pango_fc_shape_engine_class_init (PangoEngineShapeClass *class)
{
class->script_shape = _pango_fc_shape_engine_shape;
}
static void
pango_fc_shape_engine_init (PangoEngineShape *object)
{
}
static PangoEngineShape *
pango_fc_font_find_shaper (PangoFont *font G_GNUC_UNUSED,
PangoLanguage *language,
guint32 ch)
{
static PangoEngineShape *shaper;
if (g_once_init_enter (&shaper))
g_once_init_leave (&shaper, g_object_new (pango_fc_shape_engine_get_type(), NULL));
return shaper;
}
static PangoCoverage *
pango_fc_font_get_coverage (PangoFont *font,
PangoLanguage *language G_GNUC_UNUSED)
{
PangoFcFont *fcfont = (PangoFcFont *)font;
PangoFcFontPrivate *priv = fcfont->priv;
FcCharSet *charset;
PangoFcFontMap *fontmap;
PangoCoverage *coverage;
if (priv->decoder)
{
charset = pango_fc_decoder_get_charset (priv->decoder, fcfont);
return _pango_fc_font_map_fc_to_coverage (charset);
}
fontmap = g_weak_ref_get ((GWeakRef *) &fcfont->fontmap);
if (!fontmap)
return pango_coverage_new ();
coverage = _pango_fc_font_map_get_coverage (fontmap, fcfont);
g_object_unref (fontmap);
return coverage;
}
/* For Xft, it would be slightly more efficient to simply to
* call Xft, and also more robust against changes in Xft.
* But for now, we simply use the same code for all backends.
*
* The code in this function is partly based on code from Xft,
* Copyright 2000 Keith Packard
*/
static void
get_face_metrics (PangoFcFont *fcfont,
PangoFontMetrics *metrics)
{
FT_Face face = PANGO_FC_FONT_LOCK_FACE (fcfont);
FcMatrix *fc_matrix;
FT_Matrix ft_matrix;
TT_OS2 *os2;
gboolean have_transform = FALSE;
if (G_UNLIKELY (!face))
{
metrics->descent = 0;
metrics->ascent = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_HEIGHT;
metrics->underline_thickness = PANGO_SCALE;
metrics->underline_position = - PANGO_SCALE;
metrics->strikethrough_thickness = PANGO_SCALE;
metrics->strikethrough_position = PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT/2);
return;
}
if (FcPatternGetMatrix (fcfont->font_pattern,
FC_MATRIX, 0, &fc_matrix) == FcResultMatch)
{
ft_matrix.xx = 0x10000L * fc_matrix->xx;
ft_matrix.yy = 0x10000L * fc_matrix->yy;
ft_matrix.xy = 0x10000L * fc_matrix->xy;
ft_matrix.yx = 0x10000L * fc_matrix->yx;
have_transform = (ft_matrix.xx != 0x10000 || ft_matrix.xy != 0 ||
ft_matrix.yx != 0 || ft_matrix.yy != 0x10000);
}
if (have_transform)
{
FT_Vector vector;
vector.x = 0;
vector.y = face->size->metrics.descender;
FT_Vector_Transform (&vector, &ft_matrix);
metrics->descent = - PANGO_UNITS_26_6 (vector.y);
vector.x = 0;
vector.y = face->size->metrics.ascender;
FT_Vector_Transform (&vector, &ft_matrix);
metrics->ascent = PANGO_UNITS_26_6 (vector.y);
}
else if (fcfont->is_hinted ||
(face->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
{
metrics->descent = - PANGO_UNITS_26_6 (face->size->metrics.descender);
metrics->ascent = PANGO_UNITS_26_6 (face->size->metrics.ascender);
}
else
{
FT_Fixed ascender, descender;
descender = FT_MulFix (face->descender, face->size->metrics.y_scale);
metrics->descent = - PANGO_UNITS_26_6 (descender);
ascender = FT_MulFix (face->ascender, face->size->metrics.y_scale);
metrics->ascent = PANGO_UNITS_26_6 (ascender);
}
metrics->underline_thickness = 0;
metrics->underline_position = 0;
{
FT_Fixed ft_thickness, ft_position;
ft_thickness = FT_MulFix (face->underline_thickness, face->size->metrics.y_scale);
metrics->underline_thickness = PANGO_UNITS_26_6 (ft_thickness);
ft_position = FT_MulFix (face->underline_position, face->size->metrics.y_scale);
metrics->underline_position = PANGO_UNITS_26_6 (ft_position);
}
if (metrics->underline_thickness == 0 || metrics->underline_position == 0)
{
metrics->underline_thickness = (PANGO_SCALE * face->size->metrics.y_ppem) / 14;
metrics->underline_position = - metrics->underline_thickness;
}
metrics->strikethrough_thickness = 0;
metrics->strikethrough_position = 0;
os2 = FT_Get_Sfnt_Table (face, ft_sfnt_os2);
if (os2 && os2->version != 0xFFFF)
{
FT_Fixed ft_thickness, ft_position;
ft_thickness = FT_MulFix (os2->yStrikeoutSize, face->size->metrics.y_scale);
metrics->strikethrough_thickness = PANGO_UNITS_26_6 (ft_thickness);
ft_position = FT_MulFix (os2->yStrikeoutPosition, face->size->metrics.y_scale);
metrics->strikethrough_position = PANGO_UNITS_26_6 (ft_position);
}
if (metrics->strikethrough_thickness == 0 || metrics->strikethrough_position == 0)
{
metrics->strikethrough_thickness = metrics->underline_thickness;
metrics->strikethrough_position = (PANGO_SCALE * face->size->metrics.y_ppem) / 4;
}
/* If hinting is on for this font, quantize the underline and strikethrough position
* to integer values.
*/
if (fcfont->is_hinted)
{
pango_quantize_line_geometry (&metrics->underline_thickness,
&metrics->underline_position);
pango_quantize_line_geometry (&metrics->strikethrough_thickness,
&metrics->strikethrough_position);
/* Quantizing may have pushed underline_position to 0. Not good */
if (metrics->underline_position == 0)
metrics->underline_position = - metrics->underline_thickness;
}
PANGO_FC_FONT_UNLOCK_FACE (fcfont);
}
PangoFontMetrics *
pango_fc_font_create_base_metrics_for_context (PangoFcFont *fcfont,
PangoContext *context)
{
PangoFontMetrics *metrics;
metrics = pango_font_metrics_new ();
get_face_metrics (fcfont, metrics);
return metrics;
}
static int
max_glyph_width (PangoLayout *layout)
{
int max_width = 0;
GSList *l, *r;
for (l = pango_layout_get_lines_readonly (layout); l; l = l->next)
{
PangoLayoutLine *line = l->data;
for (r = line->runs; r; r = r->next)
{
PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs;
int i;
for (i = 0; i < glyphs->num_glyphs; i++)
if (glyphs->glyphs[i].geometry.width > max_width)
max_width = glyphs->glyphs[i].geometry.width;
}
}
return max_width;
}
static PangoFontMetrics *
pango_fc_font_get_metrics (PangoFont *font,
PangoLanguage *language)
{
PangoFcFont *fcfont = PANGO_FC_FONT (font);
PangoFcMetricsInfo *info = NULL; /* Quiet gcc */
GSList *tmp_list;
const char *sample_str = pango_language_get_sample_string (language);
tmp_list = fcfont->metrics_by_lang;
while (tmp_list)
{
info = tmp_list->data;
if (info->sample_str == sample_str) /* We _don't_ need strcmp */
break;
tmp_list = tmp_list->next;
}
if (!tmp_list)
{
PangoFontMap *fontmap;
PangoContext *context;
fontmap = g_weak_ref_get ((GWeakRef *) &fcfont->fontmap);
if (!fontmap)
return pango_font_metrics_new ();
info = g_slice_new0 (PangoFcMetricsInfo);
fcfont->metrics_by_lang = g_slist_prepend (fcfont->metrics_by_lang,
info);
info->sample_str = sample_str;
context = pango_font_map_create_context (fontmap);
pango_context_set_language (context, language);
info->metrics = pango_fc_font_create_base_metrics_for_context (fcfont, context);
{ /* Compute derived metrics */
PangoLayout *layout;
PangoRectangle extents;
const char *sample_str = pango_language_get_sample_string (language);
PangoFontDescription *desc = pango_font_describe_with_absolute_size (font);
gulong sample_str_width;
layout = pango_layout_new (context);
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
pango_layout_set_text (layout, sample_str, -1);
pango_layout_get_extents (layout, NULL, &extents);
sample_str_width = pango_utf8_strwidth (sample_str);
g_assert (sample_str_width > 0);
info->metrics->approximate_char_width = extents.width / sample_str_width;
pango_layout_set_text (layout, "0123456789", -1);
info->metrics->approximate_digit_width = max_glyph_width (layout);
g_object_unref (layout);
}
g_object_unref (context);
g_object_unref (fontmap);
}
return pango_font_metrics_ref (info->metrics);
}
static PangoFontMap *
pango_fc_font_get_font_map (PangoFont *font)
{
PangoFcFont *fcfont = PANGO_FC_FONT (font);
/* MT-unsafe. Oh well... The API is unsafe. */
return fcfont->fontmap;
}
static gboolean
pango_fc_font_real_has_char (PangoFcFont *font,
gunichar wc)
{
FcCharSet *charset;
if (FcPatternGetCharSet (font->font_pattern,
FC_CHARSET, 0, &charset) != FcResultMatch)
return FALSE;
return FcCharSetHasChar (charset, wc);
}
static guint
pango_fc_font_real_get_glyph (PangoFcFont *font,
gunichar wc)
{
PangoFcFontPrivate *priv = font->priv;
FT_Face face;
FT_UInt index;
guint idx;
PangoFcCmapCacheEntry *entry;
if (G_UNLIKELY (priv->cmap_cache == NULL))
{
PangoFcFontMap *fontmap = g_weak_ref_get ((GWeakRef *) &font->fontmap);
if (G_UNLIKELY (!fontmap))
return 0;
priv->cmap_cache = _pango_fc_font_map_get_cmap_cache (fontmap, font);
g_object_unref (fontmap);
if (G_UNLIKELY (!priv->cmap_cache))
return 0;
}
idx = wc & CMAP_CACHE_MASK;
entry = priv->cmap_cache->entries + idx;
if (entry->ch != wc)
{
face = PANGO_FC_FONT_LOCK_FACE (font);
if (G_LIKELY (face))
{
index = FcFreeTypeCharIndex (face, wc);
if (index > (FT_UInt)face->num_glyphs)
index = 0;
PANGO_FC_FONT_UNLOCK_FACE (font);
}
else
index = 0;
entry->ch = wc;
entry->glyph = index;
}
return entry->glyph;
}
/**
* pango_fc_font_lock_face:
* @font: a #PangoFcFont.
*
* Gets the FreeType FT_Face associated with a font,
* This face will be kept around until you call
* pango_fc_font_unlock_face().
*
* Return value: the FreeType FT_Face associated with @font.
*
* Since: 1.4
**/
FT_Face
pango_fc_font_lock_face (PangoFcFont *font)
{
g_return_val_if_fail (PANGO_IS_FC_FONT (font), NULL);
return PANGO_FC_FONT_LOCK_FACE (font);
}
/**
* pango_fc_font_unlock_face:
* @font: a #PangoFcFont.
*
* Releases a font previously obtained with
* pango_fc_font_lock_face().
*
* Since: 1.4
**/
void
pango_fc_font_unlock_face (PangoFcFont *font)
{
g_return_if_fail (PANGO_IS_FC_FONT (font));
PANGO_FC_FONT_UNLOCK_FACE (font);
}
/**
* pango_fc_font_has_char:
* @font: a #PangoFcFont
* @wc: Unicode codepoint to look up
*
* Determines whether @font has a glyph for the codepoint @wc.
*
* Return value: %TRUE if @font has the requested codepoint.
*
* Since: 1.4
**/
gboolean
pango_fc_font_has_char (PangoFcFont *font,
gunichar wc)
{
PangoFcFontPrivate *priv = font->priv;
FcCharSet *charset;
g_return_val_if_fail (PANGO_IS_FC_FONT (font), FALSE);
if (priv->decoder)
{
charset = pango_fc_decoder_get_charset (priv->decoder, font);
return FcCharSetHasChar (charset, wc);
}
return PANGO_FC_FONT_GET_CLASS (font)->has_char (font, wc);
}
/**
* pango_fc_font_get_glyph:
* @font: a #PangoFcFont
* @wc: Unicode character to look up
*
* Gets the glyph index for a given Unicode character
* for @font. If you only want to determine
* whether the font has the glyph, use pango_fc_font_has_char().
*
* Return value: the glyph index, or 0, if the Unicode
* character doesn't exist in the font.
*
* Since: 1.4
**/
PangoGlyph
pango_fc_font_get_glyph (PangoFcFont *font,
gunichar wc)
{
PangoFcFontPrivate *priv = font->priv;
/* Replace NBSP with a normal space; it should be invariant that
* they shape the same other than breaking properties.
*/
if (wc == 0xA0)
wc = 0x20;
if (priv->decoder)
return pango_fc_decoder_get_glyph (priv->decoder, font, wc);
return PANGO_FC_FONT_GET_CLASS (font)->get_glyph (font, wc);
}
/**
* pango_fc_font_get_unknown_glyph:
* @font: a #PangoFcFont
* @wc: the Unicode character for which a glyph is needed.
*
* Returns the index of a glyph suitable for drawing @wc as an
* unknown character.
*
* Use PANGO_GET_UNKNOWN_GLYPH() instead.
*
* Return value: a glyph index into @font.
*
* Since: 1.4
**/
PangoGlyph
pango_fc_font_get_unknown_glyph (PangoFcFont *font,
gunichar wc)
{
if (font && PANGO_FC_FONT_GET_CLASS (font)->get_unknown_glyph)
return PANGO_FC_FONT_GET_CLASS (font)->get_unknown_glyph (font, wc);
return PANGO_GET_UNKNOWN_GLYPH (wc);
}
void
_pango_fc_font_shutdown (PangoFcFont *font)
{
g_return_if_fail (PANGO_IS_FC_FONT (font));
if (PANGO_FC_FONT_GET_CLASS (font)->shutdown)
PANGO_FC_FONT_GET_CLASS (font)->shutdown (font);
}
/**
* pango_fc_font_kern_glyphs:
* @font: a #PangoFcFont
* @glyphs: a #PangoGlyphString
*
* Adjust each adjacent pair of glyphs in @glyphs according to
* kerning information in @font.
*
* Since: 1.4
* Deprecated: 1.32
**/
void
pango_fc_font_kern_glyphs (PangoFcFont *font,
PangoGlyphString *glyphs)
{
FT_Face face;
FT_Error error;
FT_Vector kerning;
int i;
gboolean hinting = font->is_hinted;
gboolean scale = FALSE;
double xscale = 1;
PangoFcFontKey *key;
g_return_if_fail (PANGO_IS_FC_FONT (font));
g_return_if_fail (glyphs != NULL);
face = PANGO_FC_FONT_LOCK_FACE (font);
if (G_UNLIKELY (!face))
return;
if (!FT_HAS_KERNING (face))
{
PANGO_FC_FONT_UNLOCK_FACE (font);
return;
}
key = _pango_fc_font_get_font_key (font);
if (key) {
const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key);
PangoMatrix identity = PANGO_MATRIX_INIT;
if (G_UNLIKELY (matrix && 0 != memcmp (&identity, matrix, 2 * sizeof (double))))
{
scale = TRUE;
pango_matrix_get_font_scale_factors (matrix, &xscale, NULL);
if (xscale) xscale = 1 / xscale;
}
}
for (i = 1; i < glyphs->num_glyphs; ++i)
{
error = FT_Get_Kerning (face,
glyphs->glyphs[i-1].glyph,
glyphs->glyphs[i].glyph,
ft_kerning_default,
&kerning);
if (error == FT_Err_Ok) {
int adjustment = PANGO_UNITS_26_6 (kerning.x);
if (hinting)
adjustment = PANGO_UNITS_ROUND (adjustment);
if (G_UNLIKELY (scale))
adjustment *= xscale;
glyphs->glyphs[i-1].geometry.width += adjustment;
}
}
PANGO_FC_FONT_UNLOCK_FACE (font);
}
/**
* _pango_fc_font_get_decoder:
* @font: a #PangoFcFont
*
* This will return any custom decoder set on this font.
*
* Return value: The custom decoder
*
* Since: 1.6
**/
PangoFcDecoder *
_pango_fc_font_get_decoder (PangoFcFont *font)
{
PangoFcFontPrivate *priv = font->priv;
return priv->decoder;
}
/**
* _pango_fc_font_set_decoder:
* @font: a #PangoFcFont
* @decoder: a #PangoFcDecoder to set for this font
*
* This sets a custom decoder for this font. Any previous decoder
* will be released before this one is set.
*
* Since: 1.6
**/
void
_pango_fc_font_set_decoder (PangoFcFont *font,
PangoFcDecoder *decoder)
{
PangoFcFontPrivate *priv = font->priv;
if (priv->decoder)
g_object_unref (priv->decoder);
priv->decoder = decoder;
if (priv->decoder)
g_object_ref (priv->decoder);
}
PangoFcFontKey *
_pango_fc_font_get_font_key (PangoFcFont *fcfont)
{
PangoFcFontPrivate *priv = fcfont->priv;
return priv->key;
}
void
_pango_fc_font_set_font_key (PangoFcFont *fcfont,
PangoFcFontKey *key)
{
PangoFcFontPrivate *priv = fcfont->priv;
priv->key = key;
}
static FT_Glyph_Metrics *
get_per_char (FT_Face face,
FT_Int32 load_flags,
PangoGlyph glyph)
{
FT_Error error;
FT_Glyph_Metrics *result;
error = FT_Load_Glyph (face, glyph, load_flags);
if (error == FT_Err_Ok)
result = &face->glyph->metrics;
else
result = NULL;
return result;
}
/**
* pango_fc_font_get_raw_extents:
* @fcfont: a #PangoFcFont
* @load_flags: flags to pass to FT_Load_Glyph()
* @glyph: the glyph index to load
* @ink_rect: (out) (optional): location to store ink extents of the
* glyph, or %NULL
* @logical_rect: (out) (optional): location to store logical extents
* of the glyph or %NULL
*
* Gets the extents of a single glyph from a font. The extents are in
* user space; that is, they are not transformed by any matrix in effect
* for the font.
*
* Long term, this functionality probably belongs in the default
* implementation of the get_glyph_extents() virtual function.
* The other possibility would be to to make it public in something
* like it's current form, and also expose glyph information
* caching functionality similar to pango_ft2_font_set_glyph_info().
*
* Since: 1.6
**/
void
pango_fc_font_get_raw_extents (PangoFcFont *fcfont,
FT_Int32 load_flags,
PangoGlyph glyph,
PangoRectangle *ink_rect,
PangoRectangle *logical_rect)
{
FT_Glyph_Metrics *gm;
FT_Face face;
g_return_if_fail (PANGO_IS_FC_FONT (fcfont));
face = PANGO_FC_FONT_LOCK_FACE (fcfont);
if (G_UNLIKELY (!face))
{
/* Get generic unknown-glyph extents. */
pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect);
return;
}
if (glyph == PANGO_GLYPH_EMPTY)
gm = NULL;
else
gm = get_per_char (face, load_flags, glyph);
if (gm)
{
if (ink_rect)
{
ink_rect->x = PANGO_UNITS_26_6 (gm->horiBearingX);
ink_rect->width = PANGO_UNITS_26_6 (gm->width);
ink_rect->y = -PANGO_UNITS_26_6 (gm->horiBearingY);
ink_rect->height = PANGO_UNITS_26_6 (gm->height);
}
if (logical_rect)
{
logical_rect->x = 0;
logical_rect->width = PANGO_UNITS_26_6 (gm->horiAdvance);
if (fcfont->is_hinted ||
(face->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
{
logical_rect->y = - PANGO_UNITS_26_6 (face->size->metrics.ascender);
logical_rect->height = PANGO_UNITS_26_6 (face->size->metrics.ascender - face->size->metrics.descender);
}
else
{
FT_Fixed ascender, descender;
ascender = FT_MulFix (face->ascender, face->size->metrics.y_scale);
descender = FT_MulFix (face->descender, face->size->metrics.y_scale);
logical_rect->y = - PANGO_UNITS_26_6 (ascender);
logical_rect->height = PANGO_UNITS_26_6 (ascender - descender);
}
}
}
else
{
if (ink_rect)
{
ink_rect->x = 0;
ink_rect->width = 0;
ink_rect->y = 0;
ink_rect->height = 0;
}
if (logical_rect)
{
logical_rect->x = 0;
logical_rect->width = 0;
logical_rect->y = 0;
logical_rect->height = 0;
}
}
PANGO_FC_FONT_UNLOCK_FACE (fcfont);
}