blob: 711b2236d68bb26edd1b6edd13b03507f38fbd94 [file] [log] [blame]
Michiharu Ariza5561b812018-08-06 10:04:53 -07001/*
Michiharu Ariza0dfa5842018-11-12 08:47:07 -08002 * Copyright © 2018 Adobe Inc.
Michiharu Ariza5561b812018-08-06 10:04:53 -07003 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Adobe Author(s): Michiharu Ariza
25 */
26
Behdad Esfahbod737436d2019-06-18 13:07:44 -070027#include "hb.hh"
28
29#ifndef HB_NO_SUBSET_CFF
30
Michiharu Ariza8af96902018-08-29 13:26:17 -070031#include "hb-ot-cff-common.hh"
Michiharu Ariza5561b812018-08-06 10:04:53 -070032#include "hb-ot-cff2-table.hh"
Michiharu Ariza8af96902018-08-29 13:26:17 -070033#include "hb-subset-cff-common.hh"
Michiharu Ariza5561b812018-08-06 10:04:53 -070034
Michiharu Ariza1377adc2018-09-19 17:00:10 -070035/* Disable FDSelect format 0 for compatibility with fonttools which doesn't seem choose it.
36 * Rarely any/much smaller than format 3 anyway. */
37#define CFF_SERIALIZE_FDSELECT_0 0
38
Michiharu Ariza5561b812018-08-06 10:04:53 -070039using namespace CFF;
40
Khaled Hosny3e2734c2021-07-26 02:12:21 +020041
42/* Determine an optimal FDSelect format according to a provided plan.
Michiharu Ariza5561b812018-08-06 10:04:53 -070043 *
44 * Return value: FDSelect format, size, and ranges for the most compact subset FDSelect
45 * along with a font index remapping table
Khaled Hosny3e2734c2021-07-26 02:12:21 +020046 */
Michiharu Ariza5561b812018-08-06 10:04:53 -070047
48bool
Michiharu Arizaf2908b42019-01-31 14:16:37 -080049hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +043050 unsigned int fdCount,
51 const FDSelect &src, /* IN */
52 unsigned int &subset_fd_count /* OUT */,
53 unsigned int &subset_fdselect_size /* OUT */,
54 unsigned int &subset_fdselect_format /* OUT */,
55 hb_vector_t<code_pair_t> &fdselect_ranges /* OUT */,
Michiharu Ariza09496692019-06-17 22:12:40 -070056 hb_inc_bimap_t &fdmap /* OUT */)
Michiharu Ariza5561b812018-08-06 10:04:53 -070057{
58 subset_fd_count = 0;
Michiharu Ariza0f159a32018-09-12 16:08:54 -070059 subset_fdselect_size = 0;
60 subset_fdselect_format = 0;
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +043061 unsigned int num_ranges = 0;
Michiharu Ariza5561b812018-08-06 10:04:53 -070062
Michiharu Arizaf2908b42019-01-31 14:16:37 -080063 unsigned int subset_num_glyphs = plan->num_output_glyphs ();
Michiharu Ariza5561b812018-08-06 10:04:53 -070064 if (subset_num_glyphs == 0)
65 return true;
66
67 {
68 /* use hb_set to determine the subset of font dicts */
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +043069 hb_set_t *set = hb_set_create ();
Ebrahim Byagowi0527fda2019-10-08 16:19:39 +033070 if (unlikely (set == &Null (hb_set_t))) return false;
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +043071 hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
Michiharu Ariza5561b812018-08-06 10:04:53 -070072 for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
73 {
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +043074 hb_codepoint_t glyph;
75 hb_codepoint_t fd;
Michiharu Arizaf2908b42019-01-31 14:16:37 -080076 if (!plan->old_gid_for_new_gid (i, &glyph))
77 {
Michiharu Arizae2856c22019-02-07 15:32:32 -080078 /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
79 glyph = i;
Michiharu Arizaf2908b42019-01-31 14:16:37 -080080 }
Michiharu Arizae2856c22019-02-07 15:32:32 -080081 fd = src.get_fd (glyph);
Michiharu Ariza5561b812018-08-06 10:04:53 -070082 set->add (fd);
Behdad Esfahbod592f39b2018-11-30 22:54:57 -050083
Michiharu Ariza5561b812018-08-06 10:04:53 -070084 if (fd != prev_fd)
85 {
Behdad Esfahbod825df6d2018-11-30 23:04:59 -050086 num_ranges++;
87 prev_fd = fd;
Michiharu Ariza29f0b6b2018-12-22 07:47:04 -080088 code_pair_t pair = { fd, i };
Behdad Esfahbod825df6d2018-11-30 23:04:59 -050089 fdselect_ranges.push (pair);
Michiharu Ariza5561b812018-08-06 10:04:53 -070090 }
91 }
92
Michiharu Ariza9fae33b2018-08-06 10:44:12 -070093 subset_fd_count = set->get_population ();
94 if (subset_fd_count == fdCount)
Michiharu Ariza5561b812018-08-06 10:04:53 -070095 {
96 /* all font dicts belong to the subset. no need to subset FDSelect & FDArray */
Michiharu Ariza9d0231c2018-11-15 15:39:43 -080097 fdmap.identity (fdCount);
Michiharu Ariza5561b812018-08-06 10:04:53 -070098 hb_set_destroy (set);
Michiharu Ariza5561b812018-08-06 10:04:53 -070099 }
Michiharu Ariza9d0231c2018-11-15 15:39:43 -0800100 else
Michiharu Ariza1666b892018-09-10 16:00:20 -0700101 {
Michiharu Ariza9d0231c2018-11-15 15:39:43 -0800102 /* create a fdmap */
Michiharu Ariza09496692019-06-17 22:12:40 -0700103 fdmap.reset ();
Michiharu Ariza1666b892018-09-10 16:00:20 -0700104
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430105 hb_codepoint_t fd = CFF_UNDEF_CODE;
Michiharu Ariza9d0231c2018-11-15 15:39:43 -0800106 while (set->next (&fd))
Behdad Esfahbod825df6d2018-11-30 23:04:59 -0500107 fdmap.add (fd);
Michiharu Ariza9d0231c2018-11-15 15:39:43 -0800108 hb_set_destroy (set);
Michiharu Ariza09496692019-06-17 22:12:40 -0700109 if (unlikely (fdmap.get_population () != subset_fd_count))
Ebrahim Byagowice114d62019-12-31 15:53:02 +0330110 return false;
Michiharu Ariza9d0231c2018-11-15 15:39:43 -0800111 }
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700112
113 /* update each font dict index stored as "code" in fdselect_ranges */
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500114 for (unsigned int i = 0; i < fdselect_ranges.length; i++)
Michiharu Arizaf3ee2bd2019-06-20 14:33:09 -0700115 fdselect_ranges[i].code = fdmap[fdselect_ranges[i].code];
Michiharu Ariza5561b812018-08-06 10:04:53 -0700116 }
117
118 /* determine which FDSelect format is most compact */
119 if (subset_fd_count > 0xFF)
120 {
Michiharu Ariza33358622018-12-11 12:20:20 -0800121 if (unlikely (src.format != 4))
122 return false;
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700123 subset_fdselect_format = 4;
Michiharu Ariza34b06d92018-11-02 16:40:20 -0700124 subset_fdselect_size = FDSelect::min_size + FDSelect4::min_size + FDSelect4_Range::static_size * num_ranges + HBUINT32::static_size;
Michiharu Ariza5561b812018-08-06 10:04:53 -0700125 }
126 else
127 {
Michiharu Ariza1377adc2018-09-19 17:00:10 -0700128#if CFF_SERIALIZE_FDSELECT_0
Michiharu Ariza34b06d92018-11-02 16:40:20 -0700129 unsigned int format0_size = FDSelect::min_size + FDSelect0::min_size + HBUINT8::static_size * subset_num_glyphs;
Michiharu Ariza1377adc2018-09-19 17:00:10 -0700130#endif
Michiharu Ariza34b06d92018-11-02 16:40:20 -0700131 unsigned int format3_size = FDSelect::min_size + FDSelect3::min_size + FDSelect3_Range::static_size * num_ranges + HBUINT16::static_size;
Michiharu Ariza5561b812018-08-06 10:04:53 -0700132
Michiharu Ariza1377adc2018-09-19 17:00:10 -0700133#if CFF_SERIALIZE_FDSELECT_0
Michiharu Ariza5561b812018-08-06 10:04:53 -0700134 if (format0_size <= format3_size)
135 {
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700136 // subset_fdselect_format = 0;
137 subset_fdselect_size = format0_size;
Michiharu Ariza5561b812018-08-06 10:04:53 -0700138 }
139 else
Michiharu Ariza1377adc2018-09-19 17:00:10 -0700140#endif
Michiharu Ariza5561b812018-08-06 10:04:53 -0700141 {
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700142 subset_fdselect_format = 3;
143 subset_fdselect_size = format3_size;
Michiharu Ariza5561b812018-08-06 10:04:53 -0700144 }
145 }
146
147 return true;
148}
149
150template <typename FDSELECT3_4>
151static inline bool
152serialize_fdselect_3_4 (hb_serialize_context_t *c,
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430153 const unsigned int num_glyphs,
154 const FDSelect &src,
155 unsigned int size,
156 const hb_vector_t<code_pair_t> &fdselect_ranges)
Michiharu Ariza5561b812018-08-06 10:04:53 -0700157{
158 TRACE_SERIALIZE (this);
159 FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
Ebrahim Byagowi2be859d2020-04-20 23:48:23 +0430160 if (unlikely (!p)) return_trace (false);
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700161 p->nRanges () = fdselect_ranges.length;
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500162 for (unsigned int i = 0; i < fdselect_ranges.length; i++)
Michiharu Ariza5561b812018-08-06 10:04:53 -0700163 {
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700164 p->ranges[i].first = fdselect_ranges[i].glyph;
165 p->ranges[i].fd = fdselect_ranges[i].code;
Michiharu Ariza5561b812018-08-06 10:04:53 -0700166 }
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430167 p->sentinel () = num_glyphs;
Michiharu Ariza5561b812018-08-06 10:04:53 -0700168 return_trace (true);
169}
170
Khaled Hosny3e2734c2021-07-26 02:12:21 +0200171/* Serialize a subset FDSelect format planned above. */
Michiharu Ariza5561b812018-08-06 10:04:53 -0700172bool
173hb_serialize_cff_fdselect (hb_serialize_context_t *c,
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430174 const unsigned int num_glyphs,
175 const FDSelect &src,
176 unsigned int fd_count,
177 unsigned int fdselect_format,
178 unsigned int size,
179 const hb_vector_t<code_pair_t> &fdselect_ranges)
Michiharu Ariza5561b812018-08-06 10:04:53 -0700180{
181 TRACE_SERIALIZE (this);
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430182 FDSelect *p = c->allocate_min<FDSelect> ();
Ebrahim Byagowi2be859d2020-04-20 23:48:23 +0430183 if (unlikely (!p)) return_trace (false);
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700184 p->format = fdselect_format;
Michiharu Ariza5561b812018-08-06 10:04:53 -0700185 size -= FDSelect::min_size;
186
187 switch (fdselect_format)
188 {
Michiharu Ariza1377adc2018-09-19 17:00:10 -0700189#if CFF_SERIALIZE_FDSELECT_0
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430190 case 0:
191 {
192 FDSelect0 *p = c->allocate_size<FDSelect0> (size);
Ebrahim Byagowi2be859d2020-04-20 23:48:23 +0430193 if (unlikely (!p)) return_trace (false);
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430194 unsigned int range_index = 0;
195 unsigned int fd = fdselect_ranges[range_index++].code;
196 for (unsigned int i = 0; i < num_glyphs; i++)
Michiharu Ariza5561b812018-08-06 10:04:53 -0700197 {
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430198 if ((range_index < fdselect_ranges.len) &&
199 (i >= fdselect_ranges[range_index].glyph))
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700200 {
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430201 fd = fdselect_ranges[range_index++].code;
Michiharu Ariza0f159a32018-09-12 16:08:54 -0700202 }
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430203 p->fds[i] = fd;
Michiharu Ariza5561b812018-08-06 10:04:53 -0700204 }
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430205 return_trace (true);
206 }
Michiharu Ariza1377adc2018-09-19 17:00:10 -0700207#endif /* CFF_SERIALIZE_FDSELECT_0 */
Behdad Esfahbod592f39b2018-11-30 22:54:57 -0500208
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430209 case 3:
210 return serialize_fdselect_3_4<FDSelect3> (c, num_glyphs, src,
211 size, fdselect_ranges);
Behdad Esfahbod592f39b2018-11-30 22:54:57 -0500212
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430213 case 4:
214 return serialize_fdselect_3_4<FDSelect4> (c, num_glyphs, src,
215 size, fdselect_ranges);
Michiharu Ariza5561b812018-08-06 10:04:53 -0700216
Ebrahim Byagowi6bcbe492019-06-13 15:04:51 +0430217 default:
218 return_trace (false);
Michiharu Ariza5561b812018-08-06 10:04:53 -0700219 }
Michiharu Ariza5561b812018-08-06 10:04:53 -0700220}
Behdad Esfahbod737436d2019-06-18 13:07:44 -0700221
222
223#endif