subset FDSelect and FDArray
Added a set of sources hb-subset-cff-common-private.cc & .hh for FDSelect subseting code. Added FDSelect format 4 (CFF2 only) support. Shared its implementation with format 3 as a template.
This commit is contained in:
parent
cc3f4e00aa
commit
5561b81849
|
@ -209,6 +209,7 @@ HB_SUBSET_sources = \
|
||||||
hb-subset.cc \
|
hb-subset.cc \
|
||||||
hb-subset-glyf.cc \
|
hb-subset-glyf.cc \
|
||||||
hb-subset-cff2.cc \
|
hb-subset-cff2.cc \
|
||||||
|
hb-subset-cff-common-private.cc \
|
||||||
hb-subset-input.cc \
|
hb-subset-input.cc \
|
||||||
hb-subset-plan.cc \
|
hb-subset-plan.cc \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@ -217,6 +218,7 @@ HB_SUBSET_headers = \
|
||||||
hb-subset.h \
|
hb-subset.h \
|
||||||
hb-subset-glyf.hh \
|
hb-subset-glyf.hh \
|
||||||
hb-subset-cff2.hh \
|
hb-subset-cff2.hh \
|
||||||
|
hb-subset-cff-common-private.hh \
|
||||||
hb-subset-plan.hh \
|
hb-subset-plan.hh \
|
||||||
hb-subset-private.hh \
|
hb-subset-private.hh \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -522,33 +522,37 @@ struct FDArray : IndexOf<FontDict>
|
||||||
inline bool serialize (hb_serialize_context_t *c,
|
inline bool serialize (hb_serialize_context_t *c,
|
||||||
unsigned int offSize,
|
unsigned int offSize,
|
||||||
const hb_vector_t<DICTVAL> &fontDicts,
|
const hb_vector_t<DICTVAL> &fontDicts,
|
||||||
|
unsigned int fdCount,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &fdmap,
|
||||||
OP_SERIALIZER& opszr,
|
OP_SERIALIZER& opszr,
|
||||||
const hb_vector_t<offset_size_pair> &privatePairs)
|
const hb_vector_t<offset_size_pair> &privatePairs)
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||||
this->count.set (fontDicts.len);
|
this->count.set (fdCount);
|
||||||
this->offSize.set (offSize);
|
this->offSize.set (offSize);
|
||||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize * (fontDicts.len + 1))))
|
if (!unlikely (c->allocate_size<HBUINT8> (offSize * (fdCount + 1))))
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
|
||||||
/* serialize font dict offsets */
|
/* serialize font dict offsets */
|
||||||
unsigned int offset = 1;
|
unsigned int offset = 1;
|
||||||
unsigned int i;
|
unsigned int fid = 0;
|
||||||
for (i = 0; i < fontDicts.len; i++)
|
for (unsigned i = 0; i < fontDicts.len; i++)
|
||||||
{
|
if (!fdmap.len || fdmap[i] != HB_SET_VALUE_INVALID)
|
||||||
set_offset_at (i, offset);
|
{
|
||||||
offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
set_offset_at (fid++, offset);
|
||||||
}
|
offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
||||||
set_offset_at (i, offset);
|
}
|
||||||
|
set_offset_at (fid, offset);
|
||||||
|
|
||||||
/* serialize font dicts */
|
/* serialize font dicts */
|
||||||
for (unsigned int i = 0; i < fontDicts.len; i++)
|
for (unsigned int i = 0; i < fontDicts.len; i++)
|
||||||
{
|
if (fdmap[i] != HB_SET_VALUE_INVALID)
|
||||||
FontDict *dict = c->start_embed<FontDict> ();
|
{
|
||||||
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privatePairs[i])))
|
FontDict *dict = c->start_embed<FontDict> ();
|
||||||
return_trace (false);
|
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privatePairs[i])))
|
||||||
}
|
return_trace (false);
|
||||||
|
}
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,23 +560,37 @@ struct FDArray : IndexOf<FontDict>
|
||||||
template <typename OP_SERIALIZER, typename DICTVAL>
|
template <typename OP_SERIALIZER, typename DICTVAL>
|
||||||
inline static unsigned int calculate_serialized_size (unsigned int &offSize /* OUT */,
|
inline static unsigned int calculate_serialized_size (unsigned int &offSize /* OUT */,
|
||||||
const hb_vector_t<DICTVAL> &fontDicts,
|
const hb_vector_t<DICTVAL> &fontDicts,
|
||||||
|
unsigned int fdCount,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &fdmap,
|
||||||
OP_SERIALIZER& opszr)
|
OP_SERIALIZER& opszr)
|
||||||
{
|
{
|
||||||
unsigned int dictsSize = 0;
|
unsigned int dictsSize = 0;
|
||||||
for (unsigned int i = 0; i < fontDicts.len; i++)
|
for (unsigned int i = 0; i < fontDicts.len; i++)
|
||||||
dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
if (!fdmap.len || fdmap[i] != HB_SET_VALUE_INVALID)
|
||||||
|
dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
||||||
|
|
||||||
offSize = calcOffSize (dictsSize + 1);
|
offSize = calcOffSize (dictsSize + 1);
|
||||||
return Index::calculate_serialized_size (offSize, fontDicts.len, dictsSize);
|
return Index::calculate_serialized_size (offSize, fdCount, dictsSize);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FDSelect */
|
/* FDSelect */
|
||||||
struct FDSelect0 {
|
struct FDSelect0 {
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
return_trace (likely (c->check_struct (this) && fds[c->get_num_glyphs () - 1].sanitize (c)));
|
if (unlikely (!(c->check_struct (this))))
|
||||||
|
return_trace (false);
|
||||||
|
for (unsigned int i = 0; i < c->get_num_glyphs (); i++)
|
||||||
|
if (unlikely (!fds[i].sanitize (c)))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
|
||||||
|
{
|
||||||
|
return (hb_codepoint_t)fds[glyph];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline unsigned int get_size (unsigned int num_glyphs) const
|
inline unsigned int get_size (unsigned int num_glyphs) const
|
||||||
|
@ -583,44 +601,75 @@ struct FDSelect0 {
|
||||||
DEFINE_SIZE_MIN (1);
|
DEFINE_SIZE_MIN (1);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FDSelect3_Range {
|
template <typename GID_TYPE, typename FD_TYPE>
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
struct FDSelect3_4_Range {
|
||||||
|
inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
return_trace (likely (c->check_struct (this) && (first < c->get_num_glyphs ())));
|
return_trace (likely (c->check_struct (this) && (first < c->get_num_glyphs ()) && (fd < fdcount)));
|
||||||
}
|
}
|
||||||
|
|
||||||
HBUINT16 first;
|
GID_TYPE first;
|
||||||
HBUINT8 fd;
|
FD_TYPE fd;
|
||||||
|
|
||||||
DEFINE_SIZE_STATIC (3);
|
DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FDSelect3 {
|
template <typename GID_TYPE, typename FD_TYPE>
|
||||||
|
struct FDSelect3_4 {
|
||||||
inline unsigned int get_size (void) const
|
inline unsigned int get_size (void) const
|
||||||
{ return HBUINT16::static_size * 2 + FDSelect3_Range::static_size * nRanges; }
|
{ return GID_TYPE::static_size * 2 + FDSelect3_4_Range<GID_TYPE, FD_TYPE>::static_size * nRanges; }
|
||||||
|
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
return_trace (likely (c->check_struct (this) && (nRanges > 0) &&
|
if (unlikely (!(c->check_struct (this) && (nRanges > 0) && (ranges[0].first == 0))))
|
||||||
(ranges[nRanges - 1].sanitize (c))));
|
return_trace (false);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < nRanges; i++)
|
||||||
|
{
|
||||||
|
if (unlikely (!ranges[i].sanitize (c, fdcount)))
|
||||||
|
return_trace (false);
|
||||||
|
if ((0 < i) && unlikely (ranges[i - 1].first >= ranges[i].first))
|
||||||
|
return_trace (false);
|
||||||
|
}
|
||||||
|
if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
HBUINT16 nRanges;
|
inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
|
||||||
FDSelect3_Range ranges[VAR];
|
{
|
||||||
/* HBUINT16 sentinel */
|
for (unsigned int i = 0; i < nRanges; i++)
|
||||||
|
if (glyph < ranges[i + 1].first)
|
||||||
|
return (hb_codepoint_t)ranges[i].fd;
|
||||||
|
|
||||||
DEFINE_SIZE_MIN (5);
|
assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline GID_TYPE &sentinel (void) { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
|
||||||
|
inline const GID_TYPE &sentinel (void) const { return StructAfter<GID_TYPE> (ranges[nRanges - 1]); }
|
||||||
|
|
||||||
|
GID_TYPE nRanges;
|
||||||
|
FDSelect3_4_Range<GID_TYPE, FD_TYPE> ranges[VAR];
|
||||||
|
/* GID_TYPE sentinel */
|
||||||
|
|
||||||
|
DEFINE_SIZE_ARRAY (GID_TYPE::static_size * 2, ranges);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
|
||||||
|
typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
|
||||||
|
|
||||||
struct FDSelect {
|
struct FDSelect {
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
|
||||||
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
|
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
|
||||||
(format == 0)? u.format0.sanitize (c): u.format3.sanitize (c)));
|
(format == 0)?
|
||||||
|
u.format0.sanitize (c, fdcount):
|
||||||
|
u.format3.sanitize (c, fdcount)));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
|
inline bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
|
||||||
|
@ -641,11 +690,19 @@ struct FDSelect {
|
||||||
unsigned int size = format.static_size;
|
unsigned int size = format.static_size;
|
||||||
if (format == 0)
|
if (format == 0)
|
||||||
size += u.format0.get_size (num_glyphs);
|
size += u.format0.get_size (num_glyphs);
|
||||||
else if (likely (format == 3))
|
else
|
||||||
size += u.format3.get_size ();
|
size += u.format3.get_size ();
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
|
||||||
|
{
|
||||||
|
if (format == 0)
|
||||||
|
return u.format0.get_fd (glyph);
|
||||||
|
else
|
||||||
|
return u.format3.get_fd (glyph);
|
||||||
|
}
|
||||||
|
|
||||||
HBUINT8 format;
|
HBUINT8 format;
|
||||||
union {
|
union {
|
||||||
FDSelect0 format0;
|
FDSelect0 format0;
|
||||||
|
@ -872,6 +929,7 @@ struct SubTableOffsets {
|
||||||
unsigned int topDictSize;
|
unsigned int topDictSize;
|
||||||
unsigned int varStoreOffset;
|
unsigned int varStoreOffset;
|
||||||
unsigned int FDSelectOffset;
|
unsigned int FDSelectOffset;
|
||||||
|
unsigned int FDSelectSize;
|
||||||
unsigned int FDArrayOffset;
|
unsigned int FDArrayOffset;
|
||||||
unsigned int FDArrayOffSize;
|
unsigned int FDArrayOffSize;
|
||||||
unsigned int charStringsOffset;
|
unsigned int charStringsOffset;
|
||||||
|
|
|
@ -38,6 +38,68 @@ namespace CFF {
|
||||||
*/
|
*/
|
||||||
#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
|
#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
|
||||||
|
|
||||||
|
typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
|
||||||
|
typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
|
||||||
|
|
||||||
|
struct CFF2FDSelect
|
||||||
|
{
|
||||||
|
inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||||
|
{
|
||||||
|
TRACE_SANITIZE (this);
|
||||||
|
|
||||||
|
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) &&
|
||||||
|
(format == 0)?
|
||||||
|
u.format0.sanitize (c, fdcount):
|
||||||
|
((format == 3)?
|
||||||
|
u.format3.sanitize (c, fdcount):
|
||||||
|
u.format4.sanitize (c, fdcount))));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
unsigned int size = src.get_size (num_glyphs);
|
||||||
|
CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
|
||||||
|
if (unlikely (dest == nullptr)) return_trace (false);
|
||||||
|
memcpy (dest, &src, size);
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int calculate_serialized_size (unsigned int num_glyphs) const
|
||||||
|
{ return get_size (num_glyphs); }
|
||||||
|
|
||||||
|
inline unsigned int get_size (unsigned int num_glyphs) const
|
||||||
|
{
|
||||||
|
unsigned int size = format.static_size;
|
||||||
|
if (format == 0)
|
||||||
|
size += u.format0.get_size (num_glyphs);
|
||||||
|
else if (format == 3)
|
||||||
|
size += u.format3.get_size ();
|
||||||
|
else
|
||||||
|
size += u.format4.get_size ();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
|
||||||
|
{
|
||||||
|
if (format == 0)
|
||||||
|
return u.format0.get_fd (glyph);
|
||||||
|
else if (format == 3)
|
||||||
|
return u.format3.get_fd (glyph);
|
||||||
|
else
|
||||||
|
return u.format4.get_fd (glyph);
|
||||||
|
}
|
||||||
|
|
||||||
|
HBUINT8 format;
|
||||||
|
union {
|
||||||
|
FDSelect0 format0;
|
||||||
|
FDSelect3 format3;
|
||||||
|
FDSelect4 format4;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
DEFINE_SIZE_MIN (2);
|
||||||
|
};
|
||||||
|
|
||||||
struct CFF2VariationStore
|
struct CFF2VariationStore
|
||||||
{
|
{
|
||||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||||
|
@ -100,7 +162,7 @@ struct CFF2TopDictValues : DictValues<OpStr>
|
||||||
LOffsetTo<CharStrings> charStringsOffset;
|
LOffsetTo<CharStrings> charStringsOffset;
|
||||||
LOffsetTo<CFF2VariationStore> vstoreOffset;
|
LOffsetTo<CFF2VariationStore> vstoreOffset;
|
||||||
LOffsetTo<FDArray> FDArrayOffset;
|
LOffsetTo<FDArray> FDArrayOffset;
|
||||||
LOffsetTo<FDSelect> FDSelectOffset;
|
LOffsetTo<CFF2FDSelect> FDSelectOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CFF2TopDictOpSet
|
struct CFF2TopDictOpSet
|
||||||
|
@ -414,7 +476,7 @@ struct cff2
|
||||||
if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
|
if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
|
||||||
((charStrings == &Null(CharStrings)) || unlikely (!charStrings->sanitize (&sc))) ||
|
((charStrings == &Null(CharStrings)) || unlikely (!charStrings->sanitize (&sc))) ||
|
||||||
((fdArray == &Null(FDArray)) || unlikely (!fdArray->sanitize (&sc))) ||
|
((fdArray == &Null(FDArray)) || unlikely (!fdArray->sanitize (&sc))) ||
|
||||||
((fdSelect != &Null(FDSelect)) && unlikely (!fdSelect->sanitize (&sc))))
|
((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))
|
||||||
{
|
{
|
||||||
fini ();
|
fini ();
|
||||||
return;
|
return;
|
||||||
|
@ -453,7 +515,8 @@ struct cff2
|
||||||
}
|
}
|
||||||
|
|
||||||
privateDicts[i].localSubrs = &privateDicts[i].subrsOffset (privDictStr.str);
|
privateDicts[i].localSubrs = &privateDicts[i].subrsOffset (privDictStr.str);
|
||||||
if (unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
|
if (privateDicts[i].localSubrs != &Null(Subrs) &&
|
||||||
|
unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
|
||||||
{
|
{
|
||||||
fini ();
|
fini ();
|
||||||
return;
|
return;
|
||||||
|
@ -492,7 +555,7 @@ struct cff2
|
||||||
const CFF2VariationStore *varStore;
|
const CFF2VariationStore *varStore;
|
||||||
const CharStrings *charStrings;
|
const CharStrings *charStrings;
|
||||||
const FDArray *fdArray;
|
const FDArray *fdArray;
|
||||||
const FDSelect *fdSelect;
|
const CFF2FDSelect *fdSelect;
|
||||||
|
|
||||||
hb_vector_t<CFF2FontDictValues> fontDicts;
|
hb_vector_t<CFF2FontDictValues> fontDicts;
|
||||||
hb_vector_t<PrivDictVal> privateDicts;
|
hb_vector_t<PrivDictVal> privateDicts;
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2018 Adobe Systems Incorporated.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Adobe Author(s): Michiharu Ariza
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hb-ot-cff-common-private.hh"
|
||||||
|
#include "hb-ot-cff2-table.hh"
|
||||||
|
#include "hb-subset-cff-common-private.hh"
|
||||||
|
|
||||||
|
using namespace CFF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_plan_subset_cff_fdselect
|
||||||
|
* Determine an optimal FDSelect format according to a provided plan.
|
||||||
|
*
|
||||||
|
* Return value: FDSelect format, size, and ranges for the most compact subset FDSelect
|
||||||
|
* along with a font index remapping table
|
||||||
|
**/
|
||||||
|
|
||||||
|
bool
|
||||||
|
hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||||
|
unsigned int fdCount,
|
||||||
|
const CFF2FDSelect &src, /* IN */
|
||||||
|
unsigned int &subset_fd_count /* OUT */,
|
||||||
|
unsigned int &subst_fdselect_size /* OUT */,
|
||||||
|
unsigned int &subst_fdselect_format /* OUT */,
|
||||||
|
hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */,
|
||||||
|
hb_vector_t<hb_codepoint_t> &fdmap /* OUT */)
|
||||||
|
{
|
||||||
|
subset_fd_count = 0;
|
||||||
|
subst_fdselect_size = 0;
|
||||||
|
subst_fdselect_format = 0;
|
||||||
|
unsigned int num_ranges = 0;
|
||||||
|
|
||||||
|
unsigned int subset_num_glyphs = glyphs.len;
|
||||||
|
if (subset_num_glyphs == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
{
|
||||||
|
/* use hb_set to determine the subset of font dicts */
|
||||||
|
hb_set_t *set = hb_set_create ();
|
||||||
|
if (set == &Null (hb_set_t))
|
||||||
|
return false;
|
||||||
|
hb_codepoint_t prev_fd = HB_SET_VALUE_INVALID;
|
||||||
|
for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
|
||||||
|
{
|
||||||
|
hb_codepoint_t fd = src.get_fd (glyphs[i]);
|
||||||
|
set->add (fd);
|
||||||
|
|
||||||
|
if (fd != prev_fd)
|
||||||
|
{
|
||||||
|
num_ranges++;
|
||||||
|
prev_fd = fd;
|
||||||
|
subst_first_glyphs.push (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set->get_population () == fdCount)
|
||||||
|
{
|
||||||
|
/* all font dicts belong to the subset. no need to subset FDSelect & FDArray */
|
||||||
|
hb_set_destroy (set);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a fdmap */
|
||||||
|
fdmap.resize (fdCount);
|
||||||
|
for (unsigned int i = 0; i < fdmap.len; i++)
|
||||||
|
fdmap[i] = HB_SET_VALUE_INVALID;
|
||||||
|
hb_codepoint_t fd = HB_SET_VALUE_INVALID;
|
||||||
|
while (set->next (&fd))
|
||||||
|
fdmap[fd] = subset_fd_count++;
|
||||||
|
assert (subset_fd_count == set->get_population ());
|
||||||
|
hb_set_destroy (set);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* determine which FDSelect format is most compact */
|
||||||
|
if (subset_fd_count > 0xFF)
|
||||||
|
{
|
||||||
|
assert (src.format == 4);
|
||||||
|
subst_fdselect_format = 4;
|
||||||
|
subst_fdselect_size = FDSelect4::min_size + FDSelect4_Range::static_size * num_ranges;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int format0_size = FDSelect0::min_size + HBUINT8::static_size * subset_num_glyphs;
|
||||||
|
unsigned int format3_size = FDSelect3::min_size + FDSelect3_Range::static_size * num_ranges;
|
||||||
|
|
||||||
|
if (format0_size <= format3_size)
|
||||||
|
{
|
||||||
|
// subst_fdselect_format = 0;
|
||||||
|
subst_fdselect_size = format0_size;
|
||||||
|
subst_first_glyphs.fini ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subst_fdselect_format = 3;
|
||||||
|
subst_fdselect_size = format3_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FDSELECT3_4>
|
||||||
|
static inline bool
|
||||||
|
serialize_fdselect_3_4 (hb_serialize_context_t *c,
|
||||||
|
unsigned int num_glyphs,
|
||||||
|
const CFF2FDSelect &src,
|
||||||
|
unsigned int size,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &first_glyphs,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &fdmap)
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
|
||||||
|
if (unlikely (p == nullptr)) return_trace (false);
|
||||||
|
p->nRanges.set (first_glyphs.len);
|
||||||
|
for (unsigned int i = 0; i < first_glyphs.len; i++)
|
||||||
|
{
|
||||||
|
hb_codepoint_t glyph = first_glyphs[i];
|
||||||
|
p->ranges[i].first.set (glyph);
|
||||||
|
p->ranges[i].fd.set (fdmap[src.get_fd (glyph)]);
|
||||||
|
}
|
||||||
|
p->sentinel().set (num_glyphs);
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_serialize_cff_fdselect
|
||||||
|
* Serialize a subset FDSelect format planned above.
|
||||||
|
**/
|
||||||
|
bool
|
||||||
|
hb_serialize_cff_fdselect (hb_serialize_context_t *c,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||||
|
const CFF2FDSelect &src,
|
||||||
|
unsigned int fd_count,
|
||||||
|
unsigned int fdselect_format,
|
||||||
|
unsigned int size,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &first_glyphs,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &fdmap)
|
||||||
|
{
|
||||||
|
TRACE_SERIALIZE (this);
|
||||||
|
FDSelect *p = c->allocate_min<FDSelect> ();
|
||||||
|
if (unlikely (p == nullptr)) return_trace (false);
|
||||||
|
p->format.set (fdselect_format);
|
||||||
|
size -= FDSelect::min_size;
|
||||||
|
|
||||||
|
switch (fdselect_format)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
FDSelect0 *p = c->allocate_size<FDSelect0> (size);
|
||||||
|
if (unlikely (p == nullptr)) return_trace (false);
|
||||||
|
for (unsigned int i = 0; i < glyphs.len; i++)
|
||||||
|
p->fds[i].set (fdmap[src.get_fd (glyphs[i])]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
return serialize_fdselect_3_4<FDSelect3> (c,
|
||||||
|
glyphs.len,
|
||||||
|
src,
|
||||||
|
size,
|
||||||
|
first_glyphs,
|
||||||
|
fdmap);
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
return serialize_fdselect_3_4<FDSelect4> (c,
|
||||||
|
glyphs.len,
|
||||||
|
src,
|
||||||
|
size,
|
||||||
|
first_glyphs,
|
||||||
|
fdmap);
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return_trace (true);
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2018 Adobe Systems Incorporated.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Adobe Author(s): Michiharu Ariza
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_SUBSET_CFF_COMMON_PRIVATE_HH
|
||||||
|
#define HB_SUBSET_CFF_COMMON_PRIVATE_HH
|
||||||
|
|
||||||
|
#include "hb-private.hh"
|
||||||
|
|
||||||
|
#include "hb-subset-plan.hh"
|
||||||
|
|
||||||
|
HB_INTERNAL bool
|
||||||
|
hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||||
|
unsigned int fdCount,
|
||||||
|
const CFF::CFF2FDSelect &src, /* IN */
|
||||||
|
unsigned int &subset_fd_count /* OUT */,
|
||||||
|
unsigned int &subst_fdselect_size /* OUT */,
|
||||||
|
unsigned int &subst_fdselect_format /* OUT */,
|
||||||
|
hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */,
|
||||||
|
hb_vector_t<hb_codepoint_t> &fdmap /* OUT */);
|
||||||
|
|
||||||
|
HB_INTERNAL bool
|
||||||
|
hb_serialize_cff_fdselect (hb_serialize_context_t *c,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||||
|
const CFF::CFF2FDSelect &src,
|
||||||
|
unsigned int fd_count,
|
||||||
|
unsigned int fdselect_format,
|
||||||
|
unsigned int size,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &first_glyphs,
|
||||||
|
const hb_vector_t<hb_codepoint_t> &fdmap);
|
||||||
|
|
||||||
|
#endif /* HB_SUBSET_CFF_COMMON_PRIVATE_HH */
|
|
@ -29,6 +29,7 @@
|
||||||
#include "hb-set.h"
|
#include "hb-set.h"
|
||||||
#include "hb-subset-cff2.hh"
|
#include "hb-subset-cff2.hh"
|
||||||
#include "hb-subset-plan.hh"
|
#include "hb-subset-plan.hh"
|
||||||
|
#include "hb-subset-cff-common-private.hh"
|
||||||
|
|
||||||
using namespace CFF;
|
using namespace CFF;
|
||||||
|
|
||||||
|
@ -144,14 +145,19 @@ struct CFF2PrivateDict_OpSerializer : OpSerializer
|
||||||
|
|
||||||
struct subset_plan {
|
struct subset_plan {
|
||||||
inline subset_plan (void)
|
inline subset_plan (void)
|
||||||
: final_size (0)
|
: final_size (0),
|
||||||
|
subst_fdcount(1)
|
||||||
{
|
{
|
||||||
|
subst_fdselect_first_glyphs.init ();
|
||||||
|
fdmap.init ();
|
||||||
subset_charstrings.init ();
|
subset_charstrings.init ();
|
||||||
private_off_and_size_pairs.init ();
|
private_off_and_size_pairs.init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ~subset_plan (void)
|
inline ~subset_plan (void)
|
||||||
{
|
{
|
||||||
|
subst_fdselect_first_glyphs.fini ();
|
||||||
|
fdmap.fini ();
|
||||||
subset_charstrings.fini ();
|
subset_charstrings.fini ();
|
||||||
private_off_and_size_pairs.fini ();
|
private_off_and_size_pairs.fini ();
|
||||||
}
|
}
|
||||||
|
@ -160,6 +166,7 @@ struct subset_plan {
|
||||||
hb_subset_plan_t *plan)
|
hb_subset_plan_t *plan)
|
||||||
{
|
{
|
||||||
final_size = 0;
|
final_size = 0;
|
||||||
|
orig_fdcount = acc.fdArray->count;
|
||||||
|
|
||||||
/* CFF2 header */
|
/* CFF2 header */
|
||||||
final_size += OT::cff2::static_size;
|
final_size += OT::cff2::static_size;
|
||||||
|
@ -182,17 +189,29 @@ struct subset_plan {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FDSelect */
|
/* FDSelect */
|
||||||
if (acc.fdSelect != &Null(FDSelect))
|
if (acc.fdSelect != &Null(CFF2FDSelect))
|
||||||
{
|
{
|
||||||
offsets.FDSelectOffset = final_size;
|
offsets.FDSelectOffset = final_size;
|
||||||
final_size += acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
|
if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
|
||||||
|
orig_fdcount,
|
||||||
|
*acc.fdSelect,
|
||||||
|
subst_fdcount,
|
||||||
|
offsets.FDSelectSize,
|
||||||
|
subst_fdselect_format,
|
||||||
|
subst_fdselect_first_glyphs,
|
||||||
|
fdmap)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!is_fds_subsetted ())
|
||||||
|
offsets.FDSelectSize = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
|
||||||
|
final_size += offsets.FDSelectSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FDArray (FDIndex) */
|
/* FDArray (FDIndex) */
|
||||||
{
|
{
|
||||||
offsets.FDArrayOffset = final_size;
|
offsets.FDArrayOffset = final_size;
|
||||||
CFF2FontDict_OpSerializer fontSzr;
|
CFF2FontDict_OpSerializer fontSzr;
|
||||||
final_size += FDArray::calculate_serialized_size(offsets.FDArrayOffSize/*OUT*/, acc.fontDicts, fontSzr);
|
final_size += FDArray::calculate_serialized_size(offsets.FDArrayOffSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CharStrings */
|
/* CharStrings */
|
||||||
|
@ -211,7 +230,7 @@ struct subset_plan {
|
||||||
|
|
||||||
/* private dicts & local subrs */
|
/* private dicts & local subrs */
|
||||||
offsets.privateDictsOffset = final_size;
|
offsets.privateDictsOffset = final_size;
|
||||||
for (unsigned int i = 0; i < acc.fdArray->count; i++)
|
for (unsigned int i = 0; i < orig_fdcount; i++)
|
||||||
{
|
{
|
||||||
CFF2PrivateDict_OpSerializer privSzr;
|
CFF2PrivateDict_OpSerializer privSzr;
|
||||||
unsigned int private_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
unsigned int private_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
||||||
|
@ -228,12 +247,23 @@ struct subset_plan {
|
||||||
unsigned int final_size;
|
unsigned int final_size;
|
||||||
SubTableOffsets offsets;
|
SubTableOffsets offsets;
|
||||||
|
|
||||||
|
unsigned int orig_fdcount;
|
||||||
|
unsigned int subst_fdcount;
|
||||||
|
inline bool is_fds_subsetted (void) const { return subst_fdcount < orig_fdcount; }
|
||||||
|
unsigned int subst_fdselect_format;
|
||||||
|
hb_vector_t<hb_codepoint_t> subst_fdselect_first_glyphs;
|
||||||
|
|
||||||
|
/* font dict index remap table from fullset FDArray to subset FDArray.
|
||||||
|
* set to HB_SET_VALUE_INVALID if excluded from subset */
|
||||||
|
hb_vector_t<hb_codepoint_t> fdmap;
|
||||||
|
|
||||||
hb_vector_t<ByteStr> subset_charstrings;
|
hb_vector_t<ByteStr> subset_charstrings;
|
||||||
hb_vector_t<offset_size_pair> private_off_and_size_pairs;
|
hb_vector_t<offset_size_pair> private_off_and_size_pairs;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool _write_cff2 (const subset_plan &plan,
|
static inline bool _write_cff2 (const subset_plan &plan,
|
||||||
const OT::cff2::accelerator_subset_t &acc,
|
const OT::cff2::accelerator_subset_t &acc,
|
||||||
|
const hb_vector_t<hb_codepoint_t>& glyphs,
|
||||||
unsigned int dest_sz,
|
unsigned int dest_sz,
|
||||||
void *dest)
|
void *dest)
|
||||||
{
|
{
|
||||||
|
@ -286,14 +316,29 @@ static inline bool _write_cff2 (const subset_plan &plan,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FDSelect */
|
/* FDSelect */
|
||||||
if (acc.fdSelect != &Null(FDSelect))
|
if (acc.fdSelect != &Null(CFF2FDSelect))
|
||||||
{
|
{
|
||||||
assert (plan.offsets.FDSelectOffset == c.head - c.start);
|
assert (plan.offsets.FDSelectOffset == c.head - c.start);
|
||||||
FDSelect *dest = c.start_embed<FDSelect> ();
|
|
||||||
if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
|
if (plan.is_fds_subsetted ())
|
||||||
{
|
{
|
||||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDSelect");
|
if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *acc.fdSelect, acc.fdArray->count,
|
||||||
return false;
|
plan.subst_fdselect_format, plan.offsets.FDSelectSize,
|
||||||
|
plan.subst_fdselect_first_glyphs,
|
||||||
|
plan.fdmap)))
|
||||||
|
{
|
||||||
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CFF2FDSelect *dest = c.start_embed<CFF2FDSelect> ();
|
||||||
|
if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
|
||||||
|
{
|
||||||
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDSelect");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +348,9 @@ static inline bool _write_cff2 (const subset_plan &plan,
|
||||||
FDArray *fda = c.start_embed<FDArray> ();
|
FDArray *fda = c.start_embed<FDArray> ();
|
||||||
if (unlikely (fda == nullptr)) return false;
|
if (unlikely (fda == nullptr)) return false;
|
||||||
CFF2FontDict_OpSerializer fontSzr;
|
CFF2FontDict_OpSerializer fontSzr;
|
||||||
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayOffSize, acc.fontDicts, fontSzr, plan.private_off_and_size_pairs)))
|
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayOffSize,
|
||||||
|
acc.fontDicts, plan.subst_fdcount, plan.fdmap,
|
||||||
|
fontSzr, plan.private_off_and_size_pairs)))
|
||||||
{
|
{
|
||||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");
|
||||||
return false;
|
return false;
|
||||||
|
@ -373,7 +420,7 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
|
||||||
unsigned int cff2_prime_size = cff2_subset_plan.get_final_size ();
|
unsigned int cff2_prime_size = cff2_subset_plan.get_final_size ();
|
||||||
char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
|
char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
|
||||||
|
|
||||||
if (unlikely (!_write_cff2 (cff2_subset_plan, acc,
|
if (unlikely (!_write_cff2 (cff2_subset_plan, acc, plan->glyphs,
|
||||||
cff2_prime_size, cff2_prime_data))) {
|
cff2_prime_size, cff2_prime_data))) {
|
||||||
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
|
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
|
||||||
free (cff2_prime_data);
|
free (cff2_prime_data);
|
||||||
|
|
Loading…
Reference in New Issue