diff options
Diffstat (limited to 'gfx/harfbuzz/src/hb-subset-cff-common.cc')
-rw-r--r-- | gfx/harfbuzz/src/hb-subset-cff-common.cc | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/gfx/harfbuzz/src/hb-subset-cff-common.cc b/gfx/harfbuzz/src/hb-subset-cff-common.cc new file mode 100644 index 0000000000..5e4ea5fe7c --- /dev/null +++ b/gfx/harfbuzz/src/hb-subset-cff-common.cc @@ -0,0 +1,231 @@ +/* + * Copyright © 2018 Adobe 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb.hh" + +#ifndef HB_NO_SUBSET_CFF + +#include "hb-ot-cff-common.hh" +#include "hb-ot-cff2-table.hh" +#include "hb-subset-cff-common.hh" + +/* Disable FDSelect format 0 for compatibility with fonttools which doesn't seem choose it. + * Rarely any/much smaller than format 3 anyway. */ +#define CFF_SERIALIZE_FDSELECT_0 0 + +using namespace CFF; + + +/* 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_subset_plan_t *plan, + unsigned int fdCount, + const FDSelect &src, /* IN */ + unsigned int &subset_fd_count /* OUT */, + unsigned int &subset_fdselect_size /* OUT */, + unsigned int &subset_fdselect_format /* OUT */, + hb_vector_t<code_pair_t> &fdselect_ranges /* OUT */, + hb_inc_bimap_t &fdmap /* OUT */) +{ + subset_fd_count = 0; + subset_fdselect_size = 0; + subset_fdselect_format = 0; + unsigned int num_ranges = 0; + + unsigned int subset_num_glyphs = plan->num_output_glyphs (); + if (subset_num_glyphs == 0) + return true; + + { + /* use hb_set to determine the subset of font dicts */ + hb_set_t set; + hb_codepoint_t prev_fd = CFF_UNDEF_CODE; + hb_pair_t<unsigned, hb_codepoint_t> last_range {0, 0}; + auto it = hb_iter (plan->new_to_old_gid_list); + auto _ = *it; + for (hb_codepoint_t gid = 0; gid < subset_num_glyphs; gid++) + { + hb_codepoint_t old_glyph; + if (gid == _.first) + { + old_glyph = _.second; + _ = *++it; + } + else + { + /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */ + old_glyph = gid; + } + if (old_glyph >= last_range.second) + last_range = src.get_fd_range (old_glyph); + unsigned fd = last_range.first; + + if (fd != prev_fd) + { + set.add (fd); + num_ranges++; + prev_fd = fd; + fdselect_ranges.push (code_pair_t { fd, gid }); + + if (gid == old_glyph) + gid = hb_min (_.first - 1, last_range.second - 1); + } + } + + subset_fd_count = set.get_population (); + if (subset_fd_count == fdCount) + { + /* all font dicts belong to the subset. no need to subset FDSelect & FDArray */ + fdmap.identity (fdCount); + } + else + { + /* create a fdmap */ + fdmap.reset (); + + hb_codepoint_t fd = CFF_UNDEF_CODE; + while (set.next (&fd)) + fdmap.add (fd); + if (unlikely (fdmap.get_population () != subset_fd_count)) + return false; + } + + /* update each font dict index stored as "code" in fdselect_ranges */ + for (unsigned int i = 0; i < fdselect_ranges.length; i++) + fdselect_ranges[i].code = fdmap[fdselect_ranges[i].code]; + } + + /* determine which FDSelect format is most compact */ + if (subset_fd_count > 0xFF) + { + if (unlikely (src.format != 4)) + return false; + subset_fdselect_format = 4; + subset_fdselect_size = FDSelect::min_size + FDSelect4::min_size + FDSelect4_Range::static_size * num_ranges + HBUINT32::static_size; + } + else + { +#if CFF_SERIALIZE_FDSELECT_0 + unsigned int format0_size = FDSelect::min_size + FDSelect0::min_size + HBUINT8::static_size * subset_num_glyphs; +#endif + unsigned int format3_size = FDSelect::min_size + FDSelect3::min_size + FDSelect3_Range::static_size * num_ranges + HBUINT16::static_size; + +#if CFF_SERIALIZE_FDSELECT_0 + if (format0_size <= format3_size) + { + // subset_fdselect_format = 0; + subset_fdselect_size = format0_size; + } + else +#endif + { + subset_fdselect_format = 3; + subset_fdselect_size = format3_size; + } + } + + return true; +} + +template <typename FDSELECT3_4> +static inline bool +serialize_fdselect_3_4 (hb_serialize_context_t *c, + const unsigned int num_glyphs, + const FDSelect &src, + unsigned int size, + const hb_vector_t<code_pair_t> &fdselect_ranges) +{ + TRACE_SERIALIZE (this); + FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size); + if (unlikely (!p)) return_trace (false); + p->nRanges () = fdselect_ranges.length; + for (unsigned int i = 0; i < fdselect_ranges.length; i++) + { + p->ranges[i].first = fdselect_ranges[i].glyph; + p->ranges[i].fd = fdselect_ranges[i].code; + } + p->sentinel () = num_glyphs; + return_trace (true); +} + +/* Serialize a subset FDSelect format planned above. */ +bool +hb_serialize_cff_fdselect (hb_serialize_context_t *c, + const unsigned int num_glyphs, + const FDSelect &src, + unsigned int fd_count, + unsigned int fdselect_format, + unsigned int size, + const hb_vector_t<code_pair_t> &fdselect_ranges) +{ + TRACE_SERIALIZE (this); + FDSelect *p = c->allocate_min<FDSelect> (); + if (unlikely (!p)) return_trace (false); + p->format = fdselect_format; + size -= FDSelect::min_size; + + switch (fdselect_format) + { +#if CFF_SERIALIZE_FDSELECT_0 + case 0: + { + FDSelect0 *p = c->allocate_size<FDSelect0> (size); + if (unlikely (!p)) return_trace (false); + unsigned int range_index = 0; + unsigned int fd = fdselect_ranges[range_index++].code; + for (unsigned int i = 0; i < num_glyphs; i++) + { + if ((range_index < fdselect_ranges.len) && + (i >= fdselect_ranges[range_index].glyph)) + { + fd = fdselect_ranges[range_index++].code; + } + p->fds[i] = fd; + } + return_trace (true); + } +#endif /* CFF_SERIALIZE_FDSELECT_0 */ + + case 3: + return serialize_fdselect_3_4<FDSelect3> (c, num_glyphs, src, + size, fdselect_ranges); + + case 4: + return serialize_fdselect_3_4<FDSelect4> (c, num_glyphs, src, + size, fdselect_ranges); + + default: + return_trace (false); + } +} + + +#endif |