55c4e3f6193bf7dea3e935480fd3357ac466bd6c
[platform/upstream/harfbuzz.git] / src / hb-subset-plan.cc
1 /*
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, Roderick Sheeter
25  */
26
27 #include "hb-map-private.hh"
28 #include "hb-subset-private.hh"
29 #include "hb-set-private.hh"
30
31 #include "hb-subset-plan.hh"
32 #include "hb-ot-cmap-table.hh"
33 #include "hb-ot-glyf-table.hh"
34
35 static void
36 _add_gid_and_children (const OT::glyf::accelerator_t &glyf,
37                        hb_codepoint_t gid,
38                        hb_set_t *gids_to_retain)
39 {
40   if (hb_set_has (gids_to_retain, gid))
41     // Already visited this gid, ignore.
42     return;
43
44   hb_set_add (gids_to_retain, gid);
45
46   OT::glyf::CompositeGlyphHeader::Iterator composite;
47   if (glyf.get_composite (gid, &composite))
48   {
49     do
50     {
51       _add_gid_and_children (glyf, (hb_codepoint_t) composite.current->glyphIndex, gids_to_retain);
52     } while (composite.move_to_next());
53   }
54 }
55
56 static void
57 _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
58 {
59   // TODO(grieger): This uses all lookups, instead collect
60   //                the set of lookups that are relevant.
61   //                See fontTools implementation.
62   hb_ot_layout_lookups_substitute_closure (face,
63                                            nullptr,
64                                            gids_to_retain);
65 }
66
67
68 static void
69 _populate_gids_to_retain (hb_face_t *face,
70                           const hb_set_t *unicodes,
71                           bool close_over_gsub,
72                           hb_set_t *unicodes_to_retain,
73                           hb_map_t *codepoint_to_glyph,
74                           hb_vector_t<hb_codepoint_t> *glyphs)
75 {
76   OT::cmap::accelerator_t cmap;
77   OT::glyf::accelerator_t glyf;
78   cmap.init (face);
79   glyf.init (face);
80
81   hb_set_t *initial_gids_to_retain = hb_set_create ();
82   initial_gids_to_retain->add (0); // Not-def
83
84   hb_codepoint_t cp = HB_SET_VALUE_INVALID;
85   while (unicodes->next (&cp))
86   {
87     hb_codepoint_t gid;
88     if (!cmap.get_nominal_glyph (cp, &gid))
89     {
90       DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
91       continue;
92     }
93     unicodes_to_retain->add (cp);
94     codepoint_to_glyph->set (cp, gid);
95     initial_gids_to_retain->add (gid);
96   }
97
98   if (close_over_gsub)
99     // Add all glyphs needed for GSUB substitutions.
100     _gsub_closure (face, initial_gids_to_retain);
101
102   // Populate a full set of glyphs to retain by adding all referenced
103   // composite glyphs.
104   hb_codepoint_t gid = HB_SET_VALUE_INVALID;
105   hb_set_t *all_gids_to_retain = hb_set_create ();
106   while (initial_gids_to_retain->next (&gid))
107   {
108     _add_gid_and_children (glyf, gid, all_gids_to_retain);
109   }
110   hb_set_destroy (initial_gids_to_retain);
111
112   glyphs->alloc (all_gids_to_retain->get_population ());
113   gid = HB_SET_VALUE_INVALID;
114   while (all_gids_to_retain->next (&gid))
115     glyphs->push (gid);
116
117   hb_set_destroy (all_gids_to_retain);
118   glyf.fini ();
119   cmap.fini ();
120 }
121
122 static void
123 _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
124                                 hb_map_t *glyph_map)
125 {
126   for (unsigned int i = 0; i < glyphs.len; i++) {
127     glyph_map->set (glyphs[i], i);
128   }
129 }
130
131 /**
132  * hb_subset_plan_create:
133  * Computes a plan for subsetting the supplied face according
134  * to a provide profile and input. The plan describes
135  * which tables and glyphs should be retained.
136  *
137  * Return value: New subset plan.
138  *
139  * Since: 1.7.5
140  **/
141 hb_subset_plan_t *
142 hb_subset_plan_create (hb_face_t           *face,
143                        hb_subset_profile_t *profile,
144                        hb_subset_input_t   *input)
145 {
146   hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
147
148   plan->drop_hints = input->drop_hints;
149   plan->drop_ot_layout = input->drop_ot_layout;
150   plan->unicodes = hb_set_create();
151   plan->glyphs.init();
152   plan->source = hb_face_reference (face);
153   plan->dest = hb_subset_face_create ();
154   plan->codepoint_to_glyph = hb_map_create();
155   plan->glyph_map = hb_map_create();
156
157   _populate_gids_to_retain (face,
158                             input->unicodes,
159                             !plan->drop_ot_layout,
160                             plan->unicodes,
161                             plan->codepoint_to_glyph,
162                             &plan->glyphs);
163   _create_old_gid_to_new_gid_map (plan->glyphs,
164                                   plan->glyph_map);
165
166   return plan;
167 }
168
169 /**
170  * hb_subset_plan_destroy:
171  *
172  * Since: 1.7.5
173  **/
174 void
175 hb_subset_plan_destroy (hb_subset_plan_t *plan)
176 {
177   if (!hb_object_destroy (plan)) return;
178
179   hb_set_destroy (plan->unicodes);
180   plan->glyphs.fini();
181   hb_face_destroy (plan->source);
182   hb_face_destroy (plan->dest);
183   hb_map_destroy (plan->codepoint_to_glyph);
184   hb_map_destroy (plan->glyph_map);
185
186   free (plan);
187 }