blob: fc343fec2e3dd9b7c10041f4d3ac40088803a07a [file] [log] [blame]
Garret Riegera2965f22018-01-31 14:53:09 -08001/*
Behdad Esfahbodbfa87162018-02-10 13:37:28 -06002 * Copyright © 2018 Google, Inc.
Garret Riegera2965f22018-01-31 14:53:09 -08003 *
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 *
Rod Sheeterd463e9f2018-02-14 15:04:15 -080024 * Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
Garret Riegera2965f22018-01-31 14:53:09 -080025 */
26
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070027#include "hb.hh"
28#include "hb-open-type.hh"
Rod Sheeter0859a002018-02-07 15:59:36 -080029
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070030#include "hb-subset.hh"
Garret Riegera2965f22018-01-31 14:53:09 -080031
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#include "hb-open-file.hh"
Rod Sheeter0859a002018-02-07 15:59:36 -080033#include "hb-ot-cmap-table.hh"
Garret Rieger6a45e5d2018-02-06 16:04:09 -080034#include "hb-ot-glyf-table.hh"
Garret Riegerfe428622018-02-21 14:18:49 -080035#include "hb-ot-hdmx-table.hh"
Garret Rieger83e1ef92018-02-12 11:22:32 -080036#include "hb-ot-head-table.hh"
Rod Sheeterfa877702018-02-14 14:16:25 -080037#include "hb-ot-hhea-table.hh"
38#include "hb-ot-hmtx-table.hh"
Garret Rieger83e1ef92018-02-12 11:22:32 -080039#include "hb-ot-maxp-table.hh"
ckitagawa43b6c862020-01-09 10:44:20 -050040#include "hb-ot-color-sbix-table.hh"
Garret Rieger24904382018-02-12 17:31:01 -080041#include "hb-ot-os2-table.hh"
Garret Riegerdd107692018-03-06 18:33:39 -080042#include "hb-ot-post-table.hh"
Michiharu Arizafdbfa182018-08-16 00:13:09 -070043#include "hb-ot-cff1-table.hh"
Michiharu Ariza3a61c3e2018-07-18 14:17:52 -070044#include "hb-ot-cff2-table.hh"
Michiharu Arizaf212c052018-09-20 09:45:43 -070045#include "hb-ot-vorg-table.hh"
Qunxin Liu408c1da2019-03-29 10:34:32 -070046#include "hb-ot-name-table.hh"
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070047#include "hb-ot-layout-gsub-table.hh"
48#include "hb-ot-layout-gpos-table.hh"
Michiharu Ariza2c5ed7f2019-02-26 11:11:50 -080049#include "hb-ot-var-gvar-table.hh"
Michiharu Ariza09df17e2019-02-20 15:48:29 -080050#include "hb-ot-var-hvar-table.hh"
Garret Rieger6a45e5d2018-02-06 16:04:09 -080051
Behdad Esfahbod2da0d872018-02-07 12:44:35 -050052
Behdad Esfahbod19e800c2019-04-15 12:07:00 -040053HB_UNUSED static inline unsigned int
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070054_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
Behdad Esfahbod19e800c2019-04-15 12:07:00 -040055 unsigned int table_len);
56static inline unsigned int
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070057_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
58 unsigned int table_len)
Garret Riegera2965f22018-01-31 14:53:09 -080059{
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070060 unsigned int src_glyphs = plan->source->get_num_glyphs ();
Garret Rieger05e99c82019-01-28 17:05:04 -080061 unsigned int dst_glyphs = plan->glyphset ()->get_population ();
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070062
Behdad Esfahbod5f17dbc2018-09-07 10:24:22 -040063 if (unlikely (!src_glyphs))
64 return 512 + table_len;
65
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070066 return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
Garret Riegera2965f22018-01-31 14:53:09 -080067}
68
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070069template<typename TableType>
70static bool
71_subset2 (hb_subset_plan_t *plan)
Garret Riegera2965f22018-01-31 14:53:09 -080072{
Qunxin Liu209491f2019-05-29 14:03:17 -070073 bool result = false;
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070074 hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
75 const TableType *table = source_blob->as<TableType> ();
Garret Riegera2965f22018-01-31 14:53:09 -080076
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070077 hb_tag_t tag = TableType::tableTag;
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070078 if (source_blob->data)
79 {
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -070080 hb_vector_t<char> buf;
Behdad Esfahbod521262b2019-05-07 11:08:08 -070081 /* TODO Not all tables are glyph-related. 'name' table size for example should not be
82 * affected by number of glyphs. Accommodate that. */
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070083 unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +033084 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070085 if (unlikely (!buf.alloc (buf_size)))
86 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +033087 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
Ebrahim Byagowi28aba782019-08-23 16:47:15 +043088 hb_blob_destroy (source_blob);
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070089 return false;
90 }
91 retry:
Behdad Esfahbod861bc752018-11-29 14:34:44 -050092 hb_serialize_context_t serializer ((void *) buf, buf_size);
Behdad Esfahbod2e675cc2019-04-01 16:45:50 -070093 serializer.start_serialize<TableType> ();
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070094 hb_subset_context_t c (plan, &serializer);
Behdad Esfahbod6977a952019-04-27 10:05:25 -070095 bool needed = table->subset (&c);
Behdad Esfahbodfe05e482019-03-30 15:06:25 -070096 if (serializer.ran_out_of_room)
Behdad Esfahboda1e5e072018-09-05 16:24:28 -070097 {
98 buf_size += (buf_size >> 1) + 32;
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +033099 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size);
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700100 if (unlikely (!buf.alloc (buf_size)))
101 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330102 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size);
Ebrahim Byagowi28aba782019-08-23 16:47:15 +0430103 hb_blob_destroy (source_blob);
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700104 return false;
105 }
106 goto retry;
107 }
Qunxin Liu19afd252019-04-24 14:02:29 -0700108 serializer.end_serialize ();
Behdad Esfahbod2b051e72019-04-27 10:01:11 -0700109
Behdad Esfahbod6977a952019-04-27 10:05:25 -0700110 result = !serializer.in_error ();
Behdad Esfahbodfe05e482019-03-30 15:06:25 -0700111
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700112 if (result)
113 {
Behdad Esfahbod6977a952019-04-27 10:05:25 -0700114 if (needed)
115 {
116 hb_blob_t *dest_blob = serializer.copy_blob ();
117 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length);
118 result = c.plan->add_table (tag, dest_blob);
119 hb_blob_destroy (dest_blob);
120 }
121 else
122 {
123 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag));
124 }
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700125 }
126 }
127 else
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330128 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700129
130 hb_blob_destroy (source_blob);
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330131 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!");
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700132 return result;
Garret Riegera2965f22018-01-31 14:53:09 -0800133}
134
Rod Sheeter0859a002018-02-07 15:59:36 -0800135template<typename TableType>
Rod Sheeter3ed70e52018-02-14 15:24:49 -0800136static bool
Rod Sheeterfa877702018-02-14 14:16:25 -0800137_subset (hb_subset_plan_t *plan)
Rod Sheeter0859a002018-02-07 15:59:36 -0800138{
Behdad Esfahboded7b2e52018-08-01 23:59:09 -0700139 hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
Behdad Esfahbodeba1c162018-05-08 02:47:42 -0700140 const TableType *table = source_blob->as<TableType> ();
Rod Sheeter13193a92018-02-07 16:09:52 -0800141
Garret Rieger07851aa2018-03-26 20:56:56 -0600142 hb_tag_t tag = TableType::tableTag;
Garret Riegerec302ad2018-02-22 11:57:35 -0800143 hb_bool_t result = false;
Behdad Esfahbodb912fbe2018-08-06 06:30:12 -0700144 if (source_blob->data)
Behdad Esfahbodd237ce72018-08-29 18:13:07 -0700145 result = table->subset (plan);
146 else
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330147 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
Garret Riegerec302ad2018-02-22 11:57:35 -0800148
149 hb_blob_destroy (source_blob);
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330150 DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!");
Garret Riegerec302ad2018-02-22 11:57:35 -0800151 return result;
Rod Sheeter0859a002018-02-07 15:59:36 -0800152}
Garret Riegera2965f22018-01-31 14:53:09 -0800153
Behdad Esfahbod6804b612018-02-07 13:47:35 -0500154
Behdad Esfahboda981d792018-02-10 15:17:28 -0600155static bool
Garret Riegeraac7d962018-02-08 18:18:16 -0800156_subset_table (hb_subset_plan_t *plan,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330157 hb_tag_t tag)
Garret Riegeraac7d962018-02-08 18:18:16 -0800158{
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330159 DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG (tag));
Rod Sheeterfa877702018-02-14 14:16:25 -0800160 bool result = true;
Garret Riegeraac7d962018-02-08 18:18:16 -0800161 switch (tag) {
162 case HB_OT_TAG_glyf:
rsheeter02d4d4f2019-05-08 14:43:18 -0700163 result = _subset2<const OT::glyf> (plan);
Rod Sheeterfa877702018-02-14 14:16:25 -0800164 break;
Garret Riegeraa4aa232018-02-21 17:43:32 -0800165 case HB_OT_TAG_hdmx:
Garret Riegerd5decf92019-05-07 15:47:38 -0700166 result = _subset2<const OT::hdmx> (plan);
Garret Riegeraa4aa232018-02-21 17:43:32 -0800167 break;
Qunxin Liu408c1da2019-03-29 10:34:32 -0700168 case HB_OT_TAG_name:
Qunxin Liu19afd252019-04-24 14:02:29 -0700169 result = _subset2<const OT::name> (plan);
Qunxin Liu408c1da2019-03-29 10:34:32 -0700170 break;
Garret Rieger1582eab2018-02-09 12:52:08 -0800171 case HB_OT_TAG_head:
Rod Sheeter9bd6d252018-02-23 13:05:58 -0800172 // TODO that won't work well if there is no glyf
173 DEBUG_MSG(SUBSET, nullptr, "skip head, handled by glyf");
Rod Sheeterfa877702018-02-14 14:16:25 -0800174 result = true;
175 break;
176 case HB_OT_TAG_hhea:
Rod Sheeter9bd6d252018-02-23 13:05:58 -0800177 DEBUG_MSG(SUBSET, nullptr, "skip hhea handled by hmtx");
Garret Rieger1582eab2018-02-09 12:52:08 -0800178 return true;
Rod Sheeterfa877702018-02-14 14:16:25 -0800179 case HB_OT_TAG_hmtx:
Qunxin Liu209491f2019-05-29 14:03:17 -0700180 result = _subset2<const OT::hmtx> (plan);
Rod Sheeterfa877702018-02-14 14:16:25 -0800181 break;
Garret Rieger0e8f9432018-03-06 13:08:20 -0800182 case HB_OT_TAG_vhea:
Garret Rieger91867cd2018-03-07 10:17:06 -0800183 DEBUG_MSG(SUBSET, nullptr, "skip vhea handled by vmtx");
Garret Rieger0e8f9432018-03-06 13:08:20 -0800184 return true;
Garret Rieger64cf53d2018-03-02 17:33:49 -0800185 case HB_OT_TAG_vmtx:
Qunxin Liu209491f2019-05-29 14:03:17 -0700186 result = _subset2<const OT::vmtx> (plan);
Garret Rieger64cf53d2018-03-02 17:33:49 -0800187 break;
Garret Rieger83e1ef92018-02-12 11:22:32 -0800188 case HB_OT_TAG_maxp:
Qunxin Liudb938472019-06-04 10:30:53 -0700189 result = _subset2<const OT::maxp> (plan);
Garret Riegerdf6d7802018-02-12 17:56:17 -0800190 break;
ckitagawa43b6c862020-01-09 10:44:20 -0500191 case HB_OT_TAG_sbix:
192 result = _subset2<const OT::sbix> (plan);
193 break;
Garret Riegeraac7d962018-02-08 18:18:16 -0800194 case HB_OT_TAG_loca:
Rod Sheeter9bd6d252018-02-23 13:05:58 -0800195 DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf");
Garret Riegeraac7d962018-02-08 18:18:16 -0800196 return true;
197 case HB_OT_TAG_cmap:
Qunxin Liu37572882019-06-25 13:17:30 -0700198 result = _subset2<const OT::cmap> (plan);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800199 break;
Khaled Hosny2c68f342018-11-02 23:06:00 +0200200 case HB_OT_TAG_OS2:
Garret Riegerf9b1ae72019-06-05 17:40:59 -0700201 result = _subset2<const OT::OS2> (plan);
Garret Rieger24904382018-02-12 17:31:01 -0800202 break;
Garret Riegerdd107692018-03-06 18:33:39 -0800203 case HB_OT_TAG_post:
Qunxin Liu93d592e2019-06-05 16:51:31 -0700204 result = _subset2<const OT::post> (plan);
Garret Riegerdd107692018-03-06 18:33:39 -0800205 break;
Behdad Esfahbod5ea8ad52019-05-10 23:36:42 -0700206
207#ifndef HB_NO_SUBSET_CFF
Michiharu Arizae67bb3f2018-08-16 00:25:57 -0700208 case HB_OT_TAG_cff1:
209 result = _subset<const OT::cff1> (plan);
Michiharu Ariza64c54122018-08-10 11:07:07 -0700210 break;
Michiharu Ariza3a61c3e2018-07-18 14:17:52 -0700211 case HB_OT_TAG_cff2:
212 result = _subset<const OT::cff2> (plan);
213 break;
Michiharu Arizaf212c052018-09-20 09:45:43 -0700214 case HB_OT_TAG_VORG:
Qunxin Liu9bd8d662019-06-12 11:02:48 -0700215 result = _subset2<const OT::VORG> (plan);
Michiharu Arizaf212c052018-09-20 09:45:43 -0700216 break;
Behdad Esfahbod5ea8ad52019-05-10 23:36:42 -0700217#endif
Behdad Esfahbod47e538a2019-04-12 22:50:22 -0400218
Behdad Esfahbod227d85e2019-05-10 23:15:58 -0700219#ifndef HB_NO_SUBSET_LAYOUT
Behdad Esfahbod42a10122018-12-13 19:39:59 -0500220 case HB_OT_TAG_GDEF:
221 result = _subset2<const OT::GDEF> (plan);
222 break;
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700223 case HB_OT_TAG_GSUB:
224 result = _subset2<const OT::GSUB> (plan);
225 break;
226 case HB_OT_TAG_GPOS:
227 result = _subset2<const OT::GPOS> (plan);
228 break;
Michiharu Ariza2c5ed7f2019-02-26 11:11:50 -0800229 case HB_OT_TAG_gvar:
230 result = _subset2<const OT::gvar> (plan);
231 break;
Michiharu Ariza09df17e2019-02-20 15:48:29 -0800232 case HB_OT_TAG_HVAR:
233 result = _subset2<const OT::HVAR> (plan);
234 break;
Michiharu Ariza655bc962019-02-22 14:53:06 -0800235 case HB_OT_TAG_VVAR:
236 result = _subset2<const OT::VVAR> (plan);
237 break;
Behdad Esfahbod47e538a2019-04-12 22:50:22 -0400238#endif
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700239
Garret Riegeraac7d962018-02-08 18:18:16 -0800240 default:
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330241 hb_blob_t *source_table = hb_face_reference_table (plan->source, tag);
Garret Rieger66b0a392018-02-23 15:41:52 -0800242 if (likely (source_table))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330243 result = plan->add_table (tag, source_table);
Rod Sheeterfa877702018-02-14 14:16:25 -0800244 else
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330245 result = false;
Garret Rieger66b0a392018-02-23 15:41:52 -0800246 hb_blob_destroy (source_table);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800247 break;
Garret Rieger83e1ef92018-02-12 11:22:32 -0800248 }
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330249 DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG (tag), result ? "ok" : "FAILED");
Rod Sheeter2d026522018-02-21 09:42:46 -0800250 return result;
Garret Riegeraac7d962018-02-08 18:18:16 -0800251}
252
Rod Sheeter692f86e2018-02-12 11:29:23 -0800253static bool
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330254_should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag)
Rod Sheeter692f86e2018-02-12 11:29:23 -0800255{
Garret Rieger3be0ffe2019-05-16 11:29:15 -0700256 if (plan->drop_tables->has (tag))
257 return true;
258
Garret Rieger39b2f692018-03-08 16:30:36 -0800259 switch (tag) {
260 case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */
261 case HB_TAG ('c', 'v', 't', ' '): /* hint table, fallthrough */
262 case HB_TAG ('f', 'p', 'g', 'm'): /* hint table, fallthrough */
263 case HB_TAG ('p', 'r', 'e', 'p'): /* hint table, fallthrough */
264 case HB_TAG ('h', 'd', 'm', 'x'): /* hint table, fallthrough */
265 case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */
266 return plan->drop_hints;
Behdad Esfahbod47e538a2019-04-12 22:50:22 -0400267
Garret Rieger0ff36182019-05-17 15:30:01 -0700268#ifdef HB_NO_SUBSET_LAYOUT
Garret Riegera5673da2018-06-07 14:23:03 -0700269 // Drop Layout Tables if requested.
Behdad Esfahbod57610312018-12-12 21:21:26 -0500270 case HB_OT_TAG_GDEF:
271 case HB_OT_TAG_GPOS:
272 case HB_OT_TAG_GSUB:
Garret Riegerff7fc6d2019-05-22 17:36:16 -0700273 case HB_TAG ('m', 'o', 'r', 'x'):
274 case HB_TAG ('m', 'o', 'r', 't'):
275 case HB_TAG ('k', 'e', 'r', 'x'):
276 case HB_TAG ('k', 'e', 'r', 'n'):
Behdad Esfahbod47e538a2019-04-12 22:50:22 -0400277 return true;
278#endif
Behdad Esfahbod47e538a2019-04-12 22:50:22 -0400279
Garret Rieger39b2f692018-03-08 16:30:36 -0800280 default:
281 return false;
Garret Rieger24904382018-02-12 17:31:01 -0800282 }
Rod Sheeter692f86e2018-02-12 11:29:23 -0800283}
284
Garret Riegera2965f22018-01-31 14:53:09 -0800285/**
286 * hb_subset:
Behdad Esfahbod7fd0b612018-02-07 16:44:52 -0600287 * @source: font face data to be subset.
Garret Riegera2965f22018-01-31 14:53:09 -0800288 * @input: input to use for the subsetting.
Garret Riegera2965f22018-01-31 14:53:09 -0800289 *
Behdad Esfahbodf39166f2018-08-29 18:09:55 -0700290 * Subsets a font according to provided input.
Garret Riegera2965f22018-01-31 14:53:09 -0800291 **/
Behdad Esfahbodaf028122018-02-07 13:07:46 -0500292hb_face_t *
293hb_subset (hb_face_t *source,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330294 hb_subset_input_t *input)
Garret Riegera2965f22018-01-31 14:53:09 -0800295{
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330296 if (unlikely (!input || !source)) return hb_face_get_empty ();
Garret Riegera2965f22018-01-31 14:53:09 -0800297
Behdad Esfahbodf39166f2018-08-29 18:09:55 -0700298 hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
Garret Rieger31ec3c22018-02-06 15:37:34 -0800299
Garret Riegeraac7d962018-02-08 18:18:16 -0800300 hb_tag_t table_tags[32];
301 unsigned int offset = 0, count;
Rod Sheeter13193a92018-02-07 16:09:52 -0800302 bool success = true;
Ebrahim Byagowi41d6e952019-09-02 01:41:48 +0430303 hb_set_t tags_set;
Garret Riegeraac7d962018-02-08 18:18:16 -0800304 do {
305 count = ARRAY_LENGTH (table_tags);
306 hb_face_get_table_tags (source, offset, &count, table_tags);
307 for (unsigned int i = 0; i < count; i++)
308 {
309 hb_tag_t tag = table_tags[i];
Ebrahim Byagowi41d6e952019-09-02 01:41:48 +0430310 if (_should_drop_table (plan, tag) && !tags_set.has (tag))
Rod Sheeter692f86e2018-02-12 11:29:23 -0800311 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330312 DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG (tag));
313 continue;
Rod Sheeter692f86e2018-02-12 11:29:23 -0800314 }
Ebrahim Byagowi41d6e952019-09-02 01:41:48 +0430315 tags_set.add (tag);
Rod Sheeterfa877702018-02-14 14:16:25 -0800316 success = success && _subset_table (plan, tag);
Garret Riegeraac7d962018-02-08 18:18:16 -0800317 }
Garret Rieger1c337272018-03-27 10:42:19 -0700318 offset += count;
Behdad Esfahbodd237ce72018-08-29 18:13:07 -0700319 } while (success && count == ARRAY_LENGTH (table_tags));
Rod Sheeter13193a92018-02-07 16:09:52 -0800320
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330321 hb_face_t *result = success ? hb_face_reference (plan->dest) : hb_face_get_empty ();
Garret Rieger5df080b2018-02-12 10:15:59 -0800322 hb_subset_plan_destroy (plan);
Rod Sheeterfa877702018-02-14 14:16:25 -0800323 return result;
Garret Riegera2965f22018-01-31 14:53:09 -0800324}