[hmtx] Implement [boring-expansion] >64k expansion
This implements https://github.com/be-fonts/boring-expansion-spec/issues/7
This commit is contained in:
parent
379e526aa4
commit
8b7ccc41c4
|
@ -47,6 +47,7 @@
|
||||||
|
|
||||||
/* OpenType fundamentals. */
|
/* OpenType fundamentals. */
|
||||||
HB_OT_TABLE (OT, head)
|
HB_OT_TABLE (OT, head)
|
||||||
|
HB_OT_TABLE (OT, maxp)
|
||||||
#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
|
#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
|
||||||
HB_OT_ACCELERATOR (OT, cmap)
|
HB_OT_ACCELERATOR (OT, cmap)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define HB_OT_HMTX_TABLE_HH
|
#define HB_OT_HMTX_TABLE_HH
|
||||||
|
|
||||||
#include "hb-open-type.hh"
|
#include "hb-open-type.hh"
|
||||||
|
#include "hb-ot-maxp-table.hh"
|
||||||
#include "hb-ot-hhea-table.hh"
|
#include "hb-ot-hhea-table.hh"
|
||||||
#include "hb-ot-var-hvar-table.hh"
|
#include "hb-ot-var-hvar-table.hh"
|
||||||
#include "hb-ot-metrics.hh"
|
#include "hb-ot-metrics.hh"
|
||||||
|
@ -172,8 +173,17 @@ struct hmtxvmtx
|
||||||
accelerator_t (hb_face_t *face,
|
accelerator_t (hb_face_t *face,
|
||||||
unsigned int default_advance_ = 0)
|
unsigned int default_advance_ = 0)
|
||||||
{
|
{
|
||||||
|
table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
|
||||||
|
var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
|
||||||
|
|
||||||
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
|
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
|
||||||
|
|
||||||
|
/* Populate count variables and sort them out as we go */
|
||||||
|
|
||||||
|
unsigned int len = table.get_length ();
|
||||||
|
if (len & 1)
|
||||||
|
len--;
|
||||||
|
|
||||||
num_long_metrics = T::is_horizontal ?
|
num_long_metrics = T::is_horizontal ?
|
||||||
face->table.hhea->numberOfLongMetrics :
|
face->table.hhea->numberOfLongMetrics :
|
||||||
#ifndef HB_NO_VERTICAL
|
#ifndef HB_NO_VERTICAL
|
||||||
|
@ -182,25 +192,27 @@ struct hmtxvmtx
|
||||||
0
|
0
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
|
|
||||||
|
|
||||||
/* Cap num_bearings and num_long_metrics based on table length. */
|
|
||||||
unsigned int len = table.get_length ();
|
|
||||||
if (unlikely (num_long_metrics * 4 > len))
|
if (unlikely (num_long_metrics * 4 > len))
|
||||||
num_long_metrics = len / 4;
|
num_long_metrics = len / 4;
|
||||||
num_bearings = num_long_metrics + (len - 4 * num_long_metrics) / 2;
|
len -= num_long_metrics * 4;
|
||||||
|
|
||||||
|
num_bearings = face->table.maxp->get_num_glyphs ();
|
||||||
|
|
||||||
|
if (unlikely (num_bearings < num_long_metrics))
|
||||||
|
num_bearings = num_long_metrics;
|
||||||
|
if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
|
||||||
|
num_bearings = num_long_metrics + len / 2;
|
||||||
|
len -= (num_bearings - num_long_metrics) * 2;
|
||||||
|
|
||||||
/* We MUST set num_bearings to zero if num_long_metrics is zero.
|
/* We MUST set num_bearings to zero if num_long_metrics is zero.
|
||||||
* Our get_advance() depends on that. */
|
* Our get_advance() depends on that. */
|
||||||
if (unlikely (!num_long_metrics))
|
if (unlikely (!num_long_metrics))
|
||||||
{
|
|
||||||
num_bearings = num_long_metrics = 0;
|
num_bearings = num_long_metrics = 0;
|
||||||
table.destroy ();
|
|
||||||
table = hb_blob_get_empty ();
|
|
||||||
}
|
|
||||||
|
|
||||||
var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
|
num_advances = num_bearings + len / 2;
|
||||||
|
num_glyphs = face->get_num_glyphs ();
|
||||||
|
if (num_glyphs < num_advances)
|
||||||
|
num_glyphs = num_advances;
|
||||||
}
|
}
|
||||||
~accelerator_t ()
|
~accelerator_t ()
|
||||||
{
|
{
|
||||||
|
@ -239,18 +251,31 @@ struct hmtxvmtx
|
||||||
|
|
||||||
unsigned int get_advance (hb_codepoint_t glyph) const
|
unsigned int get_advance (hb_codepoint_t glyph) const
|
||||||
{
|
{
|
||||||
if (unlikely (glyph >= num_bearings))
|
/* OpenType case. */
|
||||||
{
|
if (glyph < num_bearings)
|
||||||
/* If num_bearings is zero, it means we don't have the metrics table
|
return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
|
||||||
* for this direction: return default advance. Otherwise, it means that the
|
|
||||||
* glyph index is out of bound: return zero. */
|
|
||||||
if (num_bearings)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return default_advance;
|
|
||||||
}
|
|
||||||
|
|
||||||
return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
|
/* If num_advances is zero, it means we don't have the metrics table
|
||||||
|
* for this direction: return default advance. Otherwise, there's a
|
||||||
|
* well-defined answer. */
|
||||||
|
if (unlikely (!num_advances))
|
||||||
|
return default_advance;
|
||||||
|
|
||||||
|
if (unlikely (glyph >= num_glyphs))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* num_bearings <= glyph < num_glyphs;
|
||||||
|
* num_bearings <= num_advances */
|
||||||
|
|
||||||
|
/* TODO Optimize */
|
||||||
|
|
||||||
|
if (num_bearings == num_advances)
|
||||||
|
return get_advance (num_bearings - 1);
|
||||||
|
|
||||||
|
const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
|
||||||
|
const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
|
||||||
|
|
||||||
|
return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int get_advance (hb_codepoint_t glyph,
|
unsigned int get_advance (hb_codepoint_t glyph,
|
||||||
|
@ -272,9 +297,12 @@ struct hmtxvmtx
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// 0 <= num_long_metrics <= num_bearings
|
// 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
|
||||||
unsigned int num_long_metrics;
|
unsigned num_long_metrics;
|
||||||
unsigned int num_bearings;
|
unsigned num_bearings;
|
||||||
|
unsigned num_advances;
|
||||||
|
unsigned num_glyphs;
|
||||||
|
|
||||||
unsigned int default_advance;
|
unsigned int default_advance;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -306,6 +334,8 @@ struct hmtxvmtx
|
||||||
* the end. This allows a monospaced
|
* the end. This allows a monospaced
|
||||||
* font to vary the side bearing
|
* font to vary the side bearing
|
||||||
* values for each glyph. */
|
* values for each glyph. */
|
||||||
|
/*UnsizedArrayOf<UFWORD>advancesX;*/
|
||||||
|
/* TODO Document. */
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_ARRAY (0, longMetricZ);
|
DEFINE_SIZE_ARRAY (0, longMetricZ);
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,9 +77,9 @@ test_maxp_and_hmtx (void)
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 2), ==, 3);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 2), ==, 3);
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 3), ==, 3);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 3), ==, 3);
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 4), ==, 3);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 4), ==, 3);
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 5), ==, 3);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 5), ==, 8);
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 6), ==, 3);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 6), ==, 9);
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 7), ==, 0);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 7), ==, 9);
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 8), ==, 0);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 8), ==, 0);
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 9), ==, 0);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font, 9), ==, 0);
|
||||||
g_assert_cmpuint (hb_font_get_glyph_h_advance (font,10), ==, 0);
|
g_assert_cmpuint (hb_font_get_glyph_h_advance (font,10), ==, 0);
|
||||||
|
|
Loading…
Reference in New Issue