2011-08-24 19:13:15 +02:00
/*
2012-05-11 01:25:34 +02:00
* Copyright © 2011 , 2012 Google , Inc .
2011-08-24 19:13:15 +02:00
*
* 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 .
*
2018-02-15 06:11:45 +01:00
* Google Author ( s ) : Behdad Esfahbod , Roderick Sheeter
2011-08-24 19:13:15 +02:00
*/
# ifndef HB_OT_HMTX_TABLE_HH
# define HB_OT_HMTX_TABLE_HH
2018-08-26 07:36:36 +02:00
# include "hb-open-type.hh"
2017-11-15 05:16:45 +01:00
# include "hb-ot-hhea-table.hh"
2017-11-15 05:00:34 +01:00
# include "hb-ot-os2-table.hh"
# include "hb-ot-var-hvar-table.hh"
2011-08-24 19:13:15 +02:00
/*
2018-04-12 11:08:19 +02:00
* hmtx - - Horizontal Metrics
* https : //docs.microsoft.com/en-us/typography/opentype/spec/hmtx
* vmtx - - Vertical Metrics
* https : //docs.microsoft.com/en-us/typography/opentype/spec/vmtx
2011-08-24 19:13:15 +02:00
*/
# define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
2014-09-25 12:04:08 +02:00
# define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
2011-08-24 19:13:15 +02:00
2018-04-12 11:08:19 +02:00
namespace OT {
2014-09-25 12:04:08 +02:00
struct LongMetric
2011-08-24 19:13:15 +02:00
{
2016-03-01 08:41:26 +01:00
UFWORD advance ; /* Advance width/height. */
FWORD lsb ; /* Leading (left/top) side bearing. */
2011-08-24 19:13:15 +02:00
public :
DEFINE_SIZE_STATIC ( 4 ) ;
} ;
2018-02-14 23:16:25 +01:00
template < typename T , typename H >
2017-01-23 05:09:47 +01:00
struct hmtxvmtx
2011-08-24 19:13:15 +02:00
{
2015-02-17 15:27:44 +01:00
inline bool sanitize ( hb_sanitize_context_t * c ) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE ( this ) ;
2011-08-24 19:13:15 +02:00
/* We don't check for anything specific here. The users of the
* struct do all the hard work . . . */
2015-09-29 15:57:02 +02:00
return_trace ( true ) ;
2011-08-24 19:13:15 +02:00
}
2018-02-14 23:16:25 +01:00
2018-02-15 06:11:45 +01:00
inline bool subset_update_header ( hb_subset_plan_t * plan ,
unsigned int num_hmetrics ) const
2018-02-14 23:16:25 +01:00
{
2018-07-23 20:57:45 +02:00
hb_blob_t * src_blob = hb_sanitize_context_t ( ) . reference_table < H > ( plan - > source , H : : tableTag ) ;
2018-02-15 03:42:29 +01:00
hb_blob_t * dest_blob = hb_blob_copy_writable_or_fail ( src_blob ) ;
2018-02-15 01:37:35 +01:00
hb_blob_destroy ( src_blob ) ;
2018-02-14 23:16:25 +01:00
2018-02-15 04:22:37 +01:00
if ( unlikely ( ! dest_blob ) ) {
2018-02-15 01:37:35 +01:00
return false ;
}
2018-02-14 23:16:25 +01:00
2018-02-15 03:42:29 +01:00
unsigned int length ;
2018-02-15 06:11:45 +01:00
H * table = ( H * ) hb_blob_get_data ( dest_blob , & length ) ;
2018-02-15 01:37:35 +01:00
table - > numberOfLongMetrics . set ( num_hmetrics ) ;
2018-02-14 23:16:25 +01:00
2018-05-30 21:23:51 +02:00
bool result = plan - > add_table ( H : : tableTag , dest_blob ) ;
2018-02-15 01:37:35 +01:00
hb_blob_destroy ( dest_blob ) ;
return result ;
2018-02-14 23:16:25 +01:00
}
inline bool subset ( hb_subset_plan_t * plan ) const
{
typename T : : accelerator_t _mtx ;
2018-02-15 06:11:45 +01:00
_mtx . init ( plan - > source ) ;
2018-02-14 23:16:25 +01:00
/* All the trailing glyphs with the same advance can use one LongMetric
* and just keep LSB */
2018-05-30 21:23:51 +02:00
hb_vector_t < hb_codepoint_t > & gids = plan - > glyphs ;
2018-02-14 23:16:25 +01:00
unsigned int num_advances = gids . len ;
2018-02-15 06:11:45 +01:00
unsigned int last_advance = _mtx . get_advance ( gids [ num_advances - 1 ] ) ;
2018-02-14 23:16:25 +01:00
while ( num_advances > 1
2018-02-15 06:11:45 +01:00
& & last_advance = = _mtx . get_advance ( gids [ num_advances - 2 ] ) )
2018-02-14 23:16:25 +01:00
{
num_advances - - ;
}
/* alloc the new table */
size_t dest_sz = num_advances * 4
+ ( gids . len - num_advances ) * 2 ;
2018-02-24 00:36:14 +01:00
void * dest = ( void * ) malloc ( dest_sz ) ;
2018-02-15 04:22:37 +01:00
if ( unlikely ( ! dest ) )
2018-02-14 23:16:25 +01:00
{
return false ;
}
DEBUG_MSG ( SUBSET , nullptr , " %c%c%c%c in src has %d advances, %d lsbs " , HB_UNTAG ( T : : tableTag ) , _mtx . num_advances , _mtx . num_metrics - _mtx . num_advances ) ;
2018-02-15 23:28:29 +01:00
DEBUG_MSG ( SUBSET , nullptr , " %c%c%c%c in dest has %d advances, %d lsbs, %u bytes " , HB_UNTAG ( T : : tableTag ) , num_advances , gids . len - num_advances , ( unsigned int ) dest_sz ) ;
2018-02-14 23:16:25 +01:00
2018-02-15 06:11:45 +01:00
const char * source_table = hb_blob_get_data ( _mtx . blob , nullptr ) ;
2018-02-14 23:16:25 +01:00
// Copy everything over
LongMetric * old_metrics = ( LongMetric * ) source_table ;
FWORD * lsbs = ( FWORD * ) ( old_metrics + _mtx . num_advances ) ;
char * dest_pos = ( char * ) dest ;
2018-03-20 02:39:22 +01:00
bool failed = false ;
2018-02-14 23:16:25 +01:00
for ( unsigned int i = 0 ; i < gids . len ; i + + )
{
/* the last metric or the one for gids[i] */
2018-02-15 21:53:52 +01:00
LongMetric * src_metric = old_metrics + MIN ( ( hb_codepoint_t ) _mtx . num_advances - 1 , gids [ i ] ) ;
2018-02-14 23:16:25 +01:00
if ( gids [ i ] < _mtx . num_advances )
{
/* src is a LongMetric */
if ( i < num_advances )
{
/* dest is a LongMetric, copy it */
* ( ( LongMetric * ) dest_pos ) = * src_metric ;
}
else
{
/* dest just lsb */
* ( ( FWORD * ) dest_pos ) = src_metric - > lsb ;
}
}
else
{
2018-03-20 02:39:22 +01:00
if ( gids [ i ] > = _mtx . num_metrics )
{
DEBUG_MSG ( SUBSET , nullptr , " gid %d is >= number of source metrics %d " ,
gids [ i ] , _mtx . num_metrics ) ;
failed = true ;
break ;
}
FWORD src_lsb = * ( lsbs + gids [ i ] - _mtx . num_advances ) ;
2018-02-14 23:16:25 +01:00
if ( i < num_advances )
{
/* dest needs a full LongMetric */
LongMetric * metric = ( LongMetric * ) dest_pos ;
metric - > advance = src_metric - > advance ;
metric - > lsb = src_lsb ;
}
else
{
/* dest just needs an lsb */
* ( ( FWORD * ) dest_pos ) = src_lsb ;
}
}
dest_pos + = ( i < num_advances ? 4 : 2 ) ;
}
2018-02-15 06:11:45 +01:00
_mtx . fini ( ) ;
2018-02-14 23:16:25 +01:00
// Amend header num hmetrics
2018-03-20 02:39:22 +01:00
if ( failed | | unlikely ( ! subset_update_header ( plan , num_advances ) ) )
2018-02-14 23:16:25 +01:00
{
2018-02-15 06:11:45 +01:00
free ( dest ) ;
2018-02-14 23:16:25 +01:00
return false ;
}
hb_blob_t * result = hb_blob_create ( ( const char * ) dest ,
dest_sz ,
HB_MEMORY_MODE_READONLY ,
2018-02-24 00:36:14 +01:00
dest ,
2018-02-14 23:16:25 +01:00
free ) ;
2018-05-30 21:23:51 +02:00
bool success = plan - > add_table ( T : : tableTag , result ) ;
2018-02-24 00:36:14 +01:00
hb_blob_destroy ( result ) ;
return success ;
2018-02-14 23:16:25 +01:00
}
2017-11-15 05:00:34 +01:00
struct accelerator_t
{
2018-02-14 23:16:25 +01:00
friend struct hmtxvmtx ;
2017-11-15 05:00:34 +01:00
inline void init ( hb_face_t * face ,
2017-11-15 05:02:24 +01:00
unsigned int default_advance_ = 0 )
2017-11-15 05:00:34 +01:00
{
2018-02-13 03:48:51 +01:00
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem ( face ) ;
2017-11-15 05:00:34 +01:00
bool got_font_extents = false ;
2017-11-15 05:16:45 +01:00
if ( T : : os2Tag )
2017-11-15 05:00:34 +01:00
{
2018-07-23 07:40:32 +02:00
hb_blob_t * os2_blob = hb_sanitize_context_t ( ) . reference_table < os2 > ( face ) ;
2018-05-08 11:47:42 +02:00
const os2 * os2_table = os2_blob - > as < os2 > ( ) ;
2017-11-15 05:00:34 +01:00
# define USE_TYPO_METRICS (1u<<7)
if ( 0 ! = ( os2_table - > fsSelection & USE_TYPO_METRICS ) )
{
2017-11-15 05:02:24 +01:00
ascender = os2_table - > sTypoAscender ;
descender = os2_table - > sTypoDescender ;
line_gap = os2_table - > sTypoLineGap ;
got_font_extents = ( ascender | descender ) ! = 0 ;
2017-11-15 05:00:34 +01:00
}
hb_blob_destroy ( os2_blob ) ;
}
2018-07-23 07:40:32 +02:00
hb_blob_t * _hea_blob = hb_sanitize_context_t ( ) . reference_table < H > ( face ) ;
2018-05-08 11:47:42 +02:00
const H * _hea_table = _hea_blob - > as < H > ( ) ;
2017-11-15 05:02:24 +01:00
num_advances = _hea_table - > numberOfLongMetrics ;
2017-11-15 05:00:34 +01:00
if ( ! got_font_extents )
{
2017-11-15 05:02:24 +01:00
ascender = _hea_table - > ascender ;
descender = _hea_table - > descender ;
line_gap = _hea_table - > lineGap ;
got_font_extents = ( ascender | descender ) ! = 0 ;
2017-11-15 05:00:34 +01:00
}
hb_blob_destroy ( _hea_blob ) ;
2017-11-15 05:02:24 +01:00
has_font_extents = got_font_extents ;
2017-11-15 05:00:34 +01:00
2018-07-23 07:40:32 +02:00
blob = hb_sanitize_context_t ( ) . reference_table < hmtxvmtx > ( face , T : : tableTag ) ;
2017-11-15 05:00:34 +01:00
/* Cap num_metrics() and num_advances() based on table length. */
2017-11-15 05:02:24 +01:00
unsigned int len = hb_blob_get_length ( blob ) ;
if ( unlikely ( num_advances * 4 > len ) )
num_advances = len / 4 ;
num_metrics = num_advances + ( len - 4 * num_advances ) / 2 ;
2017-11-15 05:00:34 +01:00
/* We MUST set num_metrics to zero if num_advances is zero.
* Our get_advance ( ) depends on that . */
2017-11-15 05:02:24 +01:00
if ( unlikely ( ! num_advances ) )
2017-11-15 05:00:34 +01:00
{
2017-11-15 05:02:24 +01:00
num_metrics = num_advances = 0 ;
hb_blob_destroy ( blob ) ;
blob = hb_blob_get_empty ( ) ;
2017-11-15 05:00:34 +01:00
}
2018-05-08 11:47:42 +02:00
table = blob - > as < hmtxvmtx > ( ) ;
2017-11-15 05:00:34 +01:00
2018-07-23 07:40:32 +02:00
var_blob = hb_sanitize_context_t ( ) . reference_table < HVARVVAR > ( face , T : : variationsTag ) ;
2018-05-08 11:47:42 +02:00
var_table = var_blob - > as < HVARVVAR > ( ) ;
2017-11-15 05:00:34 +01:00
}
inline void fini ( void )
{
2017-11-15 05:02:24 +01:00
hb_blob_destroy ( blob ) ;
hb_blob_destroy ( var_blob ) ;
2017-11-15 05:00:34 +01:00
}
2018-02-14 23:16:25 +01:00
inline unsigned int get_advance ( hb_codepoint_t glyph ) const
2017-11-15 05:00:34 +01:00
{
2017-11-15 05:02:24 +01:00
if ( unlikely ( glyph > = num_metrics ) )
2017-11-15 05:00:34 +01:00
{
2018-02-14 23:16:25 +01:00
/* If num_metrics is zero, it means we don't have the metrics table
* for this direction : return default advance . Otherwise , it means that the
* glyph index is out of bound : return zero . */
if ( num_metrics )
return 0 ;
else
return default_advance ;
2017-11-15 05:00:34 +01:00
}
2018-09-10 23:29:26 +02:00
return table - > longMetricZ [ MIN ( glyph , ( uint32_t ) num_advances - 1 ) ] . advance ;
2018-02-14 23:16:25 +01:00
}
inline unsigned int get_advance ( hb_codepoint_t glyph ,
hb_font_t * font ) const
{
2018-02-15 20:29:01 +01:00
unsigned int advance = get_advance ( glyph ) ;
if ( likely ( glyph < num_metrics ) )
{
advance + = ( font - > num_coords ? var_table - > get_advance_var ( glyph , font - > coords , font - > num_coords ) : 0 ) ; // TODO Optimize?!
}
2018-03-03 02:33:49 +01:00
return advance ;
2017-11-15 05:00:34 +01:00
}
public :
bool has_font_extents ;
unsigned short ascender ;
unsigned short descender ;
unsigned short line_gap ;
2017-11-15 05:02:24 +01:00
2018-02-14 23:16:25 +01:00
protected :
2017-11-15 05:00:34 +01:00
unsigned int num_metrics ;
unsigned int num_advances ;
unsigned int default_advance ;
2017-11-15 05:02:24 +01:00
2018-02-14 23:16:25 +01:00
private :
2017-11-15 05:02:24 +01:00
const hmtxvmtx * table ;
hb_blob_t * blob ;
const HVARVVAR * var_table ;
hb_blob_t * var_blob ;
2017-11-15 05:00:34 +01:00
} ;
protected :
2018-09-10 23:29:26 +02:00
UnsizedArrayOf < LongMetric > longMetricZ ; /* Paired advance width and leading
2011-08-24 19:13:15 +02:00
* bearing values for each glyph . The
* value numOfHMetrics comes from
* the ' hhea ' table . If the font is
* monospaced , only one entry need
* be in the array , but that entry is
* required . The last entry applies to
* all subsequent glyphs . */
2018-09-10 23:29:26 +02:00
/*UnsizedArrayOf<FWORD> leadingBearingX;*/ /* Here the advance is assumed
2014-09-25 12:04:08 +02:00
* to be the same as the advance
2011-08-24 19:13:15 +02:00
* for the last entry above . The
* number of entries in this array is
* derived from numGlyphs ( from ' maxp '
2014-09-25 12:04:08 +02:00
* table ) minus numberOfLongMetrics .
* This generally is used with a run
* of monospaced glyphs ( e . g . , Kanji
2011-08-24 19:13:15 +02:00
* fonts or Courier fonts ) . Only one
* run is allowed and it must be at
* the end . This allows a monospaced
2014-09-25 12:04:08 +02:00
* font to vary the side bearing
2011-08-24 19:13:15 +02:00
* values for each glyph . */
public :
2018-09-10 23:29:26 +02:00
DEFINE_SIZE_ARRAY ( 0 , longMetricZ ) ;
2011-08-24 19:13:15 +02:00
} ;
2018-02-14 23:16:25 +01:00
struct hmtx : hmtxvmtx < hmtx , hhea > {
2014-09-25 12:04:08 +02:00
static const hb_tag_t tableTag = HB_OT_TAG_hmtx ;
2017-11-15 05:16:45 +01:00
static const hb_tag_t variationsTag = HB_OT_TAG_HVAR ;
static const hb_tag_t os2Tag = HB_OT_TAG_os2 ;
2014-09-25 12:04:08 +02:00
} ;
2018-02-14 23:16:25 +01:00
struct vmtx : hmtxvmtx < vmtx , vhea > {
2014-09-25 12:04:08 +02:00
static const hb_tag_t tableTag = HB_OT_TAG_vmtx ;
2017-11-15 05:16:45 +01:00
static const hb_tag_t variationsTag = HB_OT_TAG_VVAR ;
static const hb_tag_t os2Tag = HB_TAG_NONE ;
2014-09-25 12:04:08 +02:00
} ;
2012-08-28 23:57:49 +02:00
2018-08-27 00:11:24 +02:00
struct hmtx_accelerator_t : hmtx : : accelerator_t { } ;
struct vmtx_accelerator_t : vmtx : : accelerator_t { } ;
2012-11-17 03:49:54 +01:00
} /* namespace OT */
2012-08-28 23:57:49 +02:00
2011-08-24 19:13:15 +02:00
# endif /* HB_OT_HMTX_TABLE_HH */