/* Pango
* fonts.c:
*
* Copyright (C) 1999 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:fonts
* @short_description:Structures representing abstract fonts
* @title: Fonts
*
* Pango supports a flexible architecture where a
* particular rendering architecture can supply an
* implementation of fonts. The #PangoFont structure
* represents an abstract rendering-system-independent font.
* Pango provides routines to list available fonts, and
* to load a font of a given description.
*/
#include "config.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "pango-types.h"
#include "pango-font.h"
#include "pango-fontmap.h"
#include "pango-impl-utils.h"
struct _PangoFontDescription
{
char *family_name;
PangoStyle style;
PangoVariant variant;
PangoWeight weight;
PangoStretch stretch;
PangoGravity gravity;
char *variations;
guint16 mask;
guint static_family : 1;
guint static_variations : 1;
guint size_is_absolute : 1;
int size;
};
G_DEFINE_BOXED_TYPE (PangoFontDescription, pango_font_description,
pango_font_description_copy,
pango_font_description_free);
static const PangoFontDescription pfd_defaults = {
NULL, /* family_name */
PANGO_STYLE_NORMAL, /* style */
PANGO_VARIANT_NORMAL, /* variant */
PANGO_WEIGHT_NORMAL, /* weight */
PANGO_STRETCH_NORMAL, /* stretch */
PANGO_GRAVITY_SOUTH, /* gravity */
NULL, /* variations */
0, /* mask */
0, /* static_family */
0, /* static_variations*/
0, /* size_is_absolute */
0, /* size */
};
/**
* pango_font_description_new:
*
* Creates a new font description structure with all fields unset.
*
* Return value: the newly allocated #PangoFontDescription, which
* should be freed using pango_font_description_free().
**/
PangoFontDescription *
pango_font_description_new (void)
{
PangoFontDescription *desc = g_slice_new (PangoFontDescription);
*desc = pfd_defaults;
return desc;
}
/**
* pango_font_description_set_family:
* @desc: a #PangoFontDescription.
* @family: a string representing the family name.
*
* Sets the family name field of a font description. The family
* name represents a family of related font styles, and will
* resolve to a particular #PangoFontFamily. In some uses of
* #PangoFontDescription, it is also possible to use a comma
* separated list of family names for this field.
**/
void
pango_font_description_set_family (PangoFontDescription *desc,
const char *family)
{
g_return_if_fail (desc != NULL);
pango_font_description_set_family_static (desc, family ? g_strdup (family) : NULL);
if (family)
desc->static_family = FALSE;
}
/**
* pango_font_description_set_family_static:
* @desc: a #PangoFontDescription
* @family: a string representing the family name.
*
* Like pango_font_description_set_family(), except that no
* copy of @family is made. The caller must make sure that the
* string passed in stays around until @desc has been freed
* or the name is set again. This function can be used if
* @family is a static string such as a C string literal, or
* if @desc is only needed temporarily.
**/
void
pango_font_description_set_family_static (PangoFontDescription *desc,
const char *family)
{
g_return_if_fail (desc != NULL);
if (desc->family_name == family)
return;
if (desc->family_name && !desc->static_family)
g_free (desc->family_name);
if (family)
{
desc->family_name = (char *)family;
desc->static_family = TRUE;
desc->mask |= PANGO_FONT_MASK_FAMILY;
}
else
{
desc->family_name = pfd_defaults.family_name;
desc->static_family = pfd_defaults.static_family;
desc->mask &= ~PANGO_FONT_MASK_FAMILY;
}
}
/**
* pango_font_description_get_family:
* @desc: a #PangoFontDescription.
*
* Gets the family name field of a font description. See
* pango_font_description_set_family().
*
* Return value: (nullable): the family name field for the font
* description, or %NULL if not previously set. This
* has the same life-time as the font description itself
* and should not be freed.
**/
const char *
pango_font_description_get_family (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, NULL);
return desc->family_name;
}
/**
* pango_font_description_set_style:
* @desc: a #PangoFontDescription
* @style: the style for the font description
*
* Sets the style field of a #PangoFontDescription. The
* #PangoStyle enumeration describes whether the font is slanted and
* the manner in which it is slanted; it can be either
* #PANGO_STYLE_NORMAL, #PANGO_STYLE_ITALIC, or #PANGO_STYLE_OBLIQUE.
* Most fonts will either have a italic style or an oblique
* style, but not both, and font matching in Pango will
* match italic specifications with oblique fonts and vice-versa
* if an exact match is not found.
**/
void
pango_font_description_set_style (PangoFontDescription *desc,
PangoStyle style)
{
g_return_if_fail (desc != NULL);
desc->style = style;
desc->mask |= PANGO_FONT_MASK_STYLE;
}
/**
* pango_font_description_get_style:
* @desc: a #PangoFontDescription
*
* Gets the style field of a #PangoFontDescription. See
* pango_font_description_set_style().
*
* Return value: the style field for the font description.
* Use pango_font_description_get_set_fields() to find out if
* the field was explicitly set or not.
**/
PangoStyle
pango_font_description_get_style (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, pfd_defaults.style);
return desc->style;
}
/**
* pango_font_description_set_variant:
* @desc: a #PangoFontDescription
* @variant: the variant type for the font description.
*
* Sets the variant field of a font description. The #PangoVariant
* can either be %PANGO_VARIANT_NORMAL or %PANGO_VARIANT_SMALL_CAPS.
**/
void
pango_font_description_set_variant (PangoFontDescription *desc,
PangoVariant variant)
{
g_return_if_fail (desc != NULL);
desc->variant = variant;
desc->mask |= PANGO_FONT_MASK_VARIANT;
}
/**
* pango_font_description_get_variant:
* @desc: a #PangoFontDescription.
*
* Gets the variant field of a #PangoFontDescription. See
* pango_font_description_set_variant().
*
* Return value: the variant field for the font description. Use
* pango_font_description_get_set_fields() to find out if
* the field was explicitly set or not.
**/
PangoVariant
pango_font_description_get_variant (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, pfd_defaults.variant);
return desc->variant;
}
/**
* pango_font_description_set_weight:
* @desc: a #PangoFontDescription
* @weight: the weight for the font description.
*
* Sets the weight field of a font description. The weight field
* specifies how bold or light the font should be. In addition
* to the values of the #PangoWeight enumeration, other intermediate
* numeric values are possible.
**/
void
pango_font_description_set_weight (PangoFontDescription *desc,
PangoWeight weight)
{
g_return_if_fail (desc != NULL);
desc->weight = weight;
desc->mask |= PANGO_FONT_MASK_WEIGHT;
}
/**
* pango_font_description_get_weight:
* @desc: a #PangoFontDescription
*
* Gets the weight field of a font description. See
* pango_font_description_set_weight().
*
* Return value: the weight field for the font description. Use
* pango_font_description_get_set_fields() to find out if
* the field was explicitly set or not.
**/
PangoWeight
pango_font_description_get_weight (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, pfd_defaults.weight);
return desc->weight;
}
/**
* pango_font_description_set_stretch:
* @desc: a #PangoFontDescription
* @stretch: the stretch for the font description
*
* Sets the stretch field of a font description. The stretch field
* specifies how narrow or wide the font should be.
**/
void
pango_font_description_set_stretch (PangoFontDescription *desc,
PangoStretch stretch)
{
g_return_if_fail (desc != NULL);
desc->stretch = stretch;
desc->mask |= PANGO_FONT_MASK_STRETCH;
}
/**
* pango_font_description_get_stretch:
* @desc: a #PangoFontDescription.
*
* Gets the stretch field of a font description.
* See pango_font_description_set_stretch().
*
* Return value: the stretch field for the font description. Use
* pango_font_description_get_set_fields() to find out if
* the field was explicitly set or not.
**/
PangoStretch
pango_font_description_get_stretch (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, pfd_defaults.stretch);
return desc->stretch;
}
/**
* pango_font_description_set_size:
* @desc: a #PangoFontDescription
* @size: the size of the font in points, scaled by PANGO_SCALE. (That is,
* a @size value of 10 * PANGO_SCALE is a 10 point font. The conversion
* factor between points and device units depends on system configuration
* and the output device. For screen display, a logical DPI of 96 is
* common, in which case a 10 point font corresponds to a 10 * (96 / 72) = 13.3
* pixel font. Use pango_font_description_set_absolute_size() if you need
* a particular size in device units.
*
* Sets the size field of a font description in fractional points. This is mutually
* exclusive with pango_font_description_set_absolute_size().
**/
void
pango_font_description_set_size (PangoFontDescription *desc,
gint size)
{
g_return_if_fail (desc != NULL);
g_return_if_fail (size >= 0);
desc->size = size;
desc->size_is_absolute = FALSE;
desc->mask |= PANGO_FONT_MASK_SIZE;
}
/**
* pango_font_description_get_size:
* @desc: a #PangoFontDescription
*
* Gets the size field of a font description.
* See pango_font_description_set_size().
*
* Return value: the size field for the font description in points or device units.
* You must call pango_font_description_get_size_is_absolute()
* to find out which is the case. Returns 0 if the size field has not
* previously been set or it has been set to 0 explicitly.
* Use pango_font_description_get_set_fields() to
* find out if the field was explicitly set or not.
**/
gint
pango_font_description_get_size (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, pfd_defaults.size);
return desc->size;
}
/**
* pango_font_description_set_absolute_size:
* @desc: a #PangoFontDescription
* @size: the new size, in Pango units. There are %PANGO_SCALE Pango units in one
* device unit. For an output backend where a device unit is a pixel, a @size
* value of 10 * PANGO_SCALE gives a 10 pixel font.
*
* Sets the size field of a font description, in device units. This is mutually
* exclusive with pango_font_description_set_size() which sets the font size
* in points.
*
* Since: 1.8
**/
void
pango_font_description_set_absolute_size (PangoFontDescription *desc,
double size)
{
g_return_if_fail (desc != NULL);
g_return_if_fail (size >= 0);
desc->size = size;
desc->size_is_absolute = TRUE;
desc->mask |= PANGO_FONT_MASK_SIZE;
}
/**
* pango_font_description_get_size_is_absolute:
* @desc: a #PangoFontDescription
*
* Determines whether the size of the font is in points (not absolute) or device units (absolute).
* See pango_font_description_set_size() and pango_font_description_set_absolute_size().
*
* Return value: whether the size for the font description is in
* points or device units. Use pango_font_description_get_set_fields() to
* find out if the size field of the font description was explicitly set or not.
*
* Since: 1.8
**/
gboolean
pango_font_description_get_size_is_absolute (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, pfd_defaults.size_is_absolute);
return desc->size_is_absolute;
}
/**
* pango_font_description_set_gravity:
* @desc: a #PangoFontDescription
* @gravity: the gravity for the font description.
*
* Sets the gravity field of a font description. The gravity field
* specifies how the glyphs should be rotated. If @gravity is
* %PANGO_GRAVITY_AUTO, this actually unsets the gravity mask on
* the font description.
*
* This function is seldom useful to the user. Gravity should normally
* be set on a #PangoContext.
*
* Since: 1.16
**/
void
pango_font_description_set_gravity (PangoFontDescription *desc,
PangoGravity gravity)
{
g_return_if_fail (desc != NULL);
if (gravity == PANGO_GRAVITY_AUTO)
{
pango_font_description_unset_fields (desc, PANGO_FONT_MASK_GRAVITY);
return;
}
desc->gravity = gravity;
desc->mask |= PANGO_FONT_MASK_GRAVITY;
}
/**
* pango_font_description_get_gravity:
* @desc: a #PangoFontDescription
*
* Gets the gravity field of a font description. See
* pango_font_description_set_gravity().
*
* Return value: the gravity field for the font description. Use
* pango_font_description_get_set_fields() to find out if
* the field was explicitly set or not.
*
* Since: 1.16
**/
PangoGravity
pango_font_description_get_gravity (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, pfd_defaults.gravity);
return desc->gravity;
}
/**
* pango_font_description_set_variations_static:
* @desc: a #PangoFontDescription
* @variations: a string representing the variations
*
* Like pango_font_description_set_variations(), except that no
* copy of @variations is made. The caller must make sure that the
* string passed in stays around until @desc has been freed
* or the name is set again. This function can be used if
* @variations is a static string such as a C string literal, or
* if @desc is only needed temporarily.
*
* Since: 1.42
**/
void
pango_font_description_set_variations_static (PangoFontDescription *desc,
const char *variations)
{
g_return_if_fail (desc != NULL);
if (desc->variations == variations)
return;
if (desc->variations && !desc->static_variations)
g_free (desc->variations);
if (variations)
{
desc->variations = (char *)variations;
desc->static_variations = TRUE;
desc->mask |= PANGO_FONT_MASK_VARIATIONS;
}
else
{
desc->variations = pfd_defaults.variations;
desc->static_variations = pfd_defaults.static_variations;
desc->mask &= ~PANGO_FONT_MASK_VARIATIONS;
}
}
/**
* pango_font_description_set_variations:
* @desc: a #PangoFontDescription.
* @variations: a string representing the variations
*
* Sets the variations field of a font description. OpenType
* font variations allow to select a font instance by specifying
* values for a number of axes, such as width or weight.
*
* The format of the variations string is AXIS1=VALUE,AXIS2=VALUE...,
* with each AXIS a 4 character tag that identifies a font axis,
* and each VALUE a floating point number. Unknown axes are ignored,
* and values are clamped to their allowed range.
*
* Pango does not currently have a way to find supported axes of
* a font. Both harfbuzz or freetype have API for this.
*
* Since: 1.42
**/
void
pango_font_description_set_variations (PangoFontDescription *desc,
const char *variations)
{
g_return_if_fail (desc != NULL);
pango_font_description_set_variations_static (desc, g_strdup (variations));
if (variations)
desc->static_variations = FALSE;
}
/**
* pango_font_description_get_variations:
* @desc: a #PangoFontDescription
*
* Gets the variations field of a font description. See
* pango_font_description_set_variations().
*
* Return value: (nullable): the varitions field for the font
* description, or %NULL if not previously set. This
* has the same life-time as the font description itself
* and should not be freed.
*
* Since: 1.42
**/
const char *
pango_font_description_get_variations (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, NULL);
return desc->variations;
}
/**
* pango_font_description_get_set_fields:
* @desc: a #PangoFontDescription
*
* Determines which fields in a font description have been set.
*
* Return value: a bitmask with bits set corresponding to the
* fields in @desc that have been set.
**/
PangoFontMask
pango_font_description_get_set_fields (const PangoFontDescription *desc)
{
g_return_val_if_fail (desc != NULL, pfd_defaults.mask);
return desc->mask;
}
/**
* pango_font_description_unset_fields:
* @desc: a #PangoFontDescription
* @to_unset: bitmask of fields in the @desc to unset.
*
* Unsets some of the fields in a #PangoFontDescription. The unset
* fields will get back to their default values.
**/
void
pango_font_description_unset_fields (PangoFontDescription *desc,
PangoFontMask to_unset)
{
PangoFontDescription unset_desc;
g_return_if_fail (desc != NULL);
unset_desc = pfd_defaults;
unset_desc.mask = to_unset;
pango_font_description_merge_static (desc, &unset_desc, TRUE);
desc->mask &= ~to_unset;
}
/**
* pango_font_description_merge:
* @desc: a #PangoFontDescription
* @desc_to_merge: (allow-none): the #PangoFontDescription to merge from, or %NULL
* @replace_existing: if %TRUE, replace fields in @desc with the
* corresponding values from @desc_to_merge, even if they
* are already exist.
*
* Merges the fields that are set in @desc_to_merge into the fields in
* @desc. If @replace_existing is %FALSE, only fields in @desc that
* are not already set are affected. If %TRUE, then fields that are
* already set will be replaced as well.
*
* If @desc_to_merge is %NULL, this function performs nothing.
**/
void
pango_font_description_merge (PangoFontDescription *desc,
const PangoFontDescription *desc_to_merge,
gboolean replace_existing)
{
gboolean family_merged;
gboolean variations_merged;
g_return_if_fail (desc != NULL);
if (desc_to_merge == NULL)
return;
family_merged = desc_to_merge->family_name && (replace_existing || !desc->family_name);
variations_merged = desc_to_merge->variations && (replace_existing || !desc->variations);
pango_font_description_merge_static (desc, desc_to_merge, replace_existing);
if (family_merged)
{
desc->family_name = g_strdup (desc->family_name);
desc->static_family = FALSE;
}
if (variations_merged)
{
desc->variations = g_strdup (desc->variations);
desc->static_variations = FALSE;
}
}
/**
* pango_font_description_merge_static:
* @desc: a #PangoFontDescription
* @desc_to_merge: the #PangoFontDescription to merge from
* @replace_existing: if %TRUE, replace fields in @desc with the
* corresponding values from @desc_to_merge, even if they
* are already exist.
*
* Like pango_font_description_merge(), but only a shallow copy is made
* of the family name and other allocated fields. @desc can only be
* used until @desc_to_merge is modified or freed. This is meant
* to be used when the merged font description is only needed temporarily.
**/
void
pango_font_description_merge_static (PangoFontDescription *desc,
const PangoFontDescription *desc_to_merge,
gboolean replace_existing)
{
PangoFontMask new_mask;
g_return_if_fail (desc != NULL);
g_return_if_fail (desc_to_merge != NULL);
if (replace_existing)
new_mask = desc_to_merge->mask;
else
new_mask = desc_to_merge->mask & ~desc->mask;
if (new_mask & PANGO_FONT_MASK_FAMILY)
pango_font_description_set_family_static (desc, desc_to_merge->family_name);
if (new_mask & PANGO_FONT_MASK_STYLE)
desc->style = desc_to_merge->style;
if (new_mask & PANGO_FONT_MASK_VARIANT)
desc->variant = desc_to_merge->variant;
if (new_mask & PANGO_FONT_MASK_WEIGHT)
desc->weight = desc_to_merge->weight;
if (new_mask & PANGO_FONT_MASK_STRETCH)
desc->stretch = desc_to_merge->stretch;
if (new_mask & PANGO_FONT_MASK_SIZE)
{
desc->size = desc_to_merge->size;
desc->size_is_absolute = desc_to_merge->size_is_absolute;
}
if (new_mask & PANGO_FONT_MASK_GRAVITY)
desc->gravity = desc_to_merge->gravity;
if (new_mask & PANGO_FONT_MASK_VARIATIONS)
pango_font_description_set_variations_static (desc, desc_to_merge->variations);
desc->mask |= new_mask;
}
static gint
compute_distance (const PangoFontDescription *a,
const PangoFontDescription *b)
{
if (a->style == b->style)
{
return abs((int)(a->weight) - (int)(b->weight));
}
else if (a->style != PANGO_STYLE_NORMAL &&
b->style != PANGO_STYLE_NORMAL)
{
/* Equate oblique and italic, but with a big penalty
*/
return 1000000 + abs ((int)(a->weight) - (int)(b->weight));
}
else
return G_MAXINT;
}
/**
* pango_font_description_better_match:
* @desc: a #PangoFontDescription
* @old_match: (allow-none): a #PangoFontDescription, or %NULL
* @new_match: a #PangoFontDescription
*
* Determines if the style attributes of @new_match are a closer match
* for @desc than those of @old_match are, or if @old_match is %NULL,
* determines if @new_match is a match at all.
* Approximate matching is done for
* weight and style; other style attributes must match exactly.
* Style attributes are all attributes other than family and size-related
* attributes. Approximate matching for style considers PANGO_STYLE_OBLIQUE
* and PANGO_STYLE_ITALIC as matches, but not as good a match as when the
* styles are equal.
*
* Note that @old_match must match @desc.
*
* Return value: %TRUE if @new_match is a better match
**/
gboolean
pango_font_description_better_match (const PangoFontDescription *desc,
const PangoFontDescription *old_match,
const PangoFontDescription *new_match)
{
g_return_val_if_fail (desc != NULL, G_MAXINT);
g_return_val_if_fail (new_match != NULL, G_MAXINT);
if (new_match->variant == desc->variant &&
new_match->stretch == desc->stretch &&
new_match->gravity == desc->gravity)
{
int old_distance = old_match ? compute_distance (desc, old_match) : G_MAXINT;
int new_distance = compute_distance (desc, new_match);
if (new_distance < old_distance)
return TRUE;
}
return FALSE;
}
/**
* pango_font_description_copy:
* @desc: (nullable): a #PangoFontDescription, may be %NULL
*
* Make a copy of a #PangoFontDescription.
*
* Return value: (nullable): the newly allocated
* #PangoFontDescription, which should be freed with
* pango_font_description_free(), or %NULL if @desc was
* %NULL.
**/
PangoFontDescription *
pango_font_description_copy (const PangoFontDescription *desc)
{
PangoFontDescription *result;
if (desc == NULL)
return NULL;
result = g_slice_new (PangoFontDescription);
*result = *desc;
if (result->family_name)
{
result->family_name = g_strdup (result->family_name);
result->static_family = FALSE;
}
result->variations = g_strdup (result->variations);
result->static_variations = FALSE;
return result;
}
/**
* pango_font_description_copy_static:
* @desc: (nullable): a #PangoFontDescription, may be %NULL
*
* Like pango_font_description_copy(), but only a shallow copy is made
* of the family name and other allocated fields. The result can only
* be used until @desc is modified or freed. This is meant to be used
* when the copy is only needed temporarily.
*
* Return value: (nullable): the newly allocated
* #PangoFontDescription, which should be freed with
* pango_font_description_free(), or %NULL if @desc was
* %NULL.
**/
PangoFontDescription *
pango_font_description_copy_static (const PangoFontDescription *desc)
{
PangoFontDescription *result;
if (desc == NULL)
return NULL;
result = g_slice_new (PangoFontDescription);
*result = *desc;
if (result->family_name)
result->static_family = TRUE;
if (result->variations)
result->static_variations = TRUE;
return result;
}
/**
* pango_font_description_equal:
* @desc1: a #PangoFontDescription
* @desc2: another #PangoFontDescription
*
* Compares two font descriptions for equality. Two font descriptions
* are considered equal if the fonts they describe are provably identical.
* This means that their masks do not have to match, as long as other fields
* are all the same. (Two font descriptions may result in identical fonts
* being loaded, but still compare %FALSE.)
*
* Return value: %TRUE if the two font descriptions are identical,
* %FALSE otherwise.
**/
gboolean
pango_font_description_equal (const PangoFontDescription *desc1,
const PangoFontDescription *desc2)
{
g_return_val_if_fail (desc1 != NULL, FALSE);
g_return_val_if_fail (desc2 != NULL, FALSE);
return desc1->style == desc2->style &&
desc1->variant == desc2->variant &&
desc1->weight == desc2->weight &&
desc1->stretch == desc2->stretch &&
desc1->size == desc2->size &&
desc1->size_is_absolute == desc2->size_is_absolute &&
desc1->gravity == desc2->gravity &&
(desc1->family_name == desc2->family_name ||
(desc1->family_name && desc2->family_name && g_ascii_strcasecmp (desc1->family_name, desc2->family_name) == 0)) &&
(g_strcmp0 (desc1->variations, desc2->variations) == 0);
}
#define TOLOWER(c) \
(((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
static guint
case_insensitive_hash (const char *key)
{
const char *p = key;
guint h = TOLOWER (*p);
if (h)
{
for (p += 1; *p != '\0'; p++)
h = (h << 5) - h + TOLOWER (*p);
}
return h;
}
/**
* pango_font_description_hash:
* @desc: a #PangoFontDescription
*
* Computes a hash of a #PangoFontDescription structure suitable
* to be used, for example, as an argument to g_hash_table_new().
* The hash value is independent of @desc->mask.
*
* Return value: the hash value.
**/
guint
pango_font_description_hash (const PangoFontDescription *desc)
{
guint hash = 0;
g_return_val_if_fail (desc != NULL, 0);
if (desc->family_name)
hash = case_insensitive_hash (desc->family_name);
if (desc->variations)
hash ^= g_str_hash (desc->variations);
hash ^= desc->size;
hash ^= desc->size_is_absolute ? 0xc33ca55a : 0;
hash ^= desc->style << 16;
hash ^= desc->variant << 18;
hash ^= desc->weight << 16;
hash ^= desc->stretch << 26;
hash ^= desc->gravity << 28;
return hash;
}
/**
* pango_font_description_free:
* @desc: (nullable): a #PangoFontDescription, may be %NULL
*
* Frees a font description.
**/
void
pango_font_description_free (PangoFontDescription *desc)
{
if (desc == NULL)
return;
if (desc->family_name && !desc->static_family)
g_free (desc->family_name);
if (desc->variations && !desc->static_variations)
g_free (desc->variations);
g_slice_free (PangoFontDescription, desc);
}
/**
* pango_font_descriptions_free:
* @descs: (allow-none) (array length=n_descs) (transfer full): a pointer
* to an array of #PangoFontDescription, may be %NULL
* @n_descs: number of font descriptions in @descs
*
* Frees an array of font descriptions.
**/
void
pango_font_descriptions_free (PangoFontDescription **descs,
int n_descs)
{
int i;
if (descs == NULL)
return;
for (i = 0; i<n_descs; i++)
pango_font_description_free (descs[i]);
g_free (descs);
}
typedef struct
{
int value;
const char str[16];
} FieldMap;
static const FieldMap style_map[] = {
{ PANGO_STYLE_NORMAL, "" },
{ PANGO_STYLE_NORMAL, "Roman" },
{ PANGO_STYLE_OBLIQUE, "Oblique" },
{ PANGO_STYLE_ITALIC, "Italic" }
};
static const FieldMap variant_map[] = {
{ PANGO_VARIANT_NORMAL, "" },
{ PANGO_VARIANT_SMALL_CAPS, "Small-Caps" }
};
static const FieldMap weight_map[] = {
{ PANGO_WEIGHT_THIN, "Thin" },
{ PANGO_WEIGHT_ULTRALIGHT, "Ultra-Light" },
{ PANGO_WEIGHT_ULTRALIGHT, "Extra-Light" },
{ PANGO_WEIGHT_LIGHT, "Light" },
{ PANGO_WEIGHT_SEMILIGHT, "Semi-Light" },
{ PANGO_WEIGHT_SEMILIGHT, "Demi-Light" },
{ PANGO_WEIGHT_BOOK, "Book" },
{ PANGO_WEIGHT_NORMAL, "" },
{ PANGO_WEIGHT_NORMAL, "Regular" },
{ PANGO_WEIGHT_MEDIUM, "Medium" },
{ PANGO_WEIGHT_SEMIBOLD, "Semi-Bold" },
{ PANGO_WEIGHT_SEMIBOLD, "Demi-Bold" },
{ PANGO_WEIGHT_BOLD, "Bold" },
{ PANGO_WEIGHT_ULTRABOLD, "Ultra-Bold" },
{ PANGO_WEIGHT_ULTRABOLD, "Extra-Bold" },
{ PANGO_WEIGHT_HEAVY, "Heavy" },
{ PANGO_WEIGHT_HEAVY, "Black" },
{ PANGO_WEIGHT_ULTRAHEAVY, "Ultra-Heavy" },
{ PANGO_WEIGHT_ULTRAHEAVY, "Extra-Heavy" },
{ PANGO_WEIGHT_ULTRAHEAVY, "Ultra-Black" },
{ PANGO_WEIGHT_ULTRAHEAVY, "Extra-Black" }
};
static const FieldMap stretch_map[] = {
{ PANGO_STRETCH_ULTRA_CONDENSED, "Ultra-Condensed" },
{ PANGO_STRETCH_EXTRA_CONDENSED, "Extra-Condensed" },
{ PANGO_STRETCH_CONDENSED, "Condensed" },
{ PANGO_STRETCH_SEMI_CONDENSED, "Semi-Condensed" },
{ PANGO_STRETCH_NORMAL, "" },
{ PANGO_STRETCH_SEMI_EXPANDED, "Semi-Expanded" },
{ PANGO_STRETCH_EXPANDED, "Expanded" },
{ PANGO_STRETCH_EXTRA_EXPANDED, "Extra-Expanded" },
{ PANGO_STRETCH_ULTRA_EXPANDED, "Ultra-Expanded" }
};
static const FieldMap gravity_map[] = {
{ PANGO_GRAVITY_SOUTH, "Not-Rotated" },
{ PANGO_GRAVITY_SOUTH, "South" },
{ PANGO_GRAVITY_NORTH, "Upside-Down" },
{ PANGO_GRAVITY_NORTH, "North" },
{ PANGO_GRAVITY_EAST, "Rotated-Left" },
{ PANGO_GRAVITY_EAST, "East" },
{ PANGO_GRAVITY_WEST, "Rotated-Right" },
{ PANGO_GRAVITY_WEST, "West" }
};
static gboolean
field_matches (const gchar *s1,
const gchar *s2,
gsize n)
{
gint c1, c2;
g_return_val_if_fail (s1 != NULL, 0);
g_return_val_if_fail (s2 != NULL, 0);
while (n && *s1 && *s2)
{
c1 = (gint)(guchar) TOLOWER (*s1);
c2 = (gint)(guchar) TOLOWER (*s2);
if (c1 != c2) {
if (c1 == '-') {
s1++;
continue;
}
return FALSE;
}
s1++; s2++;
n--;
}
return n == 0 && *s1 == '\0';
}
static gboolean
parse_int (const char *word,
size_t wordlen,
int *out)
{
char *end;
long val = strtol (word, &end, 10);
int i = val;
if (end != word && (end == word + wordlen) && val >= 0 && val == i)
{
if (out)
*out = i;
return TRUE;
}
return FALSE;
}
static gboolean
find_field (const char *what,
const FieldMap *map,
int n_elements,
const char *str,
int len,
int *val)
{
int i;
gboolean had_prefix = FALSE;
if (what)
{
i = strlen (what);
if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
{
str += i + 1;
len -= i + 1;
had_prefix = TRUE;
}
}
for (i=0; i<n_elements; i++)
{
if (map[i].str[0] && field_matches (map[i].str, str, len))
{
if (val)
*val = map[i].value;
return TRUE;
}
}
if (!what || had_prefix)
return parse_int (str, len, val);
return FALSE;
}
static gboolean
find_field_any (const char *str, int len, PangoFontDescription *desc)
{
if (field_matches ("Normal", str, len))
return TRUE;
#define FIELD(NAME, MASK) \
G_STMT_START { \
if (find_field (G_STRINGIFY (NAME), NAME##_map, G_N_ELEMENTS (NAME##_map), str, len, \
desc ? (int *)(void *)&desc->NAME : NULL)) \
{ \
if (desc) \
desc->mask |= MASK; \
return TRUE; \
} \
} G_STMT_END
FIELD (weight, PANGO_FONT_MASK_WEIGHT);
FIELD (style, PANGO_FONT_MASK_STYLE);
FIELD (stretch, PANGO_FONT_MASK_STRETCH);
FIELD (variant, PANGO_FONT_MASK_VARIANT);
FIELD (gravity, PANGO_FONT_MASK_GRAVITY);
#undef FIELD
return FALSE;
}
static const char *
getword (const char *str, const char *last, size_t *wordlen, const char *stop)
{
const char *result;
while (last > str && g_ascii_isspace (*(last - 1)))
last--;
result = last;
while (result > str && !g_ascii_isspace (*(result - 1)) && !strchr (stop, *(result - 1)))
result--;
*wordlen = last - result;
return result;
}
static gboolean
parse_size (const char *word,
size_t wordlen,
int *pango_size,
gboolean *size_is_absolute)
{
char *end;
double size = g_ascii_strtod (word, &end);
if (end != word &&
(end == word + wordlen ||
(end + 2 == word + wordlen && !strncmp (end, "px", 2))
) && size >= 0 && size <= 1000000) /* word is a valid float */
{
if (pango_size)
*pango_size = (int)(size * PANGO_SCALE + 0.5);
if (size_is_absolute)
*size_is_absolute = end < word + wordlen;
return TRUE;
}
return FALSE;
}
static gboolean
parse_variations (const char *word,
size_t wordlen,
char **variations)
{
if (word[0] != '@')
{
*variations = NULL;
return FALSE;
}
/* XXX: actually validate here */
*variations = g_strndup (word + 1, wordlen - 1);
return TRUE;
}
/**
* pango_font_description_from_string:
* @str: string representation of a font description.
*
* Creates a new font description from a string representation in the
* form "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]", where FAMILY-LIST is a
* comma separated list of families optionally terminated by a comma,
* STYLE_OPTIONS is a whitespace separated list of words where each word
* describes one of style, variant, weight, stretch, or gravity, and SIZE
* is a decimal number (size in points) or optionally followed by the
* unit modifier "px" for absolute size. Any one of the options may
* be absent. If FAMILY-LIST is absent, then the family_name field of
* the resulting font description will be initialized to %NULL. If
* STYLE-OPTIONS is missing, then all style options will be set to the
* default values. If SIZE is missing, the size in the resulting font
* description will be set to 0.
*
* Return value: a new #PangoFontDescription.
**/
PangoFontDescription *
pango_font_description_from_string (const char *str)
{
PangoFontDescription *desc;
const char *p, *last;
size_t len, wordlen;
g_return_val_if_fail (str != NULL, NULL);
desc = pango_font_description_new ();
desc->mask = PANGO_FONT_MASK_STYLE |
PANGO_FONT_MASK_WEIGHT |
PANGO_FONT_MASK_VARIANT |
PANGO_FONT_MASK_STRETCH;
len = strlen (str);
last = str + len;
p = getword (str, last, &wordlen, "");
/* Look for variations at the end of the string */
if (wordlen != 0)
{
if (parse_variations (p, wordlen, &desc->variations))
{
desc->mask |= PANGO_FONT_MASK_VARIATIONS;
last = p;
}
}
p = getword (str, last, &wordlen, ",");
/* Look for a size */
if (wordlen != 0)
{
gboolean size_is_absolute;
if (parse_size (p, wordlen, &desc->size, &size_is_absolute))
{
desc->size_is_absolute = size_is_absolute;
desc->mask |= PANGO_FONT_MASK_SIZE;
last = p;
}
}
/* Now parse style words
*/
p = getword (str, last, &wordlen, ",");
while (wordlen != 0)
{
if (!find_field_any (p, wordlen, desc))
break;
else
{
last = p;
p = getword (str, last, &wordlen, ",");
}
}
/* Remainder (str => p) is family list. Trim off trailing commas and leading and trailing white space
*/
while (last > str && g_ascii_isspace (*(last - 1)))
last--;
if (last > str && *(last - 1) == ',')
last--;
while (last > str && g_ascii_isspace (*(last - 1)))
last--;
while (last > str && g_ascii_isspace (*str))
str++;
if (str != last)
{
int i;
char **families;
desc->family_name = g_strndup (str, last - str);
/* Now sanitize it to trim space from around individual family names.
* bug #499624 */
families = g_strsplit (desc->family_name, ",", -1);
for (i = 0; families[i]; i++)
g_strstrip (families[i]);
g_free (desc->family_name);
desc->family_name = g_strjoinv (",", families);
g_strfreev (families);
desc->mask |= PANGO_FONT_MASK_FAMILY;
}
return desc;
}
static void
append_field (GString *str, const char *what, const FieldMap *map, int n_elements, int val)
{
int i;
for (i=0; i<n_elements; i++)
{
if (map[i].value != val)
continue;
if (G_LIKELY (map[i].str[0]))
{
if (G_LIKELY (str->len > 0 && str->str[str->len -1] != ' '))
g_string_append_c (str, ' ');
g_string_append (str, map[i].str);
}
return;
}
if (G_LIKELY (str->len > 0 || str->str[str->len -1] != ' '))
g_string_append_c (str, ' ');
g_string_append_printf (str, "%s=%d", what, val);
}
/**
* pango_font_description_to_string:
* @desc: a #PangoFontDescription
*
* Creates a string representation of a font description. See
* pango_font_description_from_string() for a description of the
* format of the string representation. The family list in the
* string description will only have a terminating comma if the
* last word of the list is a valid style option.
*
* Return value: a new string that must be freed with g_free().
**/
char *
pango_font_description_to_string (const PangoFontDescription *desc)
{
GString *result;
g_return_val_if_fail (desc != NULL, NULL);
result = g_string_new (NULL);
if (G_LIKELY (desc->family_name && desc->mask & PANGO_FONT_MASK_FAMILY))
{
const char *p;
size_t wordlen;
g_string_append (result, desc->family_name);
/* We need to add a trailing comma if the family name ends
* in a keyword like "Bold", or if the family name ends in
* a number and no keywords will be added.
*/
p = getword (desc->family_name, desc->family_name + strlen(desc->family_name), &wordlen, ",");
if (wordlen != 0 &&
(find_field_any (p, wordlen, NULL) ||
(parse_size (p, wordlen, NULL, NULL) &&
desc->weight == PANGO_WEIGHT_NORMAL &&
desc->style == PANGO_STYLE_NORMAL &&
desc->stretch == PANGO_STRETCH_NORMAL &&
desc->variant == PANGO_VARIANT_NORMAL &&
(desc->mask & (PANGO_FONT_MASK_GRAVITY | PANGO_FONT_MASK_SIZE)) == 0)))
g_string_append_c (result, ',');
}
#define FIELD(NAME, MASK) \
append_field (result, G_STRINGIFY (NAME), NAME##_map, G_N_ELEMENTS (NAME##_map), desc->NAME)
FIELD (weight, PANGO_FONT_MASK_WEIGHT);
FIELD (style, PANGO_FONT_MASK_STYLE);
FIELD (stretch, PANGO_FONT_MASK_STRETCH);
FIELD (variant, PANGO_FONT_MASK_VARIANT);
if (desc->mask & PANGO_FONT_MASK_GRAVITY)
FIELD (gravity, PANGO_FONT_MASK_GRAVITY);
#undef FIELD
if (result->len == 0)
g_string_append (result, "Normal");
if (desc->mask & PANGO_FONT_MASK_SIZE)
{
char buf[G_ASCII_DTOSTR_BUF_SIZE];
if (result->len > 0 || result->str[result->len -1] != ' ')
g_string_append_c (result, ' ');
g_ascii_dtostr (buf, sizeof (buf), (double)desc->size / PANGO_SCALE);
g_string_append (result, buf);
if (desc->size_is_absolute)
g_string_append (result, "px");
}
if (desc->variations && desc->mask & PANGO_FONT_MASK_VARIATIONS)
{
g_string_append (result, " @");
g_string_append (result, desc->variations);
}
return g_string_free (result, FALSE);
}
/**
* pango_font_description_to_filename:
* @desc: a #PangoFontDescription
*
* Creates a filename representation of a font description. The
* filename is identical to the result from calling
* pango_font_description_to_string(), but with underscores instead of
* characters that are untypical in filenames, and in lower case only.
*
* Return value: a new string that must be freed with g_free().
**/
char *
pango_font_description_to_filename (const PangoFontDescription *desc)
{
char *result;
char *p;
g_return_val_if_fail (desc != NULL, NULL);
result = pango_font_description_to_string (desc);
p = result;
while (*p)
{
if (G_UNLIKELY ((guchar) *p >= 128))
/* skip over non-ASCII chars */;
else if (strchr ("-+_.", *p) == NULL && !g_ascii_isalnum (*p))
*p = '_';
else
*p = g_ascii_tolower (*p);
p++;
}
return result;
}
static gboolean
parse_field (const char *what,
const FieldMap *map,
int n_elements,
const char *str,
int *val,
gboolean warn)
{
gboolean found;
int len = strlen (str);
if (G_UNLIKELY (*str == '\0'))
return FALSE;
if (field_matches ("Normal", str, len))
{
/* find the map entry with empty string */
int i;
for (i = 0; i < n_elements; i++)
if (map[i].str[0] == '\0')
{
*val = map[i].value;
return TRUE;
}
*val = 0;
return TRUE;
}
found = find_field (NULL, map, n_elements, str, len, val);
if (!found && warn)
{
int i;
GString *s = g_string_new (NULL);
for (i = 0; i < n_elements; i++)
{
if (i)
g_string_append_c (s, '/');
g_string_append (s, map[i].str[0] == '\0' ? "Normal" : map[i].str);
}
g_warning ("%s must be one of %s or a number",
what,
s->str);
g_string_free (s, TRUE);
}
return found;
}
#define FIELD(NAME, MASK) \
parse_field (G_STRINGIFY (NAME), NAME##_map, G_N_ELEMENTS (NAME##_map), str, (int *)(void *)NAME, warn)
/**
* pango_parse_style:
* @str: a string to parse.
* @style: (out caller-allocates): a #PangoStyle to store the result
* in.
* @warn: if %TRUE, issue a g_warning() on bad input.
*
* Parses a font style. The allowed values are "normal",
* "italic" and "oblique", case variations being
* ignored.
*
* Return value: %TRUE if @str was successfully parsed.
**/
gboolean
pango_parse_style (const char *str,
PangoStyle *style,
gboolean warn)
{
return FIELD (style, PANGO_FONT_MASK_STYLE);
}
/**
* pango_parse_variant:
* @str: a string to parse.
* @variant: (out caller-allocates): a #PangoVariant to store the
* result in.
* @warn: if %TRUE, issue a g_warning() on bad input.
*
* Parses a font variant. The allowed values are "normal"
* and "smallcaps" or "small_caps", case variations being
* ignored.
*
* Return value: %TRUE if @str was successfully parsed.
**/
gboolean
pango_parse_variant (const char *str,
PangoVariant *variant,
gboolean warn)
{
return FIELD (variant, PANGO_FONT_MASK_VARIANT);
}
/**
* pango_parse_weight:
* @str: a string to parse.
* @weight: (out caller-allocates): a #PangoWeight to store the result
* in.
* @warn: if %TRUE, issue a g_warning() on bad input.
*
* Parses a font weight. The allowed values are "heavy",
* "ultrabold", "bold", "normal", "light", "ultraleight"
* and integers. Case variations are ignored.
*
* Return value: %TRUE if @str was successfully parsed.
**/
gboolean
pango_parse_weight (const char *str,
PangoWeight *weight,
gboolean warn)
{
return FIELD (weight, PANGO_FONT_MASK_WEIGHT);
}
/**
* pango_parse_stretch:
* @str: a string to parse.
* @stretch: (out caller-allocates): a #PangoStretch to store the
* result in.
* @warn: if %TRUE, issue a g_warning() on bad input.
*
* Parses a font stretch. The allowed values are
* "ultra_condensed", "extra_condensed", "condensed",
* "semi_condensed", "normal", "semi_expanded", "expanded",
* "extra_expanded" and "ultra_expanded". Case variations are
* ignored and the '_' characters may be omitted.
*
* Return value: %TRUE if @str was successfully parsed.
**/
gboolean
pango_parse_stretch (const char *str,
PangoStretch *stretch,
gboolean warn)
{
return FIELD (stretch, PANGO_FONT_MASK_STRETCH);
}
/*
* PangoFont
*/
G_DEFINE_ABSTRACT_TYPE (PangoFont, pango_font, G_TYPE_OBJECT)
static void
pango_font_class_init (PangoFontClass *class G_GNUC_UNUSED)
{
}
static void
pango_font_init (PangoFont *font G_GNUC_UNUSED)
{
}
/**
* pango_font_describe:
* @font: a #PangoFont
*
* Returns a description of the font, with font size set in points.
* Use pango_font_describe_with_absolute_size() if you want the font
* size in device units.
*
* Return value: a newly-allocated #PangoFontDescription object.
**/
PangoFontDescription *
pango_font_describe (PangoFont *font)
{
g_return_val_if_fail (font != NULL, NULL);
return PANGO_FONT_GET_CLASS (font)->describe (font);
}
/**
* pango_font_describe_with_absolute_size:
* @font: a #PangoFont
*
* Returns a description of the font, with absolute font size set
* (in device units). Use pango_font_describe() if you want the font
* size in points.
*
* Return value: a newly-allocated #PangoFontDescription object.
*
* Since: 1.14
**/
PangoFontDescription *
pango_font_describe_with_absolute_size (PangoFont *font)
{
g_return_val_if_fail (font != NULL, NULL);
if (G_UNLIKELY (!PANGO_FONT_GET_CLASS (font)->describe_absolute))
{
g_warning ("describe_absolute not implemented for this font class, report this as a bug");
return pango_font_describe (font);
}
return PANGO_FONT_GET_CLASS (font)->describe_absolute (font);
}
/**
* pango_font_get_coverage:
* @font: a #PangoFont
* @language: the language tag
*
* Computes the coverage map for a given font and language tag.
*
* Return value: (transfer full): a newly-allocated #PangoCoverage
* object.
**/
PangoCoverage *
pango_font_get_coverage (PangoFont *font,
PangoLanguage *language)
{
g_return_val_if_fail (font != NULL, NULL);
return PANGO_FONT_GET_CLASS (font)->get_coverage (font, language);
}
/**
* pango_font_find_shaper:
* @font: a #PangoFont
* @language: the language tag
* @ch: a Unicode character.
*
* Finds the best matching shaper for a font for a particular
* language tag and character point.
*
* Return value: (transfer none): the best matching shaper.
**/
PangoEngineShape *
pango_font_find_shaper (PangoFont *font,
PangoLanguage *language,
guint32 ch)
{
PangoEngineShape* shaper;
if (G_UNLIKELY (!font))
return NULL;
shaper = PANGO_FONT_GET_CLASS (font)->find_shaper (font, language, ch);
return shaper;
}
/**
* pango_font_get_glyph_extents:
* @font: (nullable): a #PangoFont
* @glyph: the glyph index
* @ink_rect: (out) (allow-none): rectangle used to store the extents of the glyph
* as drawn or %NULL to indicate that the result is not needed.
* @logical_rect: (out) (allow-none): rectangle used to store the logical extents of
* the glyph or %NULL to indicate that the result is not needed.
*
* Gets the logical and ink extents of a glyph within a font. The
* coordinate system for each rectangle has its origin at the
* base line and horizontal origin of the character with increasing
* coordinates extending to the right and down. The macros PANGO_ASCENT(),
* PANGO_DESCENT(), PANGO_LBEARING(), and PANGO_RBEARING() can be used to convert
* from the extents rectangle to more traditional font metrics. The units
* of the rectangles are in 1/PANGO_SCALE of a device unit.
*
* If @font is %NULL, this function gracefully sets some sane values in the
* output variables and returns.
**/
void
pango_font_get_glyph_extents (PangoFont *font,
PangoGlyph glyph,
PangoRectangle *ink_rect,
PangoRectangle *logical_rect)
{
if (G_UNLIKELY (!font))
{
if (ink_rect)
{
ink_rect->x = PANGO_SCALE;
ink_rect->y = - (PANGO_UNKNOWN_GLYPH_HEIGHT - 1) * PANGO_SCALE;
ink_rect->height = (PANGO_UNKNOWN_GLYPH_HEIGHT - 2) * PANGO_SCALE;
ink_rect->width = (PANGO_UNKNOWN_GLYPH_WIDTH - 2) * PANGO_SCALE;
}
if (logical_rect)
{
logical_rect->x = logical_rect->y = 0;
logical_rect->y = - PANGO_UNKNOWN_GLYPH_HEIGHT * PANGO_SCALE;
logical_rect->height = PANGO_UNKNOWN_GLYPH_HEIGHT * PANGO_SCALE;
logical_rect->width = PANGO_UNKNOWN_GLYPH_WIDTH * PANGO_SCALE;
}
return;
}
PANGO_FONT_GET_CLASS (font)->get_glyph_extents (font, glyph, ink_rect, logical_rect);
}
/**
* pango_font_get_metrics:
* @font: (nullable): a #PangoFont
* @language: (allow-none): language tag used to determine which script to get the metrics
* for, or %NULL to indicate to get the metrics for the entire font.
*
* Gets overall metric information for a font. Since the metrics may be
* substantially different for different scripts, a language tag can
* be provided to indicate that the metrics should be retrieved that
* correspond to the script(s) used by that language.
*
* If @font is %NULL, this function gracefully sets some sane values in the
* output variables and returns.
*
* Return value: a #PangoFontMetrics object. The caller must call pango_font_metrics_unref()
* when finished using the object.
**/
PangoFontMetrics *
pango_font_get_metrics (PangoFont *font,
PangoLanguage *language)
{
if (G_UNLIKELY (!font))
{
PangoFontMetrics *metrics = pango_font_metrics_new ();
metrics->ascent = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_HEIGHT;
metrics->descent = 0;
metrics->approximate_char_width = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_WIDTH;
metrics->approximate_digit_width = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_WIDTH;
metrics->underline_position = -PANGO_SCALE;
metrics->underline_thickness = PANGO_SCALE;
metrics->strikethrough_position = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_HEIGHT / 2;
metrics->strikethrough_thickness = PANGO_SCALE;
return metrics;
}
return PANGO_FONT_GET_CLASS (font)->get_metrics (font, language);
}
/**
* pango_font_get_font_map:
* @font: (nullable): a #PangoFont, or %NULL
*
* Gets the font map for which the font was created.
*
* Note that the font maintains a <firstterm>weak</firstterm> reference
* to the font map, so if all references to font map are dropped, the font
* map will be finalized even if there are fonts created with the font
* map that are still alive. In that case this function will return %NULL.
* It is the responsibility of the user to ensure that the font map is kept
* alive. In most uses this is not an issue as a #PangoContext holds
* a reference to the font map.
*
* Return value: (transfer none) (nullable): the #PangoFontMap for the
* font, or %NULL if @font is %NULL.
*
* Since: 1.10
**/
PangoFontMap *
pango_font_get_font_map (PangoFont *font)
{
if (G_UNLIKELY (!font))
return NULL;
if (PANGO_FONT_GET_CLASS (font)->get_font_map)
return PANGO_FONT_GET_CLASS (font)->get_font_map (font);
else
return NULL;
}
G_DEFINE_BOXED_TYPE (PangoFontMetrics, pango_font_metrics,
pango_font_metrics_ref,
pango_font_metrics_unref);
/**
* pango_font_metrics_new:
*
* Creates a new #PangoFontMetrics structure. This is only for
* internal use by Pango backends and there is no public way
* to set the fields of the structure.
*
* Return value: a newly-created #PangoFontMetrics structure
* with a reference count of 1.
**/
PangoFontMetrics *
pango_font_metrics_new (void)
{
PangoFontMetrics *metrics = g_slice_new0 (PangoFontMetrics);
metrics->ref_count = 1;
return metrics;
}
/**
* pango_font_metrics_ref:
* @metrics: (nullable): a #PangoFontMetrics structure, may be %NULL
*
* Increase the reference count of a font metrics structure by one.
*
* Return value: (nullable): @metrics
**/
PangoFontMetrics *
pango_font_metrics_ref (PangoFontMetrics *metrics)
{
if (metrics == NULL)
return NULL;
g_atomic_int_inc ((int *) &metrics->ref_count);
return metrics;
}
/**
* pango_font_metrics_unref:
* @metrics: (nullable): a #PangoFontMetrics structure, may be %NULL
*
* Decrease the reference count of a font metrics structure by one. If
* the result is zero, frees the structure and any associated
* memory.
**/
void
pango_font_metrics_unref (PangoFontMetrics *metrics)
{
if (metrics == NULL)
return;
g_return_if_fail (metrics->ref_count > 0 );
if (g_atomic_int_dec_and_test ((int *) &metrics->ref_count))
g_slice_free (PangoFontMetrics, metrics);
}
/**
* pango_font_metrics_get_ascent:
* @metrics: a #PangoFontMetrics structure
*
* Gets the ascent from a font metrics structure. The ascent is
* the distance from the baseline to the logical top of a line
* of text. (The logical top may be above or below the top of the
* actual drawn ink. It is necessary to lay out the text to figure
* where the ink will be.)
*
* Return value: the ascent, in Pango units.
**/
int
pango_font_metrics_get_ascent (PangoFontMetrics *metrics)
{
g_return_val_if_fail (metrics != NULL, 0);
return metrics->ascent;
}
/**
* pango_font_metrics_get_descent:
* @metrics: a #PangoFontMetrics structure
*
* Gets the descent from a font metrics structure. The descent is
* the distance from the baseline to the logical bottom of a line
* of text. (The logical bottom may be above or below the bottom of the
* actual drawn ink. It is necessary to lay out the text to figure
* where the ink will be.)
*
* Return value: the descent, in Pango units.
**/
int
pango_font_metrics_get_descent (PangoFontMetrics *metrics)
{
g_return_val_if_fail (metrics != NULL, 0);
return metrics->descent;
}
/**
* pango_font_metrics_get_approximate_char_width:
* @metrics: a #PangoFontMetrics structure
*
* Gets the approximate character width for a font metrics structure.
* This is merely a representative value useful, for example, for
* determining the initial size for a window. Actual characters in
* text will be wider and narrower than this.
*
* Return value: the character width, in Pango units.
**/
int
pango_font_metrics_get_approximate_char_width (PangoFontMetrics *metrics)
{
g_return_val_if_fail (metrics != NULL, 0);
return metrics->approximate_char_width;
}
/**
* pango_font_metrics_get_approximate_digit_width:
* @metrics: a #PangoFontMetrics structure
*
* Gets the approximate digit width for a font metrics structure.
* This is merely a representative value useful, for example, for
* determining the initial size for a window. Actual digits in
* text can be wider or narrower than this, though this value
* is generally somewhat more accurate than the result of
* pango_font_metrics_get_approximate_char_width() for digits.
*
* Return value: the digit width, in Pango units.
**/
int
pango_font_metrics_get_approximate_digit_width (PangoFontMetrics *metrics)
{
g_return_val_if_fail (metrics != NULL, 0);
return metrics->approximate_digit_width;
}
/**
* pango_font_metrics_get_underline_position:
* @metrics: a #PangoFontMetrics structure
*
* Gets the suggested position to draw the underline.
* The value returned is the distance <emphasis>above</emphasis> the
* baseline of the top of the underline. Since most fonts have
* underline positions beneath the baseline, this value is typically
* negative.
*
* Return value: the suggested underline position, in Pango units.
*
* Since: 1.6
**/
int
pango_font_metrics_get_underline_position (PangoFontMetrics *metrics)
{
g_return_val_if_fail (metrics != NULL, 0);
return metrics->underline_position;
}
/**
* pango_font_metrics_get_underline_thickness:
* @metrics: a #PangoFontMetrics structure
*
* Gets the suggested thickness to draw for the underline.
*
* Return value: the suggested underline thickness, in Pango units.
*
* Since: 1.6
**/
int
pango_font_metrics_get_underline_thickness (PangoFontMetrics *metrics)
{
g_return_val_if_fail (metrics != NULL, 0);
return metrics->underline_thickness;
}
/**
* pango_font_metrics_get_strikethrough_position:
* @metrics: a #PangoFontMetrics structure
*
* Gets the suggested position to draw the strikethrough.
* The value returned is the distance <emphasis>above</emphasis> the
* baseline of the top of the strikethrough.
*
* Return value: the suggested strikethrough position, in Pango units.
*
* Since: 1.6
**/
int
pango_font_metrics_get_strikethrough_position (PangoFontMetrics *metrics)
{
g_return_val_if_fail (metrics != NULL, 0);
return metrics->strikethrough_position;
}
/**
* pango_font_metrics_get_strikethrough_thickness:
* @metrics: a #PangoFontMetrics structure
*
* Gets the suggested thickness to draw for the strikethrough.
*
* Return value: the suggested strikethrough thickness, in Pango units.
*
* Since: 1.6
**/
int
pango_font_metrics_get_strikethrough_thickness (PangoFontMetrics *metrics)
{
g_return_val_if_fail (metrics != NULL, 0);
return metrics->strikethrough_thickness;
}
/*
* PangoFontFamily
*/
G_DEFINE_ABSTRACT_TYPE (PangoFontFamily, pango_font_family, G_TYPE_OBJECT)
static void
pango_font_family_class_init (PangoFontFamilyClass *class G_GNUC_UNUSED)
{
}
static void
pango_font_family_init (PangoFontFamily *family G_GNUC_UNUSED)
{
}
/**
* pango_font_family_get_name:
* @family: a #PangoFontFamily
*
* Gets the name of the family. The name is unique among all
* fonts for the font backend and can be used in a #PangoFontDescription
* to specify that a face from this family is desired.
*
* Return value: the name of the family. This string is owned
* by the family object and must not be modified or freed.
**/
const char *
pango_font_family_get_name (PangoFontFamily *family)
{
g_return_val_if_fail (PANGO_IS_FONT_FAMILY (family), NULL);
return PANGO_FONT_FAMILY_GET_CLASS (family)->get_name (family);
}
/**
* pango_font_family_list_faces:
* @family: a #PangoFontFamily
* @faces: (out) (allow-none) (array length=n_faces) (transfer container):
* location to store an array of pointers to #PangoFontFace objects,
* or %NULL. This array should be freed with g_free() when it is no
* longer needed.
* @n_faces: (out): location to store number of elements in @faces.
*
* Lists the different font faces that make up @family. The faces
* in a family share a common design, but differ in slant, weight,
* width and other aspects.
**/
void
pango_font_family_list_faces (PangoFontFamily *family,
PangoFontFace ***faces,
int *n_faces)
{
g_return_if_fail (PANGO_IS_FONT_FAMILY (family));
PANGO_FONT_FAMILY_GET_CLASS (family)->list_faces (family, faces, n_faces);
}
/**
* pango_font_family_is_monospace:
* @family: a #PangoFontFamily
*
* A monospace font is a font designed for text display where the the
* characters form a regular grid. For Western languages this would
* mean that the advance width of all characters are the same, but
* this categorization also includes Asian fonts which include
* double-width characters: characters that occupy two grid cells.
* g_unichar_iswide() returns a result that indicates whether a
* character is typically double-width in a monospace font.
*
* The best way to find out the grid-cell size is to call
* pango_font_metrics_get_approximate_digit_width(), since the results
* of pango_font_metrics_get_approximate_char_width() may be affected
* by double-width characters.
*
* Return value: %TRUE if the family is monospace.
*
* Since: 1.4
**/
gboolean
pango_font_family_is_monospace (PangoFontFamily *family)
{
g_return_val_if_fail (PANGO_IS_FONT_FAMILY (family), FALSE);
if (PANGO_FONT_FAMILY_GET_CLASS (family)->is_monospace)
return PANGO_FONT_FAMILY_GET_CLASS (family)->is_monospace (family);
else
return FALSE;
}
/*
* PangoFontFace
*/
G_DEFINE_ABSTRACT_TYPE (PangoFontFace, pango_font_face, G_TYPE_OBJECT)
static void
pango_font_face_class_init (PangoFontFaceClass *class G_GNUC_UNUSED)
{
}
static void
pango_font_face_init (PangoFontFace *face G_GNUC_UNUSED)
{
}
/**
* pango_font_face_describe:
* @face: a #PangoFontFace
*
* Returns the family, style, variant, weight and stretch of
* a #PangoFontFace. The size field of the resulting font description
* will be unset.
*
* Return value: a newly-created #PangoFontDescription structure
* holding the description of the face. Use pango_font_description_free()
* to free the result.
**/
PangoFontDescription *
pango_font_face_describe (PangoFontFace *face)
{
g_return_val_if_fail (PANGO_IS_FONT_FACE (face), NULL);
return PANGO_FONT_FACE_GET_CLASS (face)->describe (face);
}
/**
* pango_font_face_is_synthesized:
* @face: a #PangoFontFace
*
* Returns whether a #PangoFontFace is synthesized by the underlying
* font rendering engine from another face, perhaps by shearing, emboldening,
* or lightening it.
*
* Return value: whether @face is synthesized.
*
* Since: 1.18
**/
gboolean
pango_font_face_is_synthesized (PangoFontFace *face)
{
g_return_val_if_fail (PANGO_IS_FONT_FACE (face), FALSE);
if (PANGO_FONT_FACE_GET_CLASS (face)->is_synthesized != NULL)
return PANGO_FONT_FACE_GET_CLASS (face)->is_synthesized (face);
else
return FALSE;
}
/**
* pango_font_face_get_face_name:
* @face: a #PangoFontFace.
*
* Gets a name representing the style of this face among the
* different faces in the #PangoFontFamily for the face. This
* name is unique among all faces in the family and is suitable
* for displaying to users.
*
* Return value: the face name for the face. This string is
* owned by the face object and must not be modified or freed.
**/
const char *
pango_font_face_get_face_name (PangoFontFace *face)
{
g_return_val_if_fail (PANGO_IS_FONT_FACE (face), NULL);
return PANGO_FONT_FACE_GET_CLASS (face)->get_face_name (face);
}
/**
* pango_font_face_list_sizes:
* @face: a #PangoFontFace.
* @sizes: (out) (array length=n_sizes) (nullable) (optional):
* location to store a pointer to an array of int. This array
* should be freed with g_free().
* @n_sizes: location to store the number of elements in @sizes
*
* List the available sizes for a font. This is only applicable to bitmap
* fonts. For scalable fonts, stores %NULL at the location pointed to by
* @sizes and 0 at the location pointed to by @n_sizes. The sizes returned
* are in Pango units and are sorted in ascending order.
*
* Since: 1.4
**/
void
pango_font_face_list_sizes (PangoFontFace *face,
int **sizes,
int *n_sizes)
{
g_return_if_fail (PANGO_IS_FONT_FACE (face));
g_return_if_fail (sizes == NULL || n_sizes != NULL);
if (n_sizes == NULL)
return;
if (PANGO_FONT_FACE_GET_CLASS (face)->list_sizes != NULL)
PANGO_FONT_FACE_GET_CLASS (face)->list_sizes (face, sizes, n_sizes);
else
{
if (sizes != NULL)
*sizes = NULL;
*n_sizes = 0;
}
}