blob: 6dc8199b23c37d350476ca098ff25f642d8cbccb [file] [log] [blame]
Garret Rieger6a45e5d2018-02-06 16:04:09 -08001/*
2 * Copyright © 2018 Google, Inc.
3 *
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 * Google Author(s): Garret Rieger
25 */
26
Garret Rieger0a5d1442018-02-07 13:09:54 -080027#include "hb-open-type-private.hh"
Garret Rieger53aa0e92018-02-06 17:05:22 -080028#include "hb-ot-glyf-table.hh"
Garret Rieger0a5d1442018-02-07 13:09:54 -080029#include "hb-set.h"
Garret Rieger6a45e5d2018-02-06 16:04:09 -080030#include "hb-subset-glyf.hh"
31
Ebrahim Byagowi203b6472018-02-11 01:00:03 +033032static bool
Garret Rieger8e9fd6f2018-02-07 19:01:21 -080033_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
Behdad Esfahbod70398032018-02-10 15:47:50 -060034 hb_prealloced_array_t<hb_codepoint_t> &glyph_ids,
Garret Riegerd18decd2018-02-09 18:41:21 -080035 bool *use_short_loca, /* OUT */
36 unsigned int *glyf_size, /* OUT */
Garret Rieger8e9fd6f2018-02-07 19:01:21 -080037 unsigned int *loca_size /* OUT */)
Garret Rieger0a5d1442018-02-07 13:09:54 -080038{
39 unsigned int total = 0;
Garret Rieger8e9fd6f2018-02-07 19:01:21 -080040 unsigned int count = 0;
Behdad Esfahbodfd0bde62018-02-13 16:35:30 -080041 for (unsigned int i = 0; i < glyph_ids.len; i++)
42 {
Rod Sheeter59c658c2018-02-08 19:22:47 -080043 hb_codepoint_t next_glyph = glyph_ids[i];
Garret Rieger0a5d1442018-02-07 13:09:54 -080044 unsigned int start_offset, end_offset;
Behdad Esfahbodfd0bde62018-02-13 16:35:30 -080045 if (unlikely (!glyf.get_offsets (next_glyph, &start_offset, &end_offset)))
46 end_offset = start_offset = 0;
Garret Rieger0a5d1442018-02-07 13:09:54 -080047
48 total += end_offset - start_offset;
Garret Rieger8e9fd6f2018-02-07 19:01:21 -080049 count++;
Garret Rieger0a5d1442018-02-07 13:09:54 -080050 }
51
Garret Rieger8e9fd6f2018-02-07 19:01:21 -080052 *glyf_size = total;
Garret Riegerd18decd2018-02-09 18:41:21 -080053 *use_short_loca = (total <= 131070);
54 *loca_size = (count + 1)
55 * (*use_short_loca ? sizeof(OT::HBUINT16) : sizeof(OT::HBUINT32));
56
57 DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca",
58 total,
59 *loca_size,
60 *use_short_loca ? "short" : "long");
Garret Rieger0a5d1442018-02-07 13:09:54 -080061 return true;
62}
63
Ebrahim Byagowi203b6472018-02-11 01:00:03 +033064static void
Garret Riegerd18decd2018-02-09 18:41:21 -080065_write_loca_entry (unsigned int id, unsigned int offset, bool is_short, void *loca_prime) {
66 if (is_short) {
67 ((OT::HBUINT16*) loca_prime) [id].set (offset / 2);
68 } else {
69 ((OT::HBUINT32*) loca_prime) [id].set (offset);
70 }
71}
72
Ebrahim Byagowi203b6472018-02-11 01:00:03 +033073static bool
Garret Rieger8e9fd6f2018-02-07 19:01:21 -080074_write_glyf_and_loca_prime (const OT::glyf::accelerator_t &glyf,
75 const char *glyf_data,
Behdad Esfahbod70398032018-02-10 15:47:50 -060076 hb_prealloced_array_t<hb_codepoint_t> &glyph_ids,
Garret Riegerd18decd2018-02-09 18:41:21 -080077 bool use_short_loca,
Garret Rieger8e9fd6f2018-02-07 19:01:21 -080078 int glyf_prime_size,
79 char *glyf_prime_data /* OUT */,
80 int loca_prime_size,
81 char *loca_prime_data /* OUT */)
Garret Rieger0a5d1442018-02-07 13:09:54 -080082{
83 char *glyf_prime_data_next = glyf_prime_data;
84
Behdad Esfahbodfd0bde62018-02-13 16:35:30 -080085 for (unsigned int i = 0; i < glyph_ids.len; i++)
86 {
87 unsigned int start_offset, end_offset;
88 if (unlikely (!glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset)))
89 end_offset = start_offset = 0;
Garret Rieger0a5d1442018-02-07 13:09:54 -080090
91 int length = end_offset - start_offset;
92 memcpy (glyf_prime_data_next, glyf_data + start_offset, length);
Garret Riegerd18decd2018-02-09 18:41:21 -080093
Behdad Esfahbodfd0bde62018-02-13 16:35:30 -080094 _write_loca_entry (i, glyf_prime_data_next - glyf_prime_data, use_short_loca, loca_prime_data);
Garret Rieger8e9fd6f2018-02-07 19:01:21 -080095
Garret Rieger0a5d1442018-02-07 13:09:54 -080096 glyf_prime_data_next += length;
97 }
98
Behdad Esfahbodfd0bde62018-02-13 16:35:30 -080099 _write_loca_entry (glyph_ids.len, glyf_prime_data_next - glyf_prime_data, use_short_loca, loca_prime_data);
Garret Rieger5a341142018-02-08 18:32:24 -0800100
Garret Rieger0a5d1442018-02-07 13:09:54 -0800101 return true;
102}
103
Ebrahim Byagowi203b6472018-02-11 01:00:03 +0330104static bool
Garret Rieger8e9fd6f2018-02-07 19:01:21 -0800105_hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf,
106 const char *glyf_data,
Behdad Esfahbodc31fcf42018-02-10 14:20:10 -0600107 hb_prealloced_array_t<hb_codepoint_t>&glyphs_to_retain,
Garret Riegerd18decd2018-02-09 18:41:21 -0800108 bool *use_short_loca,
Garret Rieger8e9fd6f2018-02-07 19:01:21 -0800109 hb_blob_t **glyf_prime /* OUT */,
110 hb_blob_t **loca_prime /* OUT */)
Garret Rieger4e1abe22018-02-07 13:28:11 -0800111{
112 // TODO(grieger): Sanity check writes to make sure they are in-bounds.
113 // TODO(grieger): Sanity check allocation size for the new table.
Garret Riegerf9c665f2018-02-07 16:53:18 -0800114 // TODO(grieger): Don't fail on bad offsets, just dump them.
Garret Rieger4e1abe22018-02-07 13:28:11 -0800115
116 unsigned int glyf_prime_size;
Garret Rieger8e9fd6f2018-02-07 19:01:21 -0800117 unsigned int loca_prime_size;
Garret Riegerd18decd2018-02-09 18:41:21 -0800118
Garret Rieger8e9fd6f2018-02-07 19:01:21 -0800119 if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf,
120 glyphs_to_retain,
Garret Riegerd18decd2018-02-09 18:41:21 -0800121 use_short_loca,
Garret Rieger8e9fd6f2018-02-07 19:01:21 -0800122 &glyf_prime_size,
123 &loca_prime_size))) {
Garret Rieger4e1abe22018-02-07 13:28:11 -0800124 return false;
125 }
126
Behdad Esfahbod97a2f032018-02-12 18:51:10 -0800127 char *glyf_prime_data = (char *) malloc (glyf_prime_size);
128 char *loca_prime_data = (char *) malloc (loca_prime_size);
Garret Rieger8e9fd6f2018-02-07 19:01:21 -0800129 if (unlikely (!_write_glyf_and_loca_prime (glyf, glyf_data, glyphs_to_retain,
Garret Riegerd18decd2018-02-09 18:41:21 -0800130 *use_short_loca,
Garret Rieger8e9fd6f2018-02-07 19:01:21 -0800131 glyf_prime_size, glyf_prime_data,
132 loca_prime_size, loca_prime_data))) {
Garret Rieger4e1abe22018-02-07 13:28:11 -0800133 free (glyf_prime_data);
134 return false;
135 }
136
137 *glyf_prime = hb_blob_create (glyf_prime_data,
138 glyf_prime_size,
139 HB_MEMORY_MODE_READONLY,
140 glyf_prime_data,
141 free);
Garret Rieger8e9fd6f2018-02-07 19:01:21 -0800142 *loca_prime = hb_blob_create (loca_prime_data,
143 loca_prime_size,
144 HB_MEMORY_MODE_READONLY,
145 loca_prime_data,
146 free);
Garret Rieger4e1abe22018-02-07 13:28:11 -0800147 return true;
148}
149
Garret Rieger6a45e5d2018-02-06 16:04:09 -0800150/**
151 * hb_subset_glyf:
152 * Subsets the glyph table according to a provided plan.
153 *
154 * Return value: subsetted glyf table.
155 *
156 * Since: 1.7.5
157 **/
158bool
Garret Riegerf9c665f2018-02-07 16:53:18 -0800159hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
160 hb_face_t *face,
Garret Rieger1582eab2018-02-09 12:52:08 -0800161 bool *use_short_loca, /* OUT */
162 hb_blob_t **glyf_prime, /* OUT */
Garret Riegerf9c665f2018-02-07 16:53:18 -0800163 hb_blob_t **loca_prime /* OUT */)
Garret Rieger6a45e5d2018-02-06 16:04:09 -0800164{
Garret Rieger0a5d1442018-02-07 13:09:54 -0800165 hb_blob_t *glyf_blob = OT::Sanitizer<OT::glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf));
166 const char *glyf_data = hb_blob_get_data(glyf_blob, nullptr);
Garret Rieger53aa0e92018-02-06 17:05:22 -0800167
Garret Rieger0a5d1442018-02-07 13:09:54 -0800168 OT::glyf::accelerator_t glyf;
169 glyf.init(face);
Garret Riegerd18decd2018-02-09 18:41:21 -0800170 bool result = _hb_subset_glyf_and_loca (glyf,
171 glyf_data,
172 plan->gids_to_retain_sorted,
173 use_short_loca,
174 glyf_prime,
175 loca_prime);
Garret Rieger0a5d1442018-02-07 13:09:54 -0800176 glyf.fini();
Garret Rieger4e1abe22018-02-07 13:28:11 -0800177
Garret Rieger1582eab2018-02-09 12:52:08 -0800178 *use_short_loca = false;
Garret Riegerf9c665f2018-02-07 16:53:18 -0800179
Garret Rieger4e1abe22018-02-07 13:28:11 -0800180 return result;
Garret Rieger6a45e5d2018-02-06 16:04:09 -0800181}