|
|
|
@ -68,247 +68,6 @@ using str_buff_t = hb_vector_t<unsigned char>; |
|
|
|
|
using str_buff_vec_t = hb_vector_t<str_buff_t>; |
|
|
|
|
using glyph_to_sid_map_t = hb_vector_t<code_pair_t>; |
|
|
|
|
|
|
|
|
|
struct length_f_t |
|
|
|
|
{ |
|
|
|
|
template <typename Iterable, |
|
|
|
|
hb_requires (hb_is_iterable (Iterable))> |
|
|
|
|
unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); } |
|
|
|
|
|
|
|
|
|
unsigned operator () (unsigned _) const { return _; } |
|
|
|
|
} |
|
|
|
|
HB_FUNCOBJ (length_f); |
|
|
|
|
|
|
|
|
|
/* CFF INDEX */ |
|
|
|
|
template <typename COUNT> |
|
|
|
|
struct CFFIndex |
|
|
|
|
{ |
|
|
|
|
unsigned int offset_array_size () const |
|
|
|
|
{ return offSize * (count + 1); } |
|
|
|
|
|
|
|
|
|
template <typename Iterable, |
|
|
|
|
hb_requires (hb_is_iterable (Iterable))> |
|
|
|
|
bool serialize (hb_serialize_context_t *c, |
|
|
|
|
const Iterable &iterable, |
|
|
|
|
const unsigned *p_data_size = nullptr, |
|
|
|
|
unsigned min_off_size = 0) |
|
|
|
|
{ |
|
|
|
|
TRACE_SERIALIZE (this); |
|
|
|
|
unsigned data_size; |
|
|
|
|
if (p_data_size) |
|
|
|
|
data_size = *p_data_size; |
|
|
|
|
else |
|
|
|
|
total_size (iterable, &data_size); |
|
|
|
|
|
|
|
|
|
auto it = hb_iter (iterable); |
|
|
|
|
if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false); |
|
|
|
|
unsigned char *ret = c->allocate_size<unsigned char> (data_size, false); |
|
|
|
|
if (unlikely (!ret)) return_trace (false); |
|
|
|
|
for (const auto &_ : +it) |
|
|
|
|
{ |
|
|
|
|
unsigned len = _.length; |
|
|
|
|
if (!len) |
|
|
|
|
continue; |
|
|
|
|
if (len <= 1) |
|
|
|
|
{ |
|
|
|
|
*ret++ = *_.arrayZ; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
hb_memcpy (ret, _.arrayZ, len); |
|
|
|
|
ret += len; |
|
|
|
|
} |
|
|
|
|
return_trace (true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename Iterator, |
|
|
|
|
hb_requires (hb_is_iterator (Iterator))> |
|
|
|
|
bool serialize_header (hb_serialize_context_t *c, |
|
|
|
|
Iterator it, |
|
|
|
|
unsigned data_size, |
|
|
|
|
unsigned min_off_size = 0) |
|
|
|
|
{ |
|
|
|
|
TRACE_SERIALIZE (this); |
|
|
|
|
|
|
|
|
|
unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8; |
|
|
|
|
off_size = hb_max(min_off_size, off_size); |
|
|
|
|
|
|
|
|
|
/* serialize CFFIndex header */ |
|
|
|
|
if (unlikely (!c->extend_min (this))) return_trace (false); |
|
|
|
|
this->count = hb_len (it); |
|
|
|
|
if (!this->count) return_trace (true); |
|
|
|
|
if (unlikely (!c->extend (this->offSize))) return_trace (false); |
|
|
|
|
this->offSize = off_size; |
|
|
|
|
if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1), false))) |
|
|
|
|
return_trace (false); |
|
|
|
|
|
|
|
|
|
/* serialize indices */ |
|
|
|
|
unsigned int offset = 1; |
|
|
|
|
if (HB_OPTIMIZE_SIZE_VAL) |
|
|
|
|
{ |
|
|
|
|
unsigned int i = 0; |
|
|
|
|
for (const auto &_ : +it) |
|
|
|
|
{ |
|
|
|
|
set_offset_at (i++, offset); |
|
|
|
|
offset += length_f (_); |
|
|
|
|
} |
|
|
|
|
set_offset_at (i, offset); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
switch (off_size) |
|
|
|
|
{ |
|
|
|
|
case 1: |
|
|
|
|
{ |
|
|
|
|
HBUINT8 *p = (HBUINT8 *) offsets; |
|
|
|
|
for (const auto &_ : +it) |
|
|
|
|
{ |
|
|
|
|
*p++ = offset; |
|
|
|
|
offset += length_f (_); |
|
|
|
|
} |
|
|
|
|
*p = offset; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
{ |
|
|
|
|
HBUINT16 *p = (HBUINT16 *) offsets; |
|
|
|
|
for (const auto &_ : +it) |
|
|
|
|
{ |
|
|
|
|
*p++ = offset; |
|
|
|
|
offset += length_f (_); |
|
|
|
|
} |
|
|
|
|
*p = offset; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case 3: |
|
|
|
|
{ |
|
|
|
|
HBUINT24 *p = (HBUINT24 *) offsets; |
|
|
|
|
for (const auto &_ : +it) |
|
|
|
|
{ |
|
|
|
|
*p++ = offset; |
|
|
|
|
offset += length_f (_); |
|
|
|
|
} |
|
|
|
|
*p = offset; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
{ |
|
|
|
|
HBUINT32 *p = (HBUINT32 *) offsets; |
|
|
|
|
for (const auto &_ : +it) |
|
|
|
|
{ |
|
|
|
|
*p++ = offset; |
|
|
|
|
offset += length_f (_); |
|
|
|
|
} |
|
|
|
|
*p = offset; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
assert (offset == data_size + 1); |
|
|
|
|
return_trace (true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename Iterable, |
|
|
|
|
hb_requires (hb_is_iterable (Iterable))> |
|
|
|
|
static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0) |
|
|
|
|
{ |
|
|
|
|
auto it = + hb_iter (iterable); |
|
|
|
|
if (!it) |
|
|
|
|
{ |
|
|
|
|
if (data_size) *data_size = 0; |
|
|
|
|
return min_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned total = 0; |
|
|
|
|
for (const auto &_ : +it) |
|
|
|
|
total += length_f (_); |
|
|
|
|
|
|
|
|
|
if (data_size) *data_size = total; |
|
|
|
|
|
|
|
|
|
unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; |
|
|
|
|
off_size = hb_max(min_off_size, off_size); |
|
|
|
|
|
|
|
|
|
return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void set_offset_at (unsigned int index, unsigned int offset) |
|
|
|
|
{ |
|
|
|
|
assert (index <= count); |
|
|
|
|
|
|
|
|
|
unsigned int size = offSize; |
|
|
|
|
const HBUINT8 *p = offsets; |
|
|
|
|
switch (size) |
|
|
|
|
{ |
|
|
|
|
case 1: ((HBUINT8 *) p)[index] = offset; break; |
|
|
|
|
case 2: ((HBUINT16 *) p)[index] = offset; break; |
|
|
|
|
case 3: ((HBUINT24 *) p)[index] = offset; break; |
|
|
|
|
case 4: ((HBUINT32 *) p)[index] = offset; break; |
|
|
|
|
default: return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
unsigned int offset_at (unsigned int index) const |
|
|
|
|
{ |
|
|
|
|
assert (index <= count); |
|
|
|
|
|
|
|
|
|
unsigned int size = offSize; |
|
|
|
|
const HBUINT8 *p = offsets; |
|
|
|
|
switch (size) |
|
|
|
|
{ |
|
|
|
|
case 1: return ((HBUINT8 *) p)[index]; |
|
|
|
|
case 2: return ((HBUINT16 *) p)[index]; |
|
|
|
|
case 3: return ((HBUINT24 *) p)[index]; |
|
|
|
|
case 4: return ((HBUINT32 *) p)[index]; |
|
|
|
|
default: return 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const unsigned char *data_base () const |
|
|
|
|
{ return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); } |
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
hb_ubytes_t operator [] (unsigned int index) const |
|
|
|
|
{ |
|
|
|
|
if (unlikely (index >= count)) return hb_ubytes_t (); |
|
|
|
|
_hb_compiler_memory_r_barrier (); |
|
|
|
|
unsigned offset0 = offset_at (index); |
|
|
|
|
unsigned offset1 = offset_at (index + 1); |
|
|
|
|
if (unlikely (offset1 < offset0 || offset1 > offset_at (count))) |
|
|
|
|
return hb_ubytes_t (); |
|
|
|
|
return hb_ubytes_t (data_base () + offset0, offset1 - offset0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
unsigned int get_size () const |
|
|
|
|
{ |
|
|
|
|
if (count) |
|
|
|
|
return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); |
|
|
|
|
return min_size; /* empty CFFIndex contains count only */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool sanitize (hb_sanitize_context_t *c) const |
|
|
|
|
{ |
|
|
|
|
TRACE_SANITIZE (this); |
|
|
|
|
return_trace (likely (c->check_struct (this) && |
|
|
|
|
hb_barrier () && |
|
|
|
|
(count == 0 || /* empty INDEX */ |
|
|
|
|
(count < count + 1u && |
|
|
|
|
hb_barrier () && |
|
|
|
|
c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 && |
|
|
|
|
c->check_array (offsets, offSize, count + 1u) && |
|
|
|
|
c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count)))))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
COUNT count; /* Number of object data. Note there are (count+1) offsets */ |
|
|
|
|
private: |
|
|
|
|
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ |
|
|
|
|
HBUINT8 offsets[HB_VAR_ARRAY]; |
|
|
|
|
/* The array of (count + 1) offsets into objects array (1-base). */ |
|
|
|
|
/* HBUINT8 data[HB_VAR_ARRAY]; Object data */ |
|
|
|
|
public: |
|
|
|
|
DEFINE_SIZE_MIN (COUNT::static_size); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/* Top Dict, Font Dict, Private Dict */ |
|
|
|
|
struct Dict : UnsizedByteStr |
|
|
|
|
{ |
|
|
|
|