mirror of
https://github.com/harfbuzz/harfbuzz.git
synced 2025-04-06 05:55:06 +00:00
Merge pull request #5055 from harfbuzz/trak-interpolate
[trak] Interpolate between tracks
This commit is contained in:
commit
b9675d6d40
2 changed files with 87 additions and 59 deletions
|
@ -48,17 +48,69 @@ struct TrackTableEntry
|
|||
|
||||
float get_track_value () const { return track.to_float (); }
|
||||
|
||||
int get_value (const void *base, unsigned int index,
|
||||
unsigned int table_size) const
|
||||
{ return (base+valuesZ).as_array (table_size)[index]; }
|
||||
float interpolate_at (unsigned int idx,
|
||||
float ptem,
|
||||
const void *base,
|
||||
hb_array_t<const F16DOT16> size_table) const
|
||||
{
|
||||
const FWORD *values = (base+valuesZ).arrayZ;
|
||||
|
||||
float s0 = size_table[idx].to_float ();
|
||||
float s1 = size_table[idx + 1].to_float ();
|
||||
int v0 = values[idx];
|
||||
int v1 = values[idx + 1];
|
||||
|
||||
// Deal with font bugs.
|
||||
if (unlikely (s1 < s0))
|
||||
{ hb_swap (s0, s1); hb_swap (v0, v1); }
|
||||
if (unlikely (ptem < s0)) return v0;
|
||||
if (unlikely (ptem > s1)) return v1;
|
||||
if (unlikely (s0 == s1)) return (v0 + v1) * 0.5f;
|
||||
|
||||
float t = (ptem - s0) / (s1 - s0);
|
||||
return v0 + t * (v1 - v0);
|
||||
}
|
||||
|
||||
float get_value (float ptem,
|
||||
const void *base,
|
||||
hb_array_t<const F16DOT16> size_table) const
|
||||
{
|
||||
const FWORD *values = (base+valuesZ).arrayZ;
|
||||
|
||||
unsigned int n_sizes = size_table.length;
|
||||
|
||||
/*
|
||||
* Choose size.
|
||||
*/
|
||||
if (!n_sizes) return 0.f;
|
||||
if (n_sizes == 1) return values[0];
|
||||
|
||||
// At least two entries.
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < n_sizes; i++)
|
||||
if (size_table[i].to_float () >= ptem)
|
||||
break;
|
||||
|
||||
// Boundary conditions.
|
||||
if (i == 0) return values[0];
|
||||
if (i == n_sizes) return values[n_sizes - 1];
|
||||
|
||||
// Exact match.
|
||||
if (size_table[i].to_float () == ptem) return values[i];
|
||||
|
||||
// Interpolate.
|
||||
return interpolate_at (i - 1, ptem, base, size_table);
|
||||
}
|
||||
|
||||
public:
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base,
|
||||
unsigned int table_size) const
|
||||
bool sanitize (hb_sanitize_context_t *c,
|
||||
const void *base,
|
||||
unsigned int n_sizes) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
(valuesZ.sanitize (c, base, table_size))));
|
||||
(valuesZ.sanitize (c, base, n_sizes))));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -76,61 +128,38 @@ struct TrackTableEntry
|
|||
|
||||
struct TrackData
|
||||
{
|
||||
float interpolate_at (unsigned int idx,
|
||||
float target_size,
|
||||
const TrackTableEntry &trackTableEntry,
|
||||
const void *base) const
|
||||
float get_tracking (const void *base, float ptem, float track = 0.f) const
|
||||
{
|
||||
unsigned int sizes = nSizes;
|
||||
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
unsigned count = nTracks;
|
||||
hb_array_t<const F16DOT16> size_table = (base+sizeTable).as_array (nSizes);
|
||||
|
||||
float s0 = size_table[idx].to_float ();
|
||||
float s1 = size_table[idx + 1].to_float ();
|
||||
float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
|
||||
return t * trackTableEntry.get_value (base, idx + 1, sizes) +
|
||||
(1.f - t) * trackTableEntry.get_value (base, idx, sizes);
|
||||
}
|
||||
if (!count) return 0.f;
|
||||
if (count == 1) return trackTable[0].get_value (ptem, base, size_table);
|
||||
|
||||
int get_tracking (const void *base, float ptem) const
|
||||
{
|
||||
/*
|
||||
* Choose track.
|
||||
*/
|
||||
const TrackTableEntry *trackTableEntry = nullptr;
|
||||
unsigned int count = nTracks;
|
||||
float last_trak = 1e5;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
/* Note: Seems like the track entries are sorted by values. But the
|
||||
* spec doesn't explicitly say that. It just mentions it in the example. */
|
||||
// At least two entries.
|
||||
|
||||
/* Not sure what CoreText does, but it looks to apply a trak=1.0 by default
|
||||
* if there is no 0.0 trak. So, just pick the one closest to 0.0. */
|
||||
unsigned i = 0;
|
||||
unsigned j = count - 1;
|
||||
|
||||
float trak = trackTable[i].get_track_value ();
|
||||
if (fabsf (trak) < fabsf (last_trak))
|
||||
{
|
||||
trackTableEntry = &trackTable[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!trackTableEntry) return 0;
|
||||
// Find the two entries that track is between.
|
||||
while (i + 1 < count && trackTable[i + 1].get_track_value () < track)
|
||||
i++;
|
||||
while (j > 0 && trackTable[j - 1].get_track_value () > track)
|
||||
j--;
|
||||
|
||||
/*
|
||||
* Choose size.
|
||||
*/
|
||||
unsigned int sizes = nSizes;
|
||||
if (!sizes) return 0;
|
||||
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
|
||||
// Exact match.
|
||||
if (i == j) return trackTable[i].get_value (ptem, base, size_table);
|
||||
|
||||
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
unsigned int size_index;
|
||||
for (size_index = 0; size_index < sizes - 1; size_index++)
|
||||
if (size_table[size_index].to_float () >= ptem)
|
||||
break;
|
||||
// Interpolate.
|
||||
|
||||
return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
|
||||
*trackTableEntry, base));
|
||||
float t0 = trackTable[i].get_track_value ();
|
||||
float t1 = trackTable[j].get_track_value ();
|
||||
|
||||
float t = (track - t0) / (t1 - t0);
|
||||
|
||||
float a = trackTable[i].get_value (ptem, base, size_table);
|
||||
float b = trackTable[j].get_value (ptem, base, size_table);
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
|
@ -178,7 +207,7 @@ struct trak
|
|||
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||
{
|
||||
const TrackData &trackData = this+horizData;
|
||||
int tracking = trackData.get_tracking (this, ptem);
|
||||
float tracking = trackData.get_tracking (this, ptem);
|
||||
hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
|
||||
hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
|
@ -191,7 +220,7 @@ struct trak
|
|||
else
|
||||
{
|
||||
const TrackData &trackData = this+vertData;
|
||||
int tracking = trackData.get_tracking (this, ptem);
|
||||
float tracking = trackData.get_tracking (this, ptem);
|
||||
hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
|
||||
hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
../fonts/TRAK.ttf;--font-ptem=2;U+0041,U+0042,U+0043;[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
|
||||
../fonts/TRAK.ttf;--font-ptem=9;U+0041,U+0042,U+0043;[A.alt=0@30,0+1060|B=1@30,0+1060|C.alt=2@30,0+1060]
|
||||
../fonts/TRAK.ttf;--font-ptem=24;U+0041,U+0042,U+0043;[A.alt=0@-7,0+986|B=1@-7,0+986|C.alt=2@-7,0+986]
|
||||
../fonts/TRAK.ttf;--font-ptem=72;U+0041,U+0042,U+0043;[A.alt=0@-35,0+929|B=1@-35,0+929|C.alt=2@-35,0+929]
|
||||
../fonts/TRAK.ttf;--font-ptem=144;U+0041,U+0042,U+0043;[A.alt=0@-78,0+843|B=1@-78,0+843|C.alt=2@-78,0+843]
|
||||
../fonts/TRAK.ttf;--font-ptem=144;U+0041,U+0042,U+0043;[A.alt=0@-78,0+843|B=1@-78,0+843|C.alt=2@-78,0+843]
|
||||
../fonts/TRAK.ttf;--font-ptem=72;U+0041,U+0042,U+0043;[A.alt=0@-36,0+929|B=1@-36,0+929|C.alt=2@-36,0+929]
|
||||
../fonts/TRAK.ttf;--font-ptem=144;U+0041,U+0042,U+0043;[A.alt=0@-50,0+900|B=1@-50,0+900|C.alt=2@-50,0+900]
|
||||
../fonts/TRAK.ttf;--font-ptem=144 --features=-trak;U+0041,U+0042,U+0043;[A.alt=0+1000|B=1+1000|C.alt=2+1000]
|
||||
../fonts/TRAK.ttf;--font-ptem=144 --features=-trak[1:3];U+0041,U+0042,U+0043,U+0041,U+0042,U+0043;[A.alt=0@-78,0+843|B=1+1000|C.alt=2+1000|A.alt=3@-78,0+843|B=4@-78,0+843|C.alt=5@-78,0+843]
|
||||
../fonts/TRAK.ttf;--font-ptem=144 --features=-trak[1:3];U+0041,U+0042,U+0043,U+0041,U+0042,U+0043;[A.alt=0@-50,0+900|B=1+1000|C.alt=2+1000|A.alt=3@-50,0+900|B=4@-50,0+900|C.alt=5@-50,0+900]
|
||||
|
|
Loading…
Add table
Reference in a new issue