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.
hb-subset.cc \
hb-subset-glyf.cc \
hb-subset-cff2.cc \
+ hb-subset-cff-common-private.cc \
hb-subset-input.cc \
hb-subset-plan.cc \
$(NULL)
hb-subset.h \
hb-subset-glyf.hh \
hb-subset-cff2.hh \
+ hb-subset-cff-common-private.hh \
hb-subset-plan.hh \
hb-subset-private.hh \
$(NULL)
inline bool serialize (hb_serialize_context_t *c,
unsigned int offSize,
const hb_vector_t<DICTVAL> &fontDicts,
+ unsigned int fdCount,
+ const hb_vector_t<hb_codepoint_t> &fdmap,
OP_SERIALIZER& opszr,
const hb_vector_t<offset_size_pair> &privatePairs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
- this->count.set (fontDicts.len);
+ this->count.set (fdCount);
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);
/* serialize font dict offsets */
unsigned int offset = 1;
- unsigned int i;
- for (i = 0; i < fontDicts.len; i++)
- {
- set_offset_at (i, offset);
- offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
- }
- set_offset_at (i, offset);
+ unsigned int fid = 0;
+ for (unsigned i = 0; i < fontDicts.len; i++)
+ if (!fdmap.len || fdmap[i] != HB_SET_VALUE_INVALID)
+ {
+ set_offset_at (fid++, offset);
+ offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
+ }
+ set_offset_at (fid, offset);
/* serialize font dicts */
for (unsigned int i = 0; i < fontDicts.len; i++)
- {
- FontDict *dict = c->start_embed<FontDict> ();
- if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privatePairs[i])))
- return_trace (false);
- }
+ if (fdmap[i] != HB_SET_VALUE_INVALID)
+ {
+ FontDict *dict = c->start_embed<FontDict> ();
+ if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privatePairs[i])))
+ return_trace (false);
+ }
return_trace (true);
}
template <typename OP_SERIALIZER, typename DICTVAL>
inline static unsigned int calculate_serialized_size (unsigned int &offSize /* OUT */,
const hb_vector_t<DICTVAL> &fontDicts,
+ unsigned int fdCount,
+ const hb_vector_t<hb_codepoint_t> &fdmap,
OP_SERIALIZER& opszr)
{
unsigned int dictsSize = 0;
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);
- return Index::calculate_serialized_size (offSize, fontDicts.len, dictsSize);
+ return Index::calculate_serialized_size (offSize, fdCount, dictsSize);
}
};
/* FDSelect */
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);
- 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
DEFINE_SIZE_MIN (1);
};
-struct FDSelect3_Range {
- inline bool sanitize (hb_sanitize_context_t *c) const
+template <typename GID_TYPE, typename FD_TYPE>
+struct FDSelect3_4_Range {
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
{
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;
- HBUINT8 fd;
+ GID_TYPE first;
+ 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
- { 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);
- return_trace (likely (c->check_struct (this) && (nRanges > 0) &&
- (ranges[nRanges - 1].sanitize (c))));
+ if (unlikely (!(c->check_struct (this) && (nRanges > 0) && (ranges[0].first == 0))))
+ 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;
- FDSelect3_Range ranges[VAR];
- /* HBUINT16 sentinel */
+ inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ {
+ for (unsigned int i = 0; i < nRanges; i++)
+ if (glyph < ranges[i + 1].first)
+ return (hb_codepoint_t)ranges[i].fd;
+
+ assert (false);
+ }
- DEFINE_SIZE_MIN (5);
+ 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 {
- inline bool sanitize (hb_sanitize_context_t *c) const
+ 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 == 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)
unsigned int size = format.static_size;
if (format == 0)
size += u.format0.get_size (num_glyphs);
- else if (likely (format == 3))
+ else
size += u.format3.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
+ return u.format3.get_fd (glyph);
+ }
+
HBUINT8 format;
union {
FDSelect0 format0;
unsigned int topDictSize;
unsigned int varStoreOffset;
unsigned int FDSelectOffset;
+ unsigned int FDSelectSize;
unsigned int FDArrayOffset;
unsigned int FDArrayOffSize;
unsigned int charStringsOffset;
*/
#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
{
inline bool sanitize (hb_sanitize_context_t *c) const
LOffsetTo<CharStrings> charStringsOffset;
LOffsetTo<CFF2VariationStore> vstoreOffset;
LOffsetTo<FDArray> FDArrayOffset;
- LOffsetTo<FDSelect> FDSelectOffset;
+ LOffsetTo<CFF2FDSelect> FDSelectOffset;
};
struct CFF2TopDictOpSet
if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
((charStrings == &Null(CharStrings)) || unlikely (!charStrings->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 ();
return;
}
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 ();
return;
const CFF2VariationStore *varStore;
const CharStrings *charStrings;
const FDArray *fdArray;
- const FDSelect *fdSelect;
+ const CFF2FDSelect *fdSelect;
hb_vector_t<CFF2FontDictValues> fontDicts;
hb_vector_t<PrivDictVal> privateDicts;
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
#include "hb-set.h"
#include "hb-subset-cff2.hh"
#include "hb-subset-plan.hh"
+#include "hb-subset-cff-common-private.hh"
using namespace CFF;
struct subset_plan {
inline subset_plan (void)
- : final_size (0)
+ : final_size (0),
+ subst_fdcount(1)
{
+ subst_fdselect_first_glyphs.init ();
+ fdmap.init ();
subset_charstrings.init ();
private_off_and_size_pairs.init ();
}
inline ~subset_plan (void)
{
+ subst_fdselect_first_glyphs.fini ();
+ fdmap.fini ();
subset_charstrings.fini ();
private_off_and_size_pairs.fini ();
}
hb_subset_plan_t *plan)
{
final_size = 0;
+ orig_fdcount = acc.fdArray->count;
/* CFF2 header */
final_size += OT::cff2::static_size;
}
/* FDSelect */
- if (acc.fdSelect != &Null(FDSelect))
+ if (acc.fdSelect != &Null(CFF2FDSelect))
{
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) */
{
offsets.FDArrayOffset = final_size;
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 */
/* private dicts & local subrs */
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;
unsigned int private_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
unsigned int final_size;
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<offset_size_pair> private_off_and_size_pairs;
};
static inline bool _write_cff2 (const subset_plan &plan,
const OT::cff2::accelerator_subset_t &acc,
+ const hb_vector_t<hb_codepoint_t>& glyphs,
unsigned int dest_sz,
void *dest)
{
}
/* FDSelect */
- if (acc.fdSelect != &Null(FDSelect))
+ if (acc.fdSelect != &Null(CFF2FDSelect))
{
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");
- return false;
+ if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *acc.fdSelect, acc.fdArray->count,
+ 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;
+ }
}
}
FDArray *fda = c.start_embed<FDArray> ();
if (unlikely (fda == nullptr)) return false;
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");
return false;
unsigned int cff2_prime_size = cff2_subset_plan.get_final_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))) {
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
free (cff2_prime_data);