From 1ab16f4556ef3e54a40b63cf4570c0ae986894e7 Mon Sep 17 00:00:00 2001 From: Ebrahim Byagowi Date: Sat, 24 Feb 2018 12:49:42 +0330 Subject: [PATCH] [aat] Implement trak logic (#816) --- src/hb-aat-layout-kerx-table.hh | 7 +++ src/hb-aat-layout-private.hh | 3 ++ src/hb-aat-layout-trak-table.hh | 78 +++++++++++++++++++++++++++++++-- src/hb-aat-layout.cc | 46 +++++++++++++++++++ src/hb-open-type-private.hh | 4 +- src/hb-ot-layout-private.hh | 22 ++++++++++ src/hb-ot-layout.cc | 4 ++ src/hb-ot-shape.cc | 2 + 8 files changed, 161 insertions(+), 5 deletions(-) diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index b061f11d2..06282e2ce 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -263,6 +263,13 @@ struct kerx { static const hb_tag_t tableTag = HB_AAT_TAG_kerx; + inline bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + /* TODO */ + return_trace (false); + } + struct SubTableWrapper { enum coverage_flags_t { diff --git a/src/hb-aat-layout-private.hh b/src/hb-aat-layout-private.hh index c1c607a2f..ce75c8e71 100644 --- a/src/hb-aat-layout-private.hh +++ b/src/hb-aat-layout-private.hh @@ -37,4 +37,7 @@ HB_INTERNAL void hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer); +HB_INTERNAL void +hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer); + #endif /* HB_AAT_LAYOUT_PRIVATE_HH */ diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh index 6dbd05ab5..a5dc3ffd0 100644 --- a/src/hb-aat-layout-trak-table.hh +++ b/src/hb-aat-layout-trak-table.hh @@ -1,6 +1,6 @@ /* - * Copyright © 2018 Google, Inc. * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2018 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -45,10 +45,15 @@ struct TrackTableEntry return_trace (c->check_struct (this)); } + inline float get_value (const void *base, unsigned int index) const + { + return (base+values)[index]; + } + protected: Fixed track; /* Track value for this record. */ HBUINT16 trackNameID; /* The 'name' table index for this track */ - OffsetTo > + OffsetTo > values; /* Offset from start of tracking table to * per-size tracking values for this track. */ @@ -61,15 +66,48 @@ struct TrackData inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + /* TODO */ return_trace (c->check_struct (this)); } + inline float get_tracking (const void *base, float ptem) const + { + /* CoreText points are CSS pixels (96 per inch), + * NOT typographic points (72 per inch). + * + * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html + */ + float csspx = ptem * 96.f / 72.f; + Fixed fixed_size; + fixed_size.set_float (csspx); + + // TODO: Make indexing work and use only an entry with zero track + const TrackTableEntry trackTableEntry = trackTable[0]; + + unsigned int size_index; + for (size_index = 0; size_index < nSizes; ++size_index) + if ((base+sizeTable)[size_index] >= fixed_size) + break; + + // We don't attempt to extrapolate to larger or smaller values + if (size_index == nSizes) + return trackTableEntry.get_value (base, nSizes - 1); + if (size_index == 0 || (base+sizeTable)[size_index] == fixed_size) + return trackTableEntry.get_value (base, size_index); + + float s0 = (base+sizeTable)[size_index - 1].to_float (); + float s1 = (base+sizeTable)[size_index].to_float (); + float t = (csspx - s0) / (s1 - s0); + return t * trackTableEntry.get_value (base, size_index) + + (1.0 - t) * trackTableEntry.get_value (base, size_index - 1); + } + protected: HBUINT16 nTracks; /* Number of separate tracks included in this table. */ HBUINT16 nSizes; /* Number of point sizes included in this table. */ LOffsetTo > sizeTable; - TrackTableEntry trackTable[VAR];/* Array[nSizes] of size values. */ + UnsizedArrayOf trackTable;/* Array[nSizes] of size values. */ public: DEFINE_SIZE_ARRAY (8, trackTable); @@ -82,9 +120,43 @@ struct trak inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + /* TODO */ return_trace (c->check_struct (this)); } + inline bool apply (hb_aat_apply_context_t *c) const + { + TRACE_APPLY (this); + const float ptem = c->font->ptem; + if (ptem > 0.f) + { + hb_buffer_t *buffer = c->buffer; + if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction)) + { + const TrackData trackData = this+horizOffset; + float tracking = trackData.get_tracking (this, ptem); + hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2); + foreach_grapheme (buffer, start, end) + { + buffer->pos[start].x_advance += advance_to_add; + buffer->pos[end].x_advance += advance_to_add; + } + } + else + { + const TrackData trackData = this+vertOffset; + float tracking = trackData.get_tracking (this, ptem); + hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2); + foreach_grapheme (buffer, start, end) + { + buffer->pos[start].y_advance += advance_to_add; + buffer->pos[end].y_advance += advance_to_add; + } + } + } + return_trace (false); + } + protected: FixedVersion<> version; /* Version of the tracking table--currently * 0x00010000u for version 1.0. */ diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 3b967c6b7..2b67bf362 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -55,6 +55,40 @@ _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr) return morx; } +static inline const AAT::kerx& +_get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + { + if (blob) + *blob = hb_blob_get_empty (); + return OT::Null(AAT::kerx); + } + hb_ot_layout_t * layout = hb_ot_layout_from_face (face); + /* XXX this doesn't call set_num_glyphs on sanitizer. */ + const AAT::kerx& kerx = *(layout->kerx.get ()); + if (blob) + *blob = layout->kerx.blob; + return kerx; +} + +static inline const AAT::trak& +_get_trak (hb_face_t *face, hb_blob_t **blob = nullptr) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) + { + if (blob) + *blob = hb_blob_get_empty (); + return OT::Null(AAT::trak); + } + hb_ot_layout_t * layout = hb_ot_layout_from_face (face); + /* XXX this doesn't call set_num_glyphs on sanitizer. */ + const AAT::trak& trak = *(layout->trak.get ()); + if (blob) + *blob = layout->trak.blob; + return trak; +} + static inline void _hb_aat_layout_create (hb_face_t *face) { @@ -78,3 +112,15 @@ hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer) AAT::hb_aat_apply_context_t c (font, buffer, blob); morx.apply (&c); } + +void +hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer) +{ + hb_blob_t *blob; + const AAT::kerx& kerx = _get_kerx (font->face, &blob); + const AAT::trak& trak = _get_trak (font->face, &blob); + + AAT::hb_aat_apply_context_t c (font, buffer, blob); + kerx.apply (&c); + trak.apply (&c); +} diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh index f5c20bcb6..e46578871 100644 --- a/src/hb-open-type-private.hh +++ b/src/hb-open-type-private.hh @@ -692,8 +692,8 @@ struct F2DOT14 : HBINT16 /* 32-bit signed fixed-point number (16.16). */ struct Fixed: HBINT32 { - //inline float to_float (void) const { return ???; } - //inline void set_float (float f) { v.set (f * ???); } + inline float to_float (void) const { return ((int32_t) v) / 65536.0; } + inline void set_float (float f) { v.set (round (f * 65536.0)); } public: DEFINE_SIZE_STATIC (4); }; diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh index 0c3bcbc5b..ce1f6a8ec 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh @@ -363,6 +363,28 @@ _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info) return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0; } + +/* Loop over grapheme. Based on foreach_cluster(). */ +#define foreach_grapheme(buffer, start, end) \ + for (unsigned int \ + _count = buffer->len, \ + start = 0, end = _count ? _next_grapheme (buffer, 0) : 0; \ + start < _count; \ + start = end, end = _next_grapheme (buffer, start)) + +static inline unsigned int +_next_grapheme (hb_buffer_t *buffer, unsigned int start) +{ + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + + while (++start < count && _hb_glyph_info_is_unicode_mark (&info[start])) + ; + + return start; +} + + #define info_cc(info) (_hb_glyph_info_get_modified_combining_class (&(info))) static inline bool diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 4cf6c722c..b92ba05f4 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -65,6 +65,8 @@ _hb_ot_layout_create (hb_face_t *face) layout->fvar.init (face); layout->avar.init (face); layout->morx.init (face); + layout->kerx.init (face); + layout->trak.init (face); { /* @@ -215,6 +217,8 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout) layout->fvar.fini (); layout->avar.fini (); layout->morx.fini (); + layout->kerx.fini (); + layout->trak.fini (); free (layout); } diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc index d9ba0f6b3..d2d8012d0 100644 --- a/src/hb-ot-shape.cc +++ b/src/hb-ot-shape.cc @@ -787,6 +787,8 @@ hb_ot_position (hb_ot_shape_context_t *c) _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); _hb_buffer_deallocate_gsubgpos_vars (c->buffer); + + //hb_aat_layout_position (c->font, c->buffer); } static inline void