commit
8302da8630
4
COPYING
4
COPYING
|
@ -12,13 +12,13 @@ Copyright © 2009 Keith Stribley
|
||||||
Copyright © 2011 Martin Hosken and SIL International
|
Copyright © 2011 Martin Hosken and SIL International
|
||||||
Copyright © 2007 Chris Wilson
|
Copyright © 2007 Chris Wilson
|
||||||
Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
|
Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
|
||||||
Copyright © 2005 David Turner
|
|
||||||
Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
|
Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
|
||||||
Copyright © 1998-2004 David Turner and Werner Lemberg
|
Copyright © 1998-2005 David Turner and Werner Lemberg
|
||||||
Copyright © 2016 Igalia S.L.
|
Copyright © 2016 Igalia S.L.
|
||||||
Copyright © 2022 Matthias Clasen
|
Copyright © 2022 Matthias Clasen
|
||||||
Copyright © 2018,2021 Khaled Hosny
|
Copyright © 2018,2021 Khaled Hosny
|
||||||
Copyright © 2018,2019,2020 Adobe, Inc
|
Copyright © 2018,2019,2020 Adobe, Inc
|
||||||
|
Copyright © 2013-2015 Alexei Podtelezhnikov
|
||||||
|
|
||||||
For full copyright notices consult the individual files in the package.
|
For full copyright notices consult the individual files in the package.
|
||||||
|
|
||||||
|
|
|
@ -416,6 +416,8 @@ hb_font_set_ptem
|
||||||
hb_font_get_ptem
|
hb_font_get_ptem
|
||||||
hb_font_set_scale
|
hb_font_set_scale
|
||||||
hb_font_get_scale
|
hb_font_get_scale
|
||||||
|
hb_font_get_synthetic_bold
|
||||||
|
hb_font_set_synthetic_bold
|
||||||
hb_font_set_synthetic_slant
|
hb_font_set_synthetic_slant
|
||||||
hb_font_get_synthetic_slant
|
hb_font_get_synthetic_slant
|
||||||
hb_font_set_variations
|
hb_font_set_variations
|
||||||
|
|
|
@ -85,6 +85,8 @@ HB_BASE_sources = \
|
||||||
hb-ot-layout-common.hh \
|
hb-ot-layout-common.hh \
|
||||||
hb-ot-layout-gdef-table.hh \
|
hb-ot-layout-gdef-table.hh \
|
||||||
hb-ot-layout-gpos-table.hh \
|
hb-ot-layout-gpos-table.hh \
|
||||||
|
hb-outline.hh \
|
||||||
|
hb-outline.cc \
|
||||||
hb-paint.cc \
|
hb-paint.cc \
|
||||||
hb-paint.hh \
|
hb-paint.hh \
|
||||||
hb-paint-extents.cc \
|
hb-paint-extents.cc \
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "hb-ot-shaper-vowel-constraints.cc"
|
#include "hb-ot-shaper-vowel-constraints.cc"
|
||||||
#include "hb-ot-tag.cc"
|
#include "hb-ot-tag.cc"
|
||||||
#include "hb-ot-var.cc"
|
#include "hb-ot-var.cc"
|
||||||
|
#include "hb-outline.cc"
|
||||||
#include "hb-paint-extents.cc"
|
#include "hb-paint-extents.cc"
|
||||||
#include "hb-paint.cc"
|
#include "hb-paint.cc"
|
||||||
#include "hb-set.cc"
|
#include "hb-set.cc"
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "hb-ot-shaper-vowel-constraints.cc"
|
#include "hb-ot-shaper-vowel-constraints.cc"
|
||||||
#include "hb-ot-tag.cc"
|
#include "hb-ot-tag.cc"
|
||||||
#include "hb-ot-var.cc"
|
#include "hb-ot-var.cc"
|
||||||
|
#include "hb-outline.cc"
|
||||||
#include "hb-paint-extents.cc"
|
#include "hb-paint-extents.cc"
|
||||||
#include "hb-paint.cc"
|
#include "hb-paint.cc"
|
||||||
#include "hb-set.cc"
|
#include "hb-set.cc"
|
||||||
|
|
|
@ -1772,8 +1772,13 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
|
||||||
|
|
||||||
1000, /* x_scale */
|
1000, /* x_scale */
|
||||||
1000, /* y_scale */
|
1000, /* y_scale */
|
||||||
0., /* slant */
|
0.f, /* x_embolden */
|
||||||
0., /* slant_xy; */
|
0.f, /* y_embolden */
|
||||||
|
true, /* embolden_in_place */
|
||||||
|
0, /* x_strength */
|
||||||
|
0, /* y_strength */
|
||||||
|
0.f, /* slant */
|
||||||
|
0.f, /* slant_xy; */
|
||||||
1.f, /* x_multf */
|
1.f, /* x_multf */
|
||||||
1.f, /* y_multf */
|
1.f, /* y_multf */
|
||||||
1<<16, /* x_mult */
|
1<<16, /* x_mult */
|
||||||
|
@ -1811,6 +1816,7 @@ _hb_font_create (hb_face_t *face)
|
||||||
font->klass = hb_font_funcs_get_empty ();
|
font->klass = hb_font_funcs_get_empty ();
|
||||||
font->data.init0 (font);
|
font->data.init0 (font);
|
||||||
font->x_scale = font->y_scale = face->get_upem ();
|
font->x_scale = font->y_scale = face->get_upem ();
|
||||||
|
font->embolden_in_place = true;
|
||||||
font->x_multf = font->y_multf = 1.f;
|
font->x_multf = font->y_multf = 1.f;
|
||||||
font->x_mult = font->y_mult = 1 << 16;
|
font->x_mult = font->y_mult = 1 << 16;
|
||||||
font->instance_index = HB_FONT_NO_VAR_NAMED_INSTANCE;
|
font->instance_index = HB_FONT_NO_VAR_NAMED_INSTANCE;
|
||||||
|
@ -1895,6 +1901,9 @@ hb_font_create_sub_font (hb_font_t *parent)
|
||||||
|
|
||||||
font->x_scale = parent->x_scale;
|
font->x_scale = parent->x_scale;
|
||||||
font->y_scale = parent->y_scale;
|
font->y_scale = parent->y_scale;
|
||||||
|
font->x_embolden = parent->x_embolden;
|
||||||
|
font->y_embolden = parent->y_embolden;
|
||||||
|
font->embolden_in_place = parent->embolden_in_place;
|
||||||
font->slant = parent->slant;
|
font->slant = parent->slant;
|
||||||
font->x_ppem = parent->x_ppem;
|
font->x_ppem = parent->x_ppem;
|
||||||
font->y_ppem = parent->y_ppem;
|
font->y_ppem = parent->y_ppem;
|
||||||
|
@ -2442,6 +2451,76 @@ hb_font_get_ptem (hb_font_t *font)
|
||||||
return font->ptem;
|
return font->ptem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_font_set_synthetic_bold:
|
||||||
|
* @font: #hb_font_t to work upon
|
||||||
|
* @x_embolden: the amount to embolden horizontally
|
||||||
|
* @y_embolden: the amount to embolden vertically
|
||||||
|
* @in_place: whether to embolden glyphs in-place
|
||||||
|
*
|
||||||
|
* Sets the "synthetic boldness" of a font.
|
||||||
|
*
|
||||||
|
* Positive values for @x_embolden / @y_embolden make a font
|
||||||
|
* bolder, negative values thinner. Typical values are in the
|
||||||
|
* 0.01 to 0.05 range. The default value is zero.
|
||||||
|
*
|
||||||
|
* Synthetic boldness is applied by offsetting the contour
|
||||||
|
* points of the glyph shape.
|
||||||
|
*
|
||||||
|
* Synthetic boldness is applied when rendering a glyph via
|
||||||
|
* hb_font_draw_glyph().
|
||||||
|
*
|
||||||
|
* If @in_place is %FALSE, then glyph advance-widths are also
|
||||||
|
* adjusted, otherwise they are not. The in-place mode is
|
||||||
|
* useful for simulating [font grading](https://fonts.google.com/knowledge/glossary/grade).
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Since: REPLACEME
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
hb_font_set_synthetic_bold (hb_font_t *font,
|
||||||
|
float x_embolden,
|
||||||
|
float y_embolden,
|
||||||
|
hb_bool_t in_place)
|
||||||
|
{
|
||||||
|
if (hb_object_is_immutable (font))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (font->x_embolden == x_embolden &&
|
||||||
|
font->y_embolden == y_embolden &&
|
||||||
|
font->embolden_in_place == in_place)
|
||||||
|
return;
|
||||||
|
|
||||||
|
font->serial++;
|
||||||
|
|
||||||
|
font->x_embolden = x_embolden;
|
||||||
|
font->y_embolden = y_embolden;
|
||||||
|
font->embolden_in_place = in_place;
|
||||||
|
font->mults_changed ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_font_get_synthetic_bold:
|
||||||
|
* @font: #hb_font_t to work upon
|
||||||
|
* @x_embolden: (out): return location for horizontal value
|
||||||
|
* @y_embolden: (out): return location for vertical value
|
||||||
|
* @in_place: (out): return location for in-place value
|
||||||
|
*
|
||||||
|
* Fetches the "synthetic boldness" parameters of a font.
|
||||||
|
*
|
||||||
|
* Since: REPLACEME
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
hb_font_get_synthetic_bold (hb_font_t *font,
|
||||||
|
float *x_embolden,
|
||||||
|
float *y_embolden,
|
||||||
|
hb_bool_t *in_place)
|
||||||
|
{
|
||||||
|
if (x_embolden) *x_embolden = font->x_embolden;
|
||||||
|
if (y_embolden) *y_embolden = font->y_embolden;
|
||||||
|
if (in_place) *in_place = font->embolden_in_place;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hb_font_set_synthetic_slant:
|
* hb_font_set_synthetic_slant:
|
||||||
* @font: #hb_font_t to work upon
|
* @font: #hb_font_t to work upon
|
||||||
|
|
|
@ -1131,6 +1131,16 @@ hb_font_set_ptem (hb_font_t *font, float ptem);
|
||||||
HB_EXTERN float
|
HB_EXTERN float
|
||||||
hb_font_get_ptem (hb_font_t *font);
|
hb_font_get_ptem (hb_font_t *font);
|
||||||
|
|
||||||
|
HB_EXTERN void
|
||||||
|
hb_font_set_synthetic_bold (hb_font_t *font,
|
||||||
|
float x_embolden, float y_embolden,
|
||||||
|
hb_bool_t in_place);
|
||||||
|
|
||||||
|
HB_EXTERN void
|
||||||
|
hb_font_get_synthetic_bold (hb_font_t *font,
|
||||||
|
float *x_embolden, float *y_embolden,
|
||||||
|
hb_bool_t *in_place);
|
||||||
|
|
||||||
HB_EXTERN void
|
HB_EXTERN void
|
||||||
hb_font_set_synthetic_slant (hb_font_t *font, float slant);
|
hb_font_set_synthetic_slant (hb_font_t *font, float slant);
|
||||||
|
|
||||||
|
|
|
@ -113,8 +113,16 @@ struct hb_font_t
|
||||||
|
|
||||||
int32_t x_scale;
|
int32_t x_scale;
|
||||||
int32_t y_scale;
|
int32_t y_scale;
|
||||||
|
|
||||||
|
float x_embolden;
|
||||||
|
float y_embolden;
|
||||||
|
bool embolden_in_place;
|
||||||
|
int32_t x_strength; /* x_embolden, in scaled units. */
|
||||||
|
int32_t y_strength; /* y_embolden, in scaled units. */
|
||||||
|
|
||||||
float slant;
|
float slant;
|
||||||
float slant_xy;
|
float slant_xy;
|
||||||
|
|
||||||
float x_multf;
|
float x_multf;
|
||||||
float y_multf;
|
float y_multf;
|
||||||
int64_t x_mult;
|
int64_t x_mult;
|
||||||
|
@ -200,6 +208,21 @@ struct hb_font_t
|
||||||
extents->width = ceilf (x2) - extents->x_bearing;
|
extents->width = ceilf (x2) - extents->x_bearing;
|
||||||
extents->height = ceilf (y2) - extents->y_bearing;
|
extents->height = ceilf (y2) - extents->y_bearing;
|
||||||
|
|
||||||
|
if (x_strength || y_strength)
|
||||||
|
{
|
||||||
|
/* Y */
|
||||||
|
int y_shift = y_strength;
|
||||||
|
if (y_scale < 0) y_shift = -y_shift;
|
||||||
|
extents->y_bearing += y_shift;
|
||||||
|
extents->height -= y_shift;
|
||||||
|
|
||||||
|
/* X */
|
||||||
|
int x_shift = x_strength;
|
||||||
|
if (x_scale < 0) x_shift = -x_shift;
|
||||||
|
if (embolden_in_place)
|
||||||
|
extents->x_bearing -= x_shift / 2;
|
||||||
|
extents->width += x_shift;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -666,12 +689,17 @@ struct hb_font_t
|
||||||
void mults_changed ()
|
void mults_changed ()
|
||||||
{
|
{
|
||||||
float upem = face->get_upem ();
|
float upem = face->get_upem ();
|
||||||
|
|
||||||
x_multf = x_scale / upem;
|
x_multf = x_scale / upem;
|
||||||
y_multf = y_scale / upem;
|
y_multf = y_scale / upem;
|
||||||
bool x_neg = x_scale < 0;
|
bool x_neg = x_scale < 0;
|
||||||
x_mult = (x_neg ? -((int64_t) -x_scale << 16) : ((int64_t) x_scale << 16)) / upem;
|
x_mult = (x_neg ? -((int64_t) -x_scale << 16) : ((int64_t) x_scale << 16)) / upem;
|
||||||
bool y_neg = y_scale < 0;
|
bool y_neg = y_scale < 0;
|
||||||
y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem;
|
y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem;
|
||||||
|
|
||||||
|
x_strength = fabs (roundf (x_scale * x_embolden));
|
||||||
|
y_strength = fabs (roundf (y_scale * y_embolden));
|
||||||
|
|
||||||
slant_xy = y_scale ? slant * x_scale / y_scale : 0.f;
|
slant_xy = y_scale ? slant * x_scale / y_scale : 0.f;
|
||||||
|
|
||||||
data.fini ();
|
data.fini ();
|
||||||
|
|
69
src/hb-ft.cc
69
src/hb-ft.cc
|
@ -45,6 +45,7 @@
|
||||||
#include FT_MULTIPLE_MASTERS_H
|
#include FT_MULTIPLE_MASTERS_H
|
||||||
#include FT_OUTLINE_H
|
#include FT_OUTLINE_H
|
||||||
#include FT_TRUETYPE_TABLES_H
|
#include FT_TRUETYPE_TABLES_H
|
||||||
|
#include FT_SYNTHESIS_H
|
||||||
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
|
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300
|
||||||
#include FT_COLOR_H
|
#include FT_COLOR_H
|
||||||
#endif
|
#endif
|
||||||
|
@ -447,6 +448,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
||||||
void *user_data HB_UNUSED)
|
void *user_data HB_UNUSED)
|
||||||
{
|
{
|
||||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||||
|
hb_position_t *orig_first_advance = first_advance;
|
||||||
hb_lock_t lock (ft_font->lock);
|
hb_lock_t lock (ft_font->lock);
|
||||||
FT_Face ft_face = ft_font->ft_face;
|
FT_Face ft_face = ft_font->ft_face;
|
||||||
int load_flags = ft_font->load_flags;
|
int load_flags = ft_font->load_flags;
|
||||||
|
@ -487,6 +489,18 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
||||||
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
|
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
|
||||||
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
|
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (font->x_strength && !font->embolden_in_place)
|
||||||
|
{
|
||||||
|
/* Emboldening. */
|
||||||
|
hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength;
|
||||||
|
first_advance = orig_first_advance;
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
*first_advance += *first_advance ? x_strength : 0;
|
||||||
|
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HB_NO_VERTICAL
|
#ifndef HB_NO_VERTICAL
|
||||||
|
@ -522,7 +536,8 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
|
||||||
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
|
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
|
||||||
* have a Y growing upward. Hence the extra negation. */
|
* have a Y growing upward. Hence the extra negation. */
|
||||||
|
|
||||||
return (-v + (1<<9)) >> 10;
|
hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength;
|
||||||
|
return ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -642,6 +657,22 @@ hb_ft_get_glyph_extents (hb_font_t *font,
|
||||||
extents->width = ceilf (x2) - extents->x_bearing;
|
extents->width = ceilf (x2) - extents->x_bearing;
|
||||||
extents->height = ceilf (y2) - extents->y_bearing;
|
extents->height = ceilf (y2) - extents->y_bearing;
|
||||||
|
|
||||||
|
if (font->x_strength || font->y_strength)
|
||||||
|
{
|
||||||
|
/* Y */
|
||||||
|
int y_shift = font->y_strength;
|
||||||
|
if (font->y_scale < 0) y_shift = -y_shift;
|
||||||
|
extents->y_bearing += y_shift;
|
||||||
|
extents->height -= y_shift;
|
||||||
|
|
||||||
|
/* X */
|
||||||
|
int x_shift = font->x_strength;
|
||||||
|
if (font->x_scale < 0) x_shift = -x_shift;
|
||||||
|
if (font->embolden_in_place)
|
||||||
|
extents->x_bearing -= x_shift / 2;
|
||||||
|
extents->width += x_shift;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,7 +794,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
|
||||||
metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
|
metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender);
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics->ascender = (hb_position_t) (y_mult * metrics->ascender);
|
metrics->ascender = (hb_position_t) (y_mult * (metrics->ascender + font->y_strength));
|
||||||
metrics->descender = (hb_position_t) (y_mult * metrics->descender);
|
metrics->descender = (hb_position_t) (y_mult * metrics->descender);
|
||||||
metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap);
|
metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap);
|
||||||
|
|
||||||
|
@ -815,7 +846,7 @@ _hb_ft_cubic_to (const FT_Vector *control1,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hb_ft_draw_glyph (hb_font_t *font HB_UNUSED,
|
hb_ft_draw_glyph (hb_font_t *font,
|
||||||
void *font_data,
|
void *font_data,
|
||||||
hb_codepoint_t glyph,
|
hb_codepoint_t glyph,
|
||||||
hb_draw_funcs_t *draw_funcs, void *draw_data,
|
hb_draw_funcs_t *draw_funcs, void *draw_data,
|
||||||
|
@ -843,6 +874,38 @@ hb_ft_draw_glyph (hb_font_t *font HB_UNUSED,
|
||||||
|
|
||||||
hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
|
hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
|
||||||
|
|
||||||
|
/* Embolden */
|
||||||
|
if (font->x_strength || font->y_strength)
|
||||||
|
{
|
||||||
|
FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_strength, font->y_strength);
|
||||||
|
|
||||||
|
int x_shift = 0;
|
||||||
|
int y_shift = 0;
|
||||||
|
if (font->embolden_in_place)
|
||||||
|
{
|
||||||
|
/* Undo the FreeType shift. */
|
||||||
|
x_shift = -font->x_strength / 2;
|
||||||
|
y_shift = 0;
|
||||||
|
if (font->y_scale < 0) y_shift = -font->y_strength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* FreeType applied things in the wrong direction for negative scale; fix up. */
|
||||||
|
if (font->x_scale < 0) x_shift = -font->x_strength;
|
||||||
|
if (font->y_scale < 0) y_shift = -font->y_strength;
|
||||||
|
}
|
||||||
|
if (x_shift || y_shift)
|
||||||
|
{
|
||||||
|
auto &outline = ft_face->glyph->outline;
|
||||||
|
for (auto &point : hb_iter (outline.points, outline.contours[outline.n_contours - 1] + 1))
|
||||||
|
{
|
||||||
|
point.x += x_shift;
|
||||||
|
point.y += y_shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FT_Outline_Decompose (&ft_face->glyph->outline,
|
FT_Outline_Decompose (&ft_face->glyph->outline,
|
||||||
&outline_funcs,
|
&outline_funcs,
|
||||||
&draw_session);
|
&draw_session);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "hb-font.hh"
|
#include "hb-font.hh"
|
||||||
#include "hb-machinery.hh"
|
#include "hb-machinery.hh"
|
||||||
#include "hb-ot-face.hh"
|
#include "hb-ot-face.hh"
|
||||||
|
#include "hb-outline.hh"
|
||||||
|
|
||||||
#include "hb-ot-cmap-table.hh"
|
#include "hb-ot-cmap-table.hh"
|
||||||
#include "hb-ot-glyf-table.hh"
|
#include "hb-ot-glyf-table.hh"
|
||||||
|
@ -180,10 +181,13 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
||||||
unsigned advance_stride,
|
unsigned advance_stride,
|
||||||
void *user_data HB_UNUSED)
|
void *user_data HB_UNUSED)
|
||||||
{
|
{
|
||||||
|
|
||||||
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
|
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
|
||||||
const hb_ot_face_t *ot_face = ot_font->ot_face;
|
const hb_ot_face_t *ot_face = ot_font->ot_face;
|
||||||
const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
|
const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
|
||||||
|
|
||||||
|
hb_position_t *orig_first_advance = first_advance;
|
||||||
|
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
const OT::HVAR &HVAR = *hmtx.var_table;
|
const OT::HVAR &HVAR = *hmtx.var_table;
|
||||||
const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
|
const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
|
||||||
|
@ -257,6 +261,18 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
OT::VariationStore::destroy_cache (varStore_cache);
|
OT::VariationStore::destroy_cache (varStore_cache);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (font->x_strength && !font->embolden_in_place)
|
||||||
|
{
|
||||||
|
/* Emboldening. */
|
||||||
|
hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength;
|
||||||
|
first_advance = orig_first_advance;
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
*first_advance += *first_advance ? x_strength : 0;
|
||||||
|
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HB_NO_VERTICAL
|
#ifndef HB_NO_VERTICAL
|
||||||
|
@ -273,6 +289,8 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
|
||||||
const hb_ot_face_t *ot_face = ot_font->ot_face;
|
const hb_ot_face_t *ot_face = ot_font->ot_face;
|
||||||
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
|
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
|
||||||
|
|
||||||
|
hb_position_t *orig_first_advance = first_advance;
|
||||||
|
|
||||||
if (vmtx.has_data ())
|
if (vmtx.has_data ())
|
||||||
{
|
{
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
|
@ -307,6 +325,18 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
|
||||||
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
|
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (font->y_strength && !font->embolden_in_place)
|
||||||
|
{
|
||||||
|
/* Emboldening. */
|
||||||
|
hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength;
|
||||||
|
first_advance = orig_first_advance;
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
*first_advance += *first_advance ? y_strength : 0;
|
||||||
|
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -436,9 +466,16 @@ hb_ot_get_font_h_extents (hb_font_t *font,
|
||||||
hb_font_extents_t *metrics,
|
hb_font_extents_t *metrics,
|
||||||
void *user_data HB_UNUSED)
|
void *user_data HB_UNUSED)
|
||||||
{
|
{
|
||||||
return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
|
bool ret = _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
|
||||||
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
|
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
|
||||||
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
|
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
|
||||||
|
|
||||||
|
/* Embolden */
|
||||||
|
int y_shift = font->y_strength;
|
||||||
|
if (font->y_scale < 0) y_shift = -y_shift;
|
||||||
|
metrics->ascender += y_shift;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HB_NO_VERTICAL
|
#ifndef HB_NO_VERTICAL
|
||||||
|
@ -462,12 +499,31 @@ hb_ot_draw_glyph (hb_font_t *font,
|
||||||
hb_draw_funcs_t *draw_funcs, void *draw_data,
|
hb_draw_funcs_t *draw_funcs, void *draw_data,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy);
|
bool embolden = font->x_strength || font->y_strength;
|
||||||
if (font->face->table.glyf->get_path (font, glyph, draw_session)) return;
|
hb_outline_t outline;
|
||||||
|
|
||||||
|
{ // Need draw_session to be destructed before emboldening.
|
||||||
|
hb_draw_session_t draw_session (embolden ? hb_outline_recording_pen_get_funcs () : draw_funcs,
|
||||||
|
embolden ? &outline : draw_data, font->slant_xy);
|
||||||
|
if (!font->face->table.glyf->get_path (font, glyph, draw_session))
|
||||||
#ifndef HB_NO_CFF
|
#ifndef HB_NO_CFF
|
||||||
if (font->face->table.cff1->get_path (font, glyph, draw_session)) return;
|
if (!font->face->table.cff1->get_path (font, glyph, draw_session))
|
||||||
if (font->face->table.cff2->get_path (font, glyph, draw_session)) return;
|
if (!font->face->table.cff2->get_path (font, glyph, draw_session))
|
||||||
#endif
|
#endif
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (embolden)
|
||||||
|
{
|
||||||
|
float x_shift = font->embolden_in_place ? 0 : font->x_strength / 2;
|
||||||
|
float y_shift = font->y_strength / 2;
|
||||||
|
if (font->x_scale < 0) x_shift = -x_shift;
|
||||||
|
if (font->y_scale < 0) y_shift = -y_shift;
|
||||||
|
outline.embolden (font->x_strength, font->y_strength,
|
||||||
|
x_shift, y_shift);
|
||||||
|
|
||||||
|
outline.replay (draw_funcs, draw_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,322 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2023 Behdad Esfahbod
|
||||||
|
* Copyright © 1999 David Turner
|
||||||
|
* Copyright © 2005 Werner Lemberg
|
||||||
|
* Copyright © 2013-2015 Alexei Podtelezhnikov
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hb.hh"
|
||||||
|
|
||||||
|
#ifndef HB_NO_OUTLINE
|
||||||
|
|
||||||
|
#include "hb-outline.hh"
|
||||||
|
|
||||||
|
#include "hb-machinery.hh"
|
||||||
|
|
||||||
|
|
||||||
|
void hb_outline_t::replay (hb_draw_funcs_t *pen, void *pen_data) const
|
||||||
|
{
|
||||||
|
hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
|
||||||
|
|
||||||
|
unsigned first = 0;
|
||||||
|
for (unsigned contour : contours)
|
||||||
|
{
|
||||||
|
auto it = points.as_array ().sub_array (first, contour - first);
|
||||||
|
while (it)
|
||||||
|
{
|
||||||
|
hb_outline_point_t p1 = *it++;
|
||||||
|
switch (p1.type)
|
||||||
|
{
|
||||||
|
case hb_outline_point_t::type_t::MOVE_TO:
|
||||||
|
{
|
||||||
|
pen->move_to (pen_data, st,
|
||||||
|
p1.x, p1.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case hb_outline_point_t::type_t::LINE_TO:
|
||||||
|
{
|
||||||
|
pen->line_to (pen_data, st,
|
||||||
|
p1.x, p1.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case hb_outline_point_t::type_t::QUADRATIC_TO:
|
||||||
|
{
|
||||||
|
hb_outline_point_t p2 = *it++;
|
||||||
|
pen->quadratic_to (pen_data, st,
|
||||||
|
p1.x, p1.y,
|
||||||
|
p2.x, p2.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case hb_outline_point_t::type_t::CUBIC_TO:
|
||||||
|
{
|
||||||
|
hb_outline_point_t p2 = *it++;
|
||||||
|
hb_outline_point_t p3 = *it++;
|
||||||
|
pen->cubic_to (pen_data, st,
|
||||||
|
p1.x, p1.y,
|
||||||
|
p2.x, p2.y,
|
||||||
|
p3.x, p3.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pen->close_path (pen_data, st);
|
||||||
|
first = contour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float hb_outline_t::area () const
|
||||||
|
{
|
||||||
|
float a = 0;
|
||||||
|
unsigned first = 0;
|
||||||
|
for (unsigned contour : contours)
|
||||||
|
{
|
||||||
|
for (unsigned i = first; i < contour; i++)
|
||||||
|
{
|
||||||
|
unsigned j = i + 1 < contour ? i + 1 : first;
|
||||||
|
|
||||||
|
auto &pi = points[i];
|
||||||
|
auto &pj = points[j];
|
||||||
|
a += pi.x * pj.y - pi.y * pj.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
first = contour;
|
||||||
|
}
|
||||||
|
return a * .5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hb_outline_t::embolden (float x_strength, float y_strength,
|
||||||
|
float x_shift, float y_shift)
|
||||||
|
{
|
||||||
|
/* This function is a straight port of FreeType's FT_Outline_EmboldenXY.
|
||||||
|
* Permission has been obtained from the FreeType authors of the code
|
||||||
|
* to relicense it under the HarfBuzz license. */
|
||||||
|
|
||||||
|
if (!x_strength && !y_strength) return;
|
||||||
|
if (!points) return;
|
||||||
|
|
||||||
|
x_strength /= 2.f;
|
||||||
|
y_strength /= 2.f;
|
||||||
|
|
||||||
|
bool orientation_negative = area () < 0;
|
||||||
|
|
||||||
|
signed first = 0;
|
||||||
|
for (unsigned c = 0; c < contours.length; c++)
|
||||||
|
{
|
||||||
|
hb_outline_vector_t in, out, anchor, shift;
|
||||||
|
float l_in, l_out, l_anchor = 0, l, q, d;
|
||||||
|
|
||||||
|
l_in = 0;
|
||||||
|
signed last = (int) contours[c] - 1;
|
||||||
|
|
||||||
|
/* pacify compiler */
|
||||||
|
in.x = in.y = anchor.x = anchor.y = 0;
|
||||||
|
|
||||||
|
/* Counter j cycles though the points; counter i advances only */
|
||||||
|
/* when points are moved; anchor k marks the first moved point. */
|
||||||
|
for ( signed i = last, j = first, k = -1;
|
||||||
|
j != i && i != k;
|
||||||
|
j = j < last ? j + 1 : first )
|
||||||
|
{
|
||||||
|
if ( j != k )
|
||||||
|
{
|
||||||
|
out.x = points[j].x - points[i].x;
|
||||||
|
out.y = points[j].y - points[i].y;
|
||||||
|
l_out = out.normalize_len ();
|
||||||
|
|
||||||
|
if ( l_out == 0 )
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out = anchor;
|
||||||
|
l_out = l_anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( l_in != 0 )
|
||||||
|
{
|
||||||
|
if ( k < 0 )
|
||||||
|
{
|
||||||
|
k = i;
|
||||||
|
anchor = in;
|
||||||
|
l_anchor = l_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = in.x * out.x + in.y * out.y;
|
||||||
|
|
||||||
|
/* shift only if turn is less than ~160 degrees */
|
||||||
|
if ( d > -15.f/16.f )
|
||||||
|
{
|
||||||
|
d = d + 1.f;
|
||||||
|
|
||||||
|
/* shift components along lateral bisector in proper orientation */
|
||||||
|
shift.x = in.y + out.y;
|
||||||
|
shift.y = in.x + out.x;
|
||||||
|
|
||||||
|
if ( orientation_negative )
|
||||||
|
shift.x = -shift.x;
|
||||||
|
else
|
||||||
|
shift.y = -shift.y;
|
||||||
|
|
||||||
|
/* restrict shift magnitude to better handle collapsing segments */
|
||||||
|
q = out.x * in.y - out.y * in.x;
|
||||||
|
if ( orientation_negative )
|
||||||
|
q = -q;
|
||||||
|
|
||||||
|
l = hb_min (l_in, l_out);
|
||||||
|
|
||||||
|
/* non-strict inequalities avoid divide-by-zero when q == l == 0 */
|
||||||
|
if (x_strength * q <= l * d)
|
||||||
|
shift.x = shift.x * x_strength / d;
|
||||||
|
else
|
||||||
|
shift.x = shift.x * l / q;
|
||||||
|
|
||||||
|
|
||||||
|
if (y_strength * q <= l * d)
|
||||||
|
shift.y = shift.y * y_strength / d;
|
||||||
|
else
|
||||||
|
shift.y = shift.y * l / q;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
shift.x = shift.y = 0;
|
||||||
|
|
||||||
|
for ( ;
|
||||||
|
i != j;
|
||||||
|
i = i < last ? i + 1 : first )
|
||||||
|
{
|
||||||
|
points[i].x += x_shift + shift.x;
|
||||||
|
points[i].y += y_shift + shift.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i = j;
|
||||||
|
|
||||||
|
in = out;
|
||||||
|
l_in = l_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
first = last + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hb_outline_recording_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
|
||||||
|
void *data,
|
||||||
|
hb_draw_state_t *st,
|
||||||
|
float to_x, float to_y,
|
||||||
|
void *user_data HB_UNUSED)
|
||||||
|
{
|
||||||
|
hb_outline_t *c = (hb_outline_t *) data;
|
||||||
|
|
||||||
|
c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::MOVE_TO});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hb_outline_recording_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
|
||||||
|
void *data,
|
||||||
|
hb_draw_state_t *st,
|
||||||
|
float to_x, float to_y,
|
||||||
|
void *user_data HB_UNUSED)
|
||||||
|
{
|
||||||
|
hb_outline_t *c = (hb_outline_t *) data;
|
||||||
|
|
||||||
|
c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::LINE_TO});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hb_outline_recording_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
|
||||||
|
void *data,
|
||||||
|
hb_draw_state_t *st,
|
||||||
|
float control_x, float control_y,
|
||||||
|
float to_x, float to_y,
|
||||||
|
void *user_data HB_UNUSED)
|
||||||
|
{
|
||||||
|
hb_outline_t *c = (hb_outline_t *) data;
|
||||||
|
|
||||||
|
c->points.push (hb_outline_point_t {control_x, control_y, hb_outline_point_t::type_t::QUADRATIC_TO});
|
||||||
|
c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::QUADRATIC_TO});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hb_outline_recording_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
|
||||||
|
void *data,
|
||||||
|
hb_draw_state_t *st,
|
||||||
|
float control1_x, float control1_y,
|
||||||
|
float control2_x, float control2_y,
|
||||||
|
float to_x, float to_y,
|
||||||
|
void *user_data HB_UNUSED)
|
||||||
|
{
|
||||||
|
hb_outline_t *c = (hb_outline_t *) data;
|
||||||
|
|
||||||
|
c->points.push (hb_outline_point_t {control1_x, control1_y, hb_outline_point_t::type_t::CUBIC_TO});
|
||||||
|
c->points.push (hb_outline_point_t {control2_x, control2_y, hb_outline_point_t::type_t::CUBIC_TO});
|
||||||
|
c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::CUBIC_TO});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hb_outline_recording_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
|
||||||
|
void *data,
|
||||||
|
hb_draw_state_t *st,
|
||||||
|
void *user_data HB_UNUSED)
|
||||||
|
{
|
||||||
|
hb_outline_t *c = (hb_outline_t *) data;
|
||||||
|
|
||||||
|
c->contours.push (c->points.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void free_static_outline_recording_pen_funcs ();
|
||||||
|
|
||||||
|
static struct hb_outline_recording_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_outline_recording_pen_funcs_lazy_loader_t>
|
||||||
|
{
|
||||||
|
static hb_draw_funcs_t *create ()
|
||||||
|
{
|
||||||
|
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
|
||||||
|
|
||||||
|
hb_draw_funcs_set_move_to_func (funcs, hb_outline_recording_pen_move_to, nullptr, nullptr);
|
||||||
|
hb_draw_funcs_set_line_to_func (funcs, hb_outline_recording_pen_line_to, nullptr, nullptr);
|
||||||
|
hb_draw_funcs_set_quadratic_to_func (funcs, hb_outline_recording_pen_quadratic_to, nullptr, nullptr);
|
||||||
|
hb_draw_funcs_set_cubic_to_func (funcs, hb_outline_recording_pen_cubic_to, nullptr, nullptr);
|
||||||
|
hb_draw_funcs_set_close_path_func (funcs, hb_outline_recording_pen_close_path, nullptr, nullptr);
|
||||||
|
|
||||||
|
hb_draw_funcs_make_immutable (funcs);
|
||||||
|
|
||||||
|
hb_atexit (free_static_outline_recording_pen_funcs);
|
||||||
|
|
||||||
|
return funcs;
|
||||||
|
}
|
||||||
|
} static_outline_recording_pen_funcs;
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void free_static_outline_recording_pen_funcs ()
|
||||||
|
{
|
||||||
|
static_outline_recording_pen_funcs.free_instance ();
|
||||||
|
}
|
||||||
|
|
||||||
|
hb_draw_funcs_t *
|
||||||
|
hb_outline_recording_pen_get_funcs ()
|
||||||
|
{
|
||||||
|
return static_outline_recording_pen_funcs.get_unconst ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2023 Behdad Esfahbod
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_OUTLINE_HH
|
||||||
|
#define HB_OUTLINE_HH
|
||||||
|
|
||||||
|
#include "hb.hh"
|
||||||
|
|
||||||
|
#include "hb-draw.hh"
|
||||||
|
|
||||||
|
|
||||||
|
struct hb_outline_point_t
|
||||||
|
{
|
||||||
|
enum class type_t
|
||||||
|
{
|
||||||
|
MOVE_TO,
|
||||||
|
LINE_TO,
|
||||||
|
QUADRATIC_TO,
|
||||||
|
CUBIC_TO,
|
||||||
|
};
|
||||||
|
|
||||||
|
hb_outline_point_t (float x, float y, type_t type) :
|
||||||
|
x (x), y (y), type (type) {}
|
||||||
|
|
||||||
|
float x, y;
|
||||||
|
type_t type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hb_outline_vector_t
|
||||||
|
{
|
||||||
|
float normalize_len ()
|
||||||
|
{
|
||||||
|
float len = hypotf (x, y);
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
x /= len;
|
||||||
|
y /= len;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
float x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hb_outline_t
|
||||||
|
{
|
||||||
|
void reset () { points.shrink (0, false); contours.resize (0); }
|
||||||
|
|
||||||
|
HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const;
|
||||||
|
HB_INTERNAL float area () const;
|
||||||
|
HB_INTERNAL void embolden (float x_strength, float y_strength,
|
||||||
|
float x_shift, float y_shift);
|
||||||
|
|
||||||
|
hb_vector_t<hb_outline_point_t> points;
|
||||||
|
hb_vector_t<unsigned> contours;
|
||||||
|
};
|
||||||
|
|
||||||
|
HB_INTERNAL hb_draw_funcs_t *
|
||||||
|
hb_outline_recording_pen_get_funcs ();
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HB_OUTLINE_HH */
|
|
@ -459,7 +459,7 @@ struct hb_vector_t
|
||||||
length--;
|
length--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void shrink (int size_)
|
void shrink (int size_, bool shrink_memory = true)
|
||||||
{
|
{
|
||||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||||
if (size >= length)
|
if (size >= length)
|
||||||
|
@ -467,6 +467,7 @@ struct hb_vector_t
|
||||||
|
|
||||||
shrink_vector (size);
|
shrink_vector (size);
|
||||||
|
|
||||||
|
if (shrink_memory)
|
||||||
alloc (size, true); /* To force shrinking memory if needed. */
|
alloc (size, true); /* To force shrinking memory if needed. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,8 @@ hb_base_sources = files(
|
||||||
'hb-ot-layout-gdef-table.hh',
|
'hb-ot-layout-gdef-table.hh',
|
||||||
'hb-ot-layout-gpos-table.hh',
|
'hb-ot-layout-gpos-table.hh',
|
||||||
'hb-ot-layout-gsub-table.hh',
|
'hb-ot-layout-gsub-table.hh',
|
||||||
|
'hb-outline.hh',
|
||||||
|
'hb-outline.cc',
|
||||||
'OT/Color/CBDT/CBDT.hh',
|
'OT/Color/CBDT/CBDT.hh',
|
||||||
'OT/Color/COLR/COLR.hh',
|
'OT/Color/COLR/COLR.hh',
|
||||||
'OT/Color/CPAL/CPAL.hh',
|
'OT/Color/CPAL/CPAL.hh',
|
||||||
|
|
|
@ -63,6 +63,9 @@ struct font_options_t : face_options_t
|
||||||
int x_ppem = 0;
|
int x_ppem = 0;
|
||||||
int y_ppem = 0;
|
int y_ppem = 0;
|
||||||
double ptem = 0.;
|
double ptem = 0.;
|
||||||
|
double x_embolden = 0.;
|
||||||
|
double y_embolden = 0.;
|
||||||
|
hb_bool_t embolden_in_place = false;
|
||||||
double slant = 0.;
|
double slant = 0.;
|
||||||
unsigned int subpixel_bits = SUBPIXEL_BITS;
|
unsigned int subpixel_bits = SUBPIXEL_BITS;
|
||||||
mutable double font_size_x = DEFAULT_FONT_SIZE;
|
mutable double font_size_x = DEFAULT_FONT_SIZE;
|
||||||
|
@ -101,6 +104,9 @@ font_options_t::post_parse (GError **error)
|
||||||
hb_font_set_ppem (font, x_ppem, y_ppem);
|
hb_font_set_ppem (font, x_ppem, y_ppem);
|
||||||
hb_font_set_ptem (font, ptem);
|
hb_font_set_ptem (font, ptem);
|
||||||
|
|
||||||
|
hb_font_set_synthetic_bold (font,
|
||||||
|
(float) x_embolden, (float) y_embolden,
|
||||||
|
embolden_in_place);
|
||||||
hb_font_set_synthetic_slant (font, slant);
|
hb_font_set_synthetic_slant (font, slant);
|
||||||
|
|
||||||
int scale_x = (int) scalbnf (font_size_x, subpixel_bits);
|
int scale_x = (int) scalbnf (font_size_x, subpixel_bits);
|
||||||
|
@ -245,6 +251,46 @@ parse_font_ppem (const char *name G_GNUC_UNUSED,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parse_font_embolden (const char *name G_GNUC_UNUSED,
|
||||||
|
const char *arg,
|
||||||
|
gpointer data,
|
||||||
|
GError **error G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
font_options_t *font_opts = (font_options_t *) data;
|
||||||
|
switch (sscanf (arg, "%lf%*[ ,]%lf", &font_opts->x_embolden, &font_opts->y_embolden)) {
|
||||||
|
case 1: font_opts->y_embolden = font_opts->x_embolden; HB_FALLTHROUGH;
|
||||||
|
case 2: return true;
|
||||||
|
default:
|
||||||
|
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
|
||||||
|
"%s argument should be one or two space-separated numbers",
|
||||||
|
name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parse_font_bold (const char *name G_GNUC_UNUSED,
|
||||||
|
const char *arg,
|
||||||
|
gpointer data,
|
||||||
|
GError **error G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
font_options_t *font_opts = (font_options_t *) data;
|
||||||
|
font_opts->embolden_in_place = false;
|
||||||
|
return parse_font_embolden ( name, arg, data, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parse_font_grade (const char *name G_GNUC_UNUSED,
|
||||||
|
const char *arg,
|
||||||
|
gpointer data,
|
||||||
|
GError **error G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
font_options_t *font_opts = (font_options_t *) data;
|
||||||
|
font_opts->embolden_in_place = true;
|
||||||
|
return parse_font_embolden ( name, arg, data, error);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
font_options_t::add_options (option_parser_t *parser)
|
font_options_t::add_options (option_parser_t *parser)
|
||||||
{
|
{
|
||||||
|
@ -286,7 +332,11 @@ font_options_t::add_options (option_parser_t *parser)
|
||||||
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_ppem, "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"},
|
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_ppem, "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"},
|
||||||
{"font-ptem", 0, font_size_flags,
|
{"font-ptem", 0, font_size_flags,
|
||||||
G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"},
|
G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"},
|
||||||
{"font-slant", 0, 0,
|
{"font-bold", 0, font_size_flags,
|
||||||
|
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_bold, "Set synthetic bold (default: 0)", "1/2 numbers; eg. 0.05"},
|
||||||
|
{"font-grade", 0, font_size_flags,
|
||||||
|
G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_grade, "Set synthetic grade (default: 0)", "1/2 numbers; eg. 0.05"},
|
||||||
|
{"font-slant", 0, font_size_flags,
|
||||||
G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"},
|
G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"},
|
||||||
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},
|
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},
|
||||||
{"sub-font", 0, G_OPTION_FLAG_HIDDEN,
|
{"sub-font", 0, G_OPTION_FLAG_HIDDEN,
|
||||||
|
|
Loading…
Reference in New Issue