Imported Upstream version 1.7.6
[platform/upstream/harfbuzz.git] / src / hb-ot-hdmx-table.hh
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
25  */
26
27 #ifndef HB_OT_HDMX_TABLE_HH
28 #define HB_OT_HDMX_TABLE_HH
29
30 #include "hb-open-type-private.hh"
31
32 namespace OT {
33
34
35 /*
36  * hdmx - Horizontal Device Metric
37  */
38
39 #define HB_OT_TAG_hdmx HB_TAG('h','d','m','x')
40
41 struct DeviceRecord
42 {
43   struct SubsetView
44   {
45     const DeviceRecord *source_device_record;
46     hb_subset_plan_t *subset_plan;
47
48     inline void init(const DeviceRecord *source_device_record,
49                      hb_subset_plan_t   *subset_plan)
50     {
51       this->source_device_record = source_device_record;
52       this->subset_plan = subset_plan;
53     }
54
55     inline unsigned int len () const
56     {
57       return this->subset_plan->gids_to_retain_sorted.len;
58     }
59
60     inline const HBUINT8& operator [] (unsigned int i) const
61     {
62       if (unlikely (i >= len())) return Null(HBUINT8);
63       hb_codepoint_t gid = this->subset_plan->gids_to_retain_sorted [i];
64       return this->source_device_record->widths[gid];
65     }
66   };
67
68   static inline unsigned int get_size (unsigned int count)
69   {
70     unsigned int raw_size = min_size + count * HBUINT8::static_size;
71     if (raw_size % 4)
72       /* Align to 32 bits */
73       return raw_size + (4 - (raw_size % 4));
74     return raw_size;
75   }
76
77   inline bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
78   {
79     TRACE_SERIALIZE (this);
80
81     if (unlikely (!c->allocate_size<DeviceRecord> (get_size (subset_view.len()))))
82       return_trace (false);
83
84     this->pixel_size.set (subset_view.source_device_record->pixel_size);
85     this->max_width.set (subset_view.source_device_record->max_width);
86
87     for (unsigned int i = 0; i < subset_view.len(); i++)
88       widths[i].set (subset_view[i]);
89
90     return_trace (true);
91   }
92
93   inline bool sanitize (hb_sanitize_context_t *c, unsigned int size_device_record) const
94   {
95     TRACE_SANITIZE (this);
96     return_trace (likely (c->check_struct (this) &&
97                           c->check_range (this, size_device_record)));
98   }
99
100   HBUINT8 pixel_size;   /* Pixel size for following widths (as ppem). */
101   HBUINT8 max_width;    /* Maximum width. */
102   HBUINT8 widths[VAR];  /* Array of widths (numGlyphs is from the 'maxp' table). */
103   public:
104   DEFINE_SIZE_ARRAY (2, widths);
105 };
106
107
108 struct hdmx
109 {
110   static const hb_tag_t tableTag = HB_OT_TAG_hdmx;
111
112   inline unsigned int get_size (void) const
113   {
114     return min_size + num_records * size_device_record;
115   }
116
117   inline const DeviceRecord& operator [] (unsigned int i) const
118   {
119     if (unlikely (i >= num_records)) return Null(DeviceRecord);
120     return StructAtOffset<DeviceRecord> (this, min_size + i * size_device_record);
121   }
122
123   inline bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
124   {
125     TRACE_SERIALIZE (this);
126
127     if (unlikely (!c->extend_min ((*this))))  return_trace (false);
128
129     this->version.set (source_hdmx->version);
130     this->num_records.set (source_hdmx->num_records);
131     this->size_device_record.set (DeviceRecord::get_size (plan->gids_to_retain_sorted.len));
132
133     for (unsigned int i = 0; i < source_hdmx->num_records; i++)
134     {
135       DeviceRecord::SubsetView subset_view;
136       subset_view.init (&(*source_hdmx)[i], plan);
137
138       c->start_embed<DeviceRecord> ()->serialize (c, subset_view);
139     }
140
141     return_trace (true);
142   }
143
144   static inline size_t get_subsetted_size (hb_subset_plan_t *plan)
145   {
146     return min_size + DeviceRecord::get_size (plan->gids_to_retain_sorted.len);
147   }
148
149   inline bool subset (hb_subset_plan_t *plan) const
150   {
151     size_t dest_size = get_subsetted_size (plan);
152     hdmx *dest = (hdmx *) malloc (dest_size);
153     if (unlikely (!dest))
154     {
155       DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size);
156       return false;
157     }
158
159     hb_serialize_context_t c (dest, dest_size);
160     hdmx *hdmx_prime = c.start_serialize<hdmx> ();
161     if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) {
162       free (dest);
163       return false;
164     }
165     c.end_serialize ();
166
167     hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest,
168                                                  dest_size,
169                                                  HB_MEMORY_MODE_READONLY,
170                                                  dest,
171                                                  free);
172     bool result = hb_subset_plan_add_table (plan, HB_OT_TAG_hdmx, hdmx_prime_blob);
173     hb_blob_destroy (hdmx_prime_blob);
174
175     return result;
176   }
177
178   inline bool sanitize (hb_sanitize_context_t *c) const
179   {
180     TRACE_SANITIZE (this);
181     return_trace (c->check_struct (this) && version == 0 &&
182                   !_hb_unsigned_int_mul_overflows (num_records, size_device_record) &&
183                   c->check_range (this, get_size()));
184   }
185
186   protected:
187   HBUINT16      version;                /* Table version number (0) */
188   HBUINT16      num_records;            /* Number of device records. */
189   HBUINT32      size_device_record;     /* Size of a device record, 32-bit aligned. */
190   HBUINT8       data[VAR];              /* Array of device records. */
191   public:
192   DEFINE_SIZE_ARRAY (8, data);
193 };
194
195 } /* namespace OT */
196
197
198 #endif /* HB_OT_HDMX_TABLE_HH */