hb-subset-plan.cc 4.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright © 2018  Google, 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.
 *
24
 * Google Author(s): Garret Rieger, Roderick Sheeter
25 26
 */

G
Garret Rieger 已提交
27
#include "hb-subset-private.hh"
28

29
#include "hb-subset-plan.hh"
30 31
#include "hb-ot-cmap-table.hh"

G
Garret Rieger 已提交
32
int
33
_hb_codepoint_t_cmp (const void *l, const void *r) {
34 35 36
  return *((hb_codepoint_t *) l) - *((hb_codepoint_t *) r);
}

37
hb_bool_t
G
Garret Rieger 已提交
38 39 40 41
hb_subset_plan_new_gid_for_old_id (hb_subset_plan_t *plan,
                                   hb_codepoint_t old_gid,
                                   hb_codepoint_t *new_gid)
{
42
  // the index in old_gids is the new gid; only up to codepoints.len are valid
43 44
  for (unsigned int i = 0; i < plan->gids_to_retain_sorted.len; i++) {
    if (plan->gids_to_retain_sorted[i] == old_gid) {
45
      *new_gid = i;
46 47 48 49 50 51
      return true;
    }
  }
  return false;
}

G
Garret Rieger 已提交
52 53 54 55 56
void
_populate_codepoints (hb_set_t *input_codepoints,
                      hb_auto_array_t<hb_codepoint_t>& plan_codepoints)
{
  plan_codepoints.alloc (hb_set_get_population (input_codepoints));
57
  hb_codepoint_t cp = -1;
G
Garret Rieger 已提交
58
  while (hb_set_next (input_codepoints, &cp)) {
59 60 61
    hb_codepoint_t *wr = plan_codepoints.push();
    *wr = cp;
  }
62
  plan_codepoints.qsort (_hb_codepoint_t_cmp);
63 64 65
}

void
G
Garret Rieger 已提交
66 67
_populate_gids_to_retain (hb_face_t *face,
                          hb_auto_array_t<hb_codepoint_t>& codepoints,
68 69
                          hb_auto_array_t<hb_codepoint_t>& old_gids,
                          hb_auto_array_t<hb_codepoint_t>& old_gids_sorted)
G
Garret Rieger 已提交
70
{
71 72
  OT::cmap::accelerator_t cmap;
  cmap.init (face);
73 74 75

  hb_auto_array_t<unsigned int> bad_indices;

G
Garret Rieger 已提交
76
  old_gids.alloc (codepoints.len);
77
  bool has_zero = false;
78
  for (unsigned int i = 0; i < codepoints.len; i++) {
79
    hb_codepoint_t gid;
G
Garret Rieger 已提交
80
    if (!cmap.get_nominal_glyph (codepoints[i], &gid)) {
81
      gid = -1;
G
Garret Rieger 已提交
82
      *(bad_indices.push ()) = i;
83
    }
84 85 86
    if (gid == 0) {
      has_zero = true;
    }
G
Garret Rieger 已提交
87
    *(old_gids.push ()) = gid;
88 89 90 91
  }

  while (bad_indices.len > 0) {
    unsigned int i = bad_indices[bad_indices.len - 1];
G
Garret Rieger 已提交
92
    bad_indices.pop ();
93
    DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", codepoints[i]);
G
Garret Rieger 已提交
94 95
    codepoints.remove (i);
    old_gids.remove (i);
96
  }
97

98 99 100 101 102 103 104 105 106 107
  // Populate a second glyph id array that is sorted by glyph id
  // and is gauranteed to contain 0.
  old_gids_sorted.alloc (old_gids.len + (has_zero ? 0 : 1));
  for (unsigned int i = 0; i < old_gids.len; i++) {
    *(old_gids_sorted.push ()) = old_gids[i];
  }
  if (!has_zero)
    *(old_gids_sorted.push ()) = 0;
  old_gids_sorted.qsort (_hb_codepoint_t_cmp);

108 109 110 111
  for (unsigned int i = 0; i < codepoints.len; i++) {
      DEBUG_MSG(SUBSET, nullptr, " U+%04X, old_gid %d, new_gid %d", codepoints[i], old_gids[i], i);
  }

112 113
  // TODO(Q1) expand with glyphs that make up complex glyphs
  // TODO expand with glyphs reached by G*
114 115
  //
  cmap.fini ();
G
Garret Rieger 已提交
116
}
117 118 119 120 121 122 123

/**
 * hb_subset_plan_create:
 * Computes a plan for subsetting the supplied face according
 * to a provide profile and input. The plan describes
 * which tables and glyphs should be retained.
 *
124
 * Return value: New subset plan.
125 126 127 128
 *
 * Since: 1.7.5
 **/
hb_subset_plan_t *
129
hb_subset_plan_create (hb_face_t           *face,
130 131 132
                       hb_subset_profile_t *profile,
                       hb_subset_input_t   *input)
{
G
Garret Rieger 已提交
133
  hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
G
Garret Rieger 已提交
134
  _populate_codepoints (input->codepoints, plan->codepoints);
135 136 137 138
  _populate_gids_to_retain (face,
                            plan->codepoints,
                            plan->gids_to_retain,
                            plan->gids_to_retain_sorted);
G
Garret Rieger 已提交
139
  return plan;
140 141 142
}

hb_subset_plan_t *
G
Garret Rieger 已提交
143
hb_subset_plan_get_empty ()
144
{
G
Garret Rieger 已提交
145 146
  hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
  return plan;
147 148 149 150 151 152 153 154 155 156 157 158
}

/**
 * hb_subset_plan_destroy:
 *
 * Since: 1.7.5
 **/
void
hb_subset_plan_destroy (hb_subset_plan_t *plan)
{
  if (!hb_object_destroy (plan)) return;

G
Garret Rieger 已提交
159 160
  plan->codepoints.finish ();
  plan->gids_to_retain.finish ();
161
  plan->gids_to_retain_sorted.finish ();
162 163
  free (plan);
}