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:
Michiharu Ariza 2018-08-06 10:04:53 -07:00
parent cc3f4e00aa
commit 5561b81849
6 changed files with 476 additions and 52 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);