Merge branch 'font-extents'

Fixes https://github.com/behdad/harfbuzz/pull/165
This commit is contained in:
Behdad Esfahbod 2015-12-10 16:56:07 +01:00
commit e1d4d0f1db
9 changed files with 399 additions and 21 deletions

View File

@ -48,6 +48,7 @@ HBSOURCES = \
hb-ot-hmtx-table.hh \
hb-ot-maxp-table.hh \
hb-ot-name-table.hh \
hb-ot-os2-table.hh \
hb-ot-tag.cc \
hb-private.hh \
hb-set-private.hh \

View File

@ -42,6 +42,8 @@
*/
#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
HB_FONT_FUNC_IMPLEMENT (glyph) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
@ -160,6 +162,21 @@ struct hb_font_t {
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
return klass->get.f.font_h_extents (this, user_data,
extents,
klass->user_data.font_h_extents);
}
inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
return klass->get.f.font_v_extents (this, user_data,
extents,
klass->user_data.font_v_extents);
}
inline bool has_glyph (hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
@ -265,6 +282,26 @@ struct hb_font_t {
/* A bit higher-level, and with fallback */
inline void get_extents_for_direction (hb_direction_t direction,
hb_font_extents_t *extents)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
if (!get_font_h_extents (extents))
{
extents->ascender = y_scale * .8;
extents->descender = y_scale - extents->ascender;
extents->line_gap = 0;
}
} else {
if (!get_font_v_extents (extents))
{
extents->ascender = x_scale / 2;
extents->descender = x_scale - extents->ascender;
extents->line_gap = 0;
}
}
}
inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
@ -284,7 +321,7 @@ struct hb_font_t {
{
*x = get_glyph_h_advance (glyph) / 2;
/* TODO use font_metrics.ascent */
/* TODO use font_extents.ascender */
*y = y_scale;
}

View File

@ -44,6 +44,54 @@
* hb_font_funcs_t
*/
static hb_bool_t
hb_font_get_font_h_extents_nil (hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
memset (metrics, 0, sizeof (*metrics));
return false;
}
static hb_bool_t
hb_font_get_font_h_extents_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
hb_bool_t ret = font->parent->get_font_h_extents (metrics);
if (ret) {
metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
metrics->descender = font->parent_scale_y_distance (metrics->descender);
metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
}
return ret;
}
static hb_bool_t
hb_font_get_font_v_extents_nil (hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
memset (metrics, 0, sizeof (*metrics));
return false;
}
static hb_bool_t
hb_font_get_font_v_extents_parent (hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
hb_bool_t ret = font->parent->get_font_v_extents (metrics);
if (ret) {
metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
metrics->descender = font->parent_scale_x_distance (metrics->descender);
metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
}
return ret;
}
static hb_bool_t
hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
@ -280,7 +328,6 @@ hb_font_get_glyph_from_name_parent (hb_font_t *font,
return font->parent->get_glyph_from_name (name, len, glyph);
}
static const hb_font_funcs_t _hb_font_funcs_nil = {
HB_OBJECT_HEADER_STATIC,
@ -521,6 +568,42 @@ hb_font_t::has_func (unsigned int i)
/* Public getters */
/**
* hb_font_get_h_extents:
* @font: a font.
* @extents: (out):
*
*
*
* Return value:
*
* Since: 1.1.2
**/
hb_bool_t
hb_font_get_h_extents (hb_font_t *font,
hb_font_extents_t *extents)
{
return font->get_font_h_extents (extents);
}
/**
* hb_font_get_v_extents:
* @font: a font.
* @extents: (out):
*
*
*
* Return value:
*
* Since: 1.1.2
**/
hb_bool_t
hb_font_get_v_extents (hb_font_t *font,
hb_font_extents_t *extents)
{
return font->get_font_v_extents (extents);
}
/**
* hb_font_get_glyph:
* @font: a font.
@ -745,6 +828,23 @@ hb_font_get_glyph_from_name (hb_font_t *font,
/* A bit higher-level, and with fallback */
/**
* hb_font_get_extents_for_direction:
* @font: a font.
* @direction:
* @extents:
*
*
*
* Since: 1.1.2
**/
void
hb_font_get_extents_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_font_extents_t *extents)
{
return font->get_extents_for_direction (direction, extents);
}
/**
* hb_font_get_glyph_advance_for_direction:
* @font: a font.

View File

@ -78,7 +78,15 @@ HB_EXTERN hb_bool_t
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
/* glyph extents */
/* font and glyph extents */
/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
typedef struct hb_font_extents_t
{
hb_position_t ascender; /* typographic ascender. */
hb_position_t descender; /* typographic descender. */
hb_position_t line_gap; /* suggested line spacing gap. */
} hb_font_extents_t;
/* Note that height is negative in coordinate systems that grow up. */
typedef struct hb_glyph_extents_t
@ -89,9 +97,15 @@ typedef struct hb_glyph_extents_t
hb_position_t height; /* distance from top to bottom side. */
} hb_glyph_extents_t;
/* func types */
typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
hb_font_extents_t *metrics,
void *user_data);
typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
@ -140,6 +154,38 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
/* func setters */
/**
* hb_font_funcs_set_font_h_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.1.2
**/
HB_EXTERN void
hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
hb_font_get_font_h_extents_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_font_v_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.1.2
**/
HB_EXTERN void
hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
hb_font_get_font_v_extents_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_func:
* @ffuncs: font functions.
@ -316,9 +362,15 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_from_name_func_t func,
void *user_data, hb_destroy_func_t destroy);
/* func dispatch */
HB_EXTERN hb_bool_t
hb_font_get_h_extents (hb_font_t *font,
hb_font_extents_t *extents);
HB_EXTERN hb_bool_t
hb_font_get_v_extents (hb_font_t *font,
hb_font_extents_t *extents);
HB_EXTERN hb_bool_t
hb_font_get_glyph (hb_font_t *font,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
@ -369,6 +421,10 @@ hb_font_get_glyph_from_name (hb_font_t *font,
/* high-level funcs, with fallback */
HB_EXTERN void
hb_font_get_extents_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_font_extents_t *extents);
HB_EXTERN void
hb_font_get_glyph_advance_for_direction (hb_font_t *font,
hb_codepoint_t glyph,

View File

@ -366,6 +366,25 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
return *glyph != 0;
}
static hb_bool_t
hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Face ft_face = ft_font->ft_face;
metrics->ascender = ft_face->size->metrics.ascender;
metrics->descender = ft_face->size->metrics.descender;
metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
if (font->y_scale < 0)
{
metrics->ascender = -metrics->ascender;
metrics->descender = -metrics->descender;
metrics->line_gap = -metrics->line_gap;
}
return true;
}
static hb_font_funcs_t *static_ft_funcs = NULL;
@ -387,6 +406,8 @@ retry:
{
funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
hb_font_funcs_set_glyph_func (funcs, hb_ft_get_glyph, NULL, NULL);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);

View File

@ -35,6 +35,7 @@
#include "hb-ot-head-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-os2-table.hh"
struct hb_ot_face_metrics_accelerator_t
@ -42,17 +43,45 @@ struct hb_ot_face_metrics_accelerator_t
unsigned int num_metrics;
unsigned int num_advances;
unsigned int default_advance;
unsigned short ascender;
unsigned short descender;
unsigned short line_gap;
const OT::_mtx *table;
hb_blob_t *blob;
inline void init (hb_face_t *face,
hb_tag_t _hea_tag, hb_tag_t _mtx_tag)
hb_tag_t _hea_tag,
hb_tag_t _mtx_tag,
hb_tag_t os2_tag)
{
this->default_advance = face->get_upem ();
bool got_font_extents = false;
if (os2_tag)
{
hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
#define USE_TYPO_METRICS (1u<<7)
if (0 != (os2->fsSelection & USE_TYPO_METRICS))
{
this->ascender = os2->sTypoAscender;
this->descender = os2->sTypoDescender;
this->line_gap = os2->sTypoLineGap;
got_font_extents = (this->ascender | this->descender) != 0;
}
hb_blob_destroy (os2_blob);
}
hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
this->num_advances = _hea->numberOfLongMetrics;
if (!got_font_extents)
{
this->ascender = _hea->ascender;
this->descender = _hea->descender;
this->line_gap = _hea->lineGap;
}
hb_blob_destroy (_hea_blob);
this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
@ -252,8 +281,8 @@ _hb_ot_font_create (hb_face_t *face)
return NULL;
ot_font->cmap.init (face);
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx);
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx); /* TODO Can we do this lazily? */
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE); /* TODO Can we do this lazily? */
ot_font->glyf.init (face);
return ot_font;
@ -320,6 +349,31 @@ hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
return ret;
}
static hb_bool_t
hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
return true;
}
static hb_bool_t
hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
return true;
}
static hb_font_funcs_t *static_ot_funcs = NULL;
@ -341,6 +395,8 @@ retry:
{
funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
hb_font_funcs_set_glyph_func (funcs, hb_ot_get_glyph, NULL, NULL);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);

105
src/hb-ot-os2-table.hh Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright © 2011,2012 Google, Inc.
*
* 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.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_OS2_TABLE_HH
#define HB_OT_OS2_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* OS/2 and Windows Metrics
* http://www.microsoft.com/typography/otspec/os2.htm
*/
#define HB_OT_TAG_os2 HB_TAG('O','S','/','2')
struct os2
{
static const hb_tag_t tableTag = HB_OT_TAG_os2;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
USHORT version;
/* Version 0 */
SHORT xAvgCharWidth;
USHORT usWeightClass;
USHORT usWidthClass;
USHORT fsType;
SHORT ySubscriptXSize;
SHORT ySubscriptYSize;
SHORT ySubscriptXOffset;
SHORT ySubscriptYOffset;
SHORT ySuperscriptXSize;
SHORT ySuperscriptYSize;
SHORT ySuperscriptXOffset;
SHORT ySuperscriptYOffset;
SHORT yStrikeoutSize;
SHORT yStrikeoutPosition;
SHORT sFamilyClass;
BYTE panose[10];
ULONG ulUnicodeRange[4];
Tag achVendID;
USHORT fsSelection;
USHORT usFirstCharIndex;
USHORT usLastCharIndex;
SHORT sTypoAscender;
SHORT sTypoDescender;
SHORT sTypoLineGap;
USHORT usWinAscent;
USHORT usWinDescent;
/* Version 1 */
//ULONG ulCodePageRange1;
//ULONG ulCodePageRange2;
/* Version 2 */
//SHORT sxHeight;
//SHORT sCapHeight;
//USHORT usDefaultChar;
//USHORT usBreakChar;
//USHORT usMaxContext;
/* Version 5 */
//USHORT usLowerOpticalPointSize;
//USHORT usUpperOpticalPointSize;
public:
DEFINE_SIZE_STATIC (78);
};
} /* namespace OT */
#endif /* HB_OT_OS2_TABLE_HH */

View File

@ -75,7 +75,9 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
hb_font_t *font = hb_font_reference (font_opts->get_font ());
cairo_font_face_t *cairo_face;
FT_Face ft_face = hb_ft_font_get_face (font);
/* We cannot use the FT_Face from hb_font_t, as doing so will confuse hb_font_t because
* cairo will reset the face size. As such, create new face... */
FT_Face ft_face = NULL;//hb_ft_font_get_face (font);
if (!ft_face)
{
if (!ft_library)

View File

@ -39,16 +39,14 @@ view_cairo_t::render (const font_options_t *font_opts)
int x_sign = font_opts->font_size_x < 0 ? -1 : +1;
int y_sign = font_opts->font_size_y < 0 ? -1 : +1;
cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts);
cairo_font_extents_t font_extents;
cairo_scaled_font_extents (scaled_font, &font_extents);
/* Looks like cairo doesn't negate the sign of font extents even if
* y_scale is negative. This is probably a bug, but that's the way
* it is, and we code for it. Assert, just in case this accidentally
* changes in the future (or is different on non-FreeType cairo font
* backends. */
assert (font_extents.height >= 0);
double leading = font_extents.height + view_options.line_space;
hb_font_t *font = font_opts->get_font();
hb_font_extents_t extents;
hb_font_get_extents_for_direction (font, direction, &extents);
double ascent = y_sign * scalbn ((double) extents.ascender, scale_bits);
double descent = y_sign * -scalbn ((double) extents.descender, scale_bits);
double font_height = y_sign * scalbn ((double) extents.ascender - extents.descender + extents.line_gap, scale_bits);
double leading = font_height + view_options.line_space;
/* Calculate surface size. */
double w, h;
@ -64,6 +62,8 @@ view_cairo_t::render (const font_options_t *font_opts)
w = MAX (w, x_sign * x_advance);
}
cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts);
/* See if font needs color. */
cairo_content_t content = CAIRO_CONTENT_ALPHA;
if (helper_cairo_scaled_font_has_color (scaled_font))
@ -80,13 +80,13 @@ view_cairo_t::render (const font_options_t *font_opts)
if (vertical)
cairo_translate (cr,
w /* We stack lines right to left */
-font_extents.height * .5 /* "ascent" for vertical */,
-font_height * .5 /* "ascent" for vertical */,
y_sign < 0 ? h : 0);
else
{
cairo_translate (cr,
x_sign < 0 ? w : 0,
y_sign < 0 ? font_extents.descent : font_extents.ascent);
y_sign < 0 ? descent : ascent);
}
/* Draw. */