2018-02-07 01:04:09 +01:00
/*
* Copyright © 2018 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 .
*
2018-02-22 07:23:05 +01:00
* Google Author ( s ) : Garret Rieger , Roderick Sheeter
2018-02-07 01:04:09 +01:00
*/
2018-02-07 22:09:54 +01:00
# include "hb-open-type-private.hh"
2018-02-07 02:05:22 +01:00
# include "hb-ot-glyf-table.hh"
2018-02-07 22:09:54 +01:00
# include "hb-set.h"
2018-02-07 01:04:09 +01:00
# include "hb-subset-glyf.hh"
2018-02-17 01:01:00 +01:00
# include "hb-subset-plan.hh"
2018-02-07 01:04:09 +01:00
2018-02-10 22:30:03 +01:00
static bool
2018-02-08 04:01:21 +01:00
_calculate_glyf_and_loca_prime_size ( const OT : : glyf : : accelerator_t & glyf ,
2018-02-10 22:47:50 +01:00
hb_prealloced_array_t < hb_codepoint_t > & glyph_ids ,
2018-02-22 07:23:05 +01:00
hb_bool_t drop_hints ,
bool * use_short_loca /* OUT */ ,
unsigned int * glyf_size /* OUT */ ,
unsigned int * loca_size /* OUT */ ,
hb_prealloced_array_t < unsigned int > * instruction_ranges /* OUT */ )
2018-02-07 22:09:54 +01:00
{
unsigned int total = 0 ;
2018-02-14 01:35:30 +01:00
for ( unsigned int i = 0 ; i < glyph_ids . len ; i + + )
{
2018-02-09 04:22:47 +01:00
hb_codepoint_t next_glyph = glyph_ids [ i ] ;
2018-02-07 22:09:54 +01:00
unsigned int start_offset , end_offset ;
2018-02-22 07:23:05 +01:00
if ( unlikely ( ! glyf . get_offsets ( next_glyph , & start_offset , & end_offset ) ) )
{
DEBUG_MSG ( SUBSET , nullptr , " Invalid gid %d " , next_glyph ) ;
continue ;
}
unsigned int instruction_start = 0 , instruction_end = 0 ;
if ( drop_hints )
{
if ( unlikely ( ! glyf . get_instruction_offsets ( start_offset , end_offset ,
& instruction_start , & instruction_end ) ) )
{
DEBUG_MSG ( SUBSET , nullptr , " Unable to get instruction offsets for %d " , next_glyph ) ;
return false ;
}
}
* ( instruction_ranges - > push ( ) ) = instruction_start ;
* ( instruction_ranges - > push ( ) ) = instruction_end ;
2018-02-07 22:09:54 +01:00
2018-02-22 07:23:05 +01:00
total + = end_offset - start_offset - ( instruction_end - instruction_start ) ;
fprintf ( stderr , " %d ends at %d (was %d to %d, remove %d) \n " , next_glyph , total , start_offset , end_offset , instruction_end - instruction_start ) ;
2018-02-07 22:09:54 +01:00
}
2018-02-08 04:01:21 +01:00
* glyf_size = total ;
2018-02-10 03:41:21 +01:00
* use_short_loca = ( total < = 131070 ) ;
2018-02-22 07:23:05 +01:00
* loca_size = ( glyph_ids . len + 1 )
2018-02-10 03:41:21 +01:00
* ( * use_short_loca ? sizeof ( OT : : HBUINT16 ) : sizeof ( OT : : HBUINT32 ) ) ;
DEBUG_MSG ( SUBSET , nullptr , " preparing to subset glyf: final size %d, loca size %d, using %s loca " ,
total ,
* loca_size ,
* use_short_loca ? " short " : " long " ) ;
2018-02-07 22:09:54 +01:00
return true ;
}
2018-02-21 00:33:03 +01:00
static bool
_write_loca_entry ( unsigned int id ,
unsigned int offset ,
bool is_short ,
void * loca_prime ,
unsigned int loca_size )
{
unsigned int entry_size = is_short ? sizeof ( OT : : HBUINT16 ) : sizeof ( OT : : HBUINT32 ) ;
if ( ( id + 1 ) * entry_size < = loca_size )
{
if ( is_short ) {
( ( OT : : HBUINT16 * ) loca_prime ) [ id ] . set ( offset / 2 ) ;
} else {
( ( OT : : HBUINT32 * ) loca_prime ) [ id ] . set ( offset ) ;
}
return true ;
2018-02-10 03:41:21 +01:00
}
2018-02-21 00:33:03 +01:00
// Offset was not written because the write is out of bounds.
DEBUG_MSG ( SUBSET ,
nullptr ,
" WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d. " ,
id ,
loca_size ) ;
return false ;
2018-02-10 03:41:21 +01:00
}
2018-02-17 01:01:00 +01:00
static void
_update_components ( hb_subset_plan_t * plan ,
char * glyph_start ,
unsigned int length )
{
OT : : glyf : : CompositeGlyphHeader : : Iterator iterator ;
if ( OT : : glyf : : CompositeGlyphHeader : : get_iterator ( glyph_start ,
length ,
& iterator ) )
{
do
{
hb_codepoint_t new_gid ;
if ( ! hb_subset_plan_new_gid_for_old_id ( plan ,
iterator . current - > glyphIndex ,
& new_gid ) )
continue ;
( ( OT : : glyf : : CompositeGlyphHeader * ) iterator . current ) - > glyphIndex . set ( new_gid ) ;
} while ( iterator . move_to_next ( ) ) ;
}
}
2018-02-10 22:30:03 +01:00
static bool
2018-02-17 01:01:00 +01:00
_write_glyf_and_loca_prime ( hb_subset_plan_t * plan ,
const OT : : glyf : : accelerator_t & glyf ,
2018-02-08 04:01:21 +01:00
const char * glyf_data ,
2018-02-10 03:41:21 +01:00
bool use_short_loca ,
2018-02-22 07:23:05 +01:00
hb_prealloced_array_t < unsigned int > & instruction_ranges ,
2018-02-21 00:33:03 +01:00
unsigned int glyf_prime_size ,
2018-02-08 04:01:21 +01:00
char * glyf_prime_data /* OUT */ ,
2018-02-21 00:33:03 +01:00
unsigned int loca_prime_size ,
2018-02-08 04:01:21 +01:00
char * loca_prime_data /* OUT */ )
2018-02-07 22:09:54 +01:00
{
2018-02-17 01:01:00 +01:00
hb_prealloced_array_t < hb_codepoint_t > & glyph_ids = plan - > gids_to_retain_sorted ;
2018-02-07 22:09:54 +01:00
char * glyf_prime_data_next = glyf_prime_data ;
2018-02-21 00:33:03 +01:00
bool success = true ;
2018-02-14 01:35:30 +01:00
for ( unsigned int i = 0 ; i < glyph_ids . len ; i + + )
{
unsigned int start_offset , end_offset ;
if ( unlikely ( ! glyf . get_offsets ( glyph_ids [ i ] , & start_offset , & end_offset ) ) )
end_offset = start_offset = 0 ;
2018-02-22 07:23:05 +01:00
unsigned int instruction_start = instruction_ranges [ i * 2 ] ;
unsigned int instruction_end = instruction_ranges [ i * 2 + 1 ] ;
2018-02-07 22:09:54 +01:00
2018-02-22 07:23:05 +01:00
int length = end_offset - start_offset - ( instruction_end - instruction_start ) ;
2018-02-21 01:48:52 +01:00
if ( glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size )
{
DEBUG_MSG ( SUBSET ,
nullptr ,
2018-02-22 07:23:05 +01:00
" WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d) " ,
i , length ) ;
2018-02-21 01:48:52 +01:00
return false ;
}
2018-02-22 07:23:05 +01:00
if ( instruction_start = = instruction_end )
{
fprintf ( stderr , " i=%d copy %d bytes from %d to %ld \n " , i , length , start_offset , glyf_prime_data_next - glyf_prime_data ) ;
memcpy ( glyf_prime_data_next , glyf_data + start_offset , length ) ;
}
else
{
fprintf ( stderr , " i=%d copy %d bytes from %d to %ld \n " , i , instruction_start - start_offset , start_offset , glyf_prime_data_next - glyf_prime_data ) ;
fprintf ( stderr , " i=%d copy %d bytes from %d to %ld \n " , i , end_offset - instruction_end , instruction_end , glyf_prime_data_next + instruction_start - start_offset - glyf_prime_data ) ;
memcpy ( glyf_prime_data_next , glyf_data + start_offset , instruction_start - start_offset ) ;
memcpy ( glyf_prime_data_next + instruction_start - start_offset , glyf_data + instruction_end , end_offset - instruction_end ) ;
/* if the instructions end at the end this was a composite glyph */
if ( instruction_end = = end_offset )
; // TODO(rsheeter) remove WE_HAVE_INSTRUCTIONS from last flags
else
; // TODO(rsheeter) zero instructionLength
}
2018-02-10 03:41:21 +01:00
2018-02-21 00:33:03 +01:00
success = success & & _write_loca_entry ( i ,
glyf_prime_data_next - glyf_prime_data ,
use_short_loca ,
loca_prime_data ,
loca_prime_size ) ;
2018-02-22 07:23:05 +01:00
_update_components ( plan , glyf_prime_data_next , length ) ;
2018-02-08 04:01:21 +01:00
2018-02-07 22:09:54 +01:00
glyf_prime_data_next + = length ;
}
2018-02-21 00:33:03 +01:00
success = success & & _write_loca_entry ( glyph_ids . len ,
glyf_prime_data_next - glyf_prime_data ,
use_short_loca ,
loca_prime_data ,
loca_prime_size ) ;
return success ;
2018-02-07 22:09:54 +01:00
}
2018-02-10 22:30:03 +01:00
static bool
2018-02-08 04:01:21 +01:00
_hb_subset_glyf_and_loca ( const OT : : glyf : : accelerator_t & glyf ,
const char * glyf_data ,
2018-02-22 07:23:05 +01:00
hb_subset_plan_t * plan ,
2018-02-10 03:41:21 +01:00
bool * use_short_loca ,
2018-02-08 04:01:21 +01:00
hb_blob_t * * glyf_prime /* OUT */ ,
hb_blob_t * * loca_prime /* OUT */ )
2018-02-07 01:04:09 +01:00
{
2018-02-07 22:09:54 +01:00
// TODO(grieger): Sanity check allocation size for the new table.
2018-02-17 01:01:00 +01:00
hb_prealloced_array_t < hb_codepoint_t > & glyphs_to_retain = plan - > gids_to_retain_sorted ;
2018-02-07 22:09:54 +01:00
unsigned int glyf_prime_size ;
2018-02-08 04:01:21 +01:00
unsigned int loca_prime_size ;
2018-02-22 07:23:05 +01:00
hb_prealloced_array_t < unsigned int > instruction_ranges ;
instruction_ranges . init ( ) ;
2018-02-10 03:41:21 +01:00
2018-02-08 04:01:21 +01:00
if ( unlikely ( ! _calculate_glyf_and_loca_prime_size ( glyf ,
glyphs_to_retain ,
2018-02-22 07:23:05 +01:00
plan - > drop_hints ,
2018-02-10 03:41:21 +01:00
use_short_loca ,
2018-02-08 04:01:21 +01:00
& glyf_prime_size ,
2018-02-22 07:23:05 +01:00
& loca_prime_size ,
& instruction_ranges ) ) ) {
instruction_ranges . finish ( ) ;
2018-02-07 22:09:54 +01:00
return false ;
}
2018-02-07 01:04:09 +01:00
2018-02-13 03:51:10 +01:00
char * glyf_prime_data = ( char * ) malloc ( glyf_prime_size ) ;
char * loca_prime_data = ( char * ) malloc ( loca_prime_size ) ;
2018-02-17 01:01:00 +01:00
if ( unlikely ( ! _write_glyf_and_loca_prime ( plan , glyf , glyf_data ,
2018-02-10 03:41:21 +01:00
* use_short_loca ,
2018-02-22 07:23:05 +01:00
instruction_ranges ,
2018-02-08 04:01:21 +01:00
glyf_prime_size , glyf_prime_data ,
loca_prime_size , loca_prime_data ) ) ) {
2018-02-07 22:09:54 +01:00
free ( glyf_prime_data ) ;
2018-02-21 00:33:03 +01:00
free ( loca_prime_data ) ;
2018-02-22 07:23:05 +01:00
instruction_ranges . finish ( ) ;
2018-02-07 22:09:54 +01:00
return false ;
}
2018-02-22 07:23:05 +01:00
instruction_ranges . finish ( ) ;
2018-02-07 02:05:22 +01:00
2018-02-07 22:09:54 +01:00
* glyf_prime = hb_blob_create ( glyf_prime_data ,
glyf_prime_size ,
HB_MEMORY_MODE_READONLY ,
glyf_prime_data ,
free ) ;
2018-02-08 04:01:21 +01:00
* loca_prime = hb_blob_create ( loca_prime_data ,
loca_prime_size ,
HB_MEMORY_MODE_READONLY ,
loca_prime_data ,
free ) ;
2018-02-07 01:04:09 +01:00
return true ;
}
2018-02-07 22:28:11 +01:00
/**
* hb_subset_glyf :
* Subsets the glyph table according to a provided plan .
*
* Return value : subsetted glyf table .
*
* Since : 1.7 .5
* */
bool
2018-02-08 01:53:18 +01:00
hb_subset_glyf_and_loca ( hb_subset_plan_t * plan ,
2018-02-09 21:52:08 +01:00
bool * use_short_loca , /* OUT */
hb_blob_t * * glyf_prime , /* OUT */
2018-02-08 01:53:18 +01:00
hb_blob_t * * loca_prime /* OUT */ )
2018-02-07 22:28:11 +01:00
{
2018-02-14 23:16:25 +01:00
hb_blob_t * glyf_blob = OT : : Sanitizer < OT : : glyf > ( ) . sanitize ( plan - > source - > reference_table ( HB_OT_TAG_glyf ) ) ;
2018-02-07 22:28:11 +01:00
const char * glyf_data = hb_blob_get_data ( glyf_blob , nullptr ) ;
OT : : glyf : : accelerator_t glyf ;
2018-02-14 23:16:25 +01:00
glyf . init ( plan - > source ) ;
2018-02-10 03:41:21 +01:00
bool result = _hb_subset_glyf_and_loca ( glyf ,
glyf_data ,
2018-02-17 01:01:00 +01:00
plan ,
2018-02-10 03:41:21 +01:00
use_short_loca ,
glyf_prime ,
loca_prime ) ;
2018-02-07 22:28:11 +01:00
glyf . fini ( ) ;
return result ;
}