blob: 04511b5d09e66e17b4d7961d9dff3d138ae3fd5b [file] [log] [blame]
Garret Riegerfe428622018-02-21 14:18:49 -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
27#ifndef HB_OT_HDMX_TABLE_HH
28#define HB_OT_HDMX_TABLE_HH
29
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070030#include "hb-open-type.hh"
Garret Riegerfe428622018-02-21 14:18:49 -080031
Ebrahim Byagowia02c3ee2018-04-12 13:38:19 +043032/*
33 * hdmx -- Horizontal Device Metrics
34 * https://docs.microsoft.com/en-us/typography/opentype/spec/hdmx
35 */
36#define HB_OT_TAG_hdmx HB_TAG('h','d','m','x')
37
38
Garret Riegerfe428622018-02-21 14:18:49 -080039namespace OT {
40
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080041
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080042struct DeviceRecord
43{
44 struct SubsetView
45 {
46 const DeviceRecord *source_device_record;
Garret Rieger3531efd2018-03-20 16:31:21 -070047 unsigned int size_device_record;
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080048 hb_subset_plan_t *subset_plan;
49
50 inline void init(const DeviceRecord *source_device_record,
Garret Rieger3531efd2018-03-20 16:31:21 -070051 unsigned int size_device_record,
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080052 hb_subset_plan_t *subset_plan)
53 {
54 this->source_device_record = source_device_record;
Garret Rieger3531efd2018-03-20 16:31:21 -070055 this->size_device_record = size_device_record;
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080056 this->subset_plan = subset_plan;
57 }
58
59 inline unsigned int len () const
60 {
Garret Rieger251cc972018-05-30 12:23:51 -070061 return this->subset_plan->glyphs.len;
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080062 }
63
Garret Rieger3531efd2018-03-20 16:31:21 -070064 inline const HBUINT8* operator [] (unsigned int i) const
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080065 {
Garret Rieger3531efd2018-03-20 16:31:21 -070066 if (unlikely (i >= len())) return nullptr;
Garret Rieger251cc972018-05-30 12:23:51 -070067 hb_codepoint_t gid = this->subset_plan->glyphs [i];
Garret Rieger3531efd2018-03-20 16:31:21 -070068
Behdad Esfahboddff2c452018-09-10 23:29:26 +020069 const HBUINT8* width = &(this->source_device_record->widthsZ[gid]);
Garret Rieger3531efd2018-03-20 16:31:21 -070070
71 if (width < ((const HBUINT8 *) this->source_device_record) + size_device_record)
72 return width;
73 else
74 return nullptr;
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080075 }
76 };
77
78 static inline unsigned int get_size (unsigned int count)
79 {
Behdad Esfahboddff2c452018-09-10 23:29:26 +020080 return hb_ceil_to_4 (min_size + count * HBUINT8::static_size);
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080081 }
82
83 inline bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
84 {
85 TRACE_SERIALIZE (this);
86
Garret Rieger21bf1472018-09-05 18:04:52 -070087 unsigned int size = get_size (subset_view.len());
88 if (unlikely (!c->allocate_size<DeviceRecord> (size)))
89 {
90 DEBUG_MSG (SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
91 size);
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080092 return_trace (false);
Garret Rieger21bf1472018-09-05 18:04:52 -070093 }
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -080094
95 this->pixel_size.set (subset_view.source_device_record->pixel_size);
96 this->max_width.set (subset_view.source_device_record->max_width);
97
98 for (unsigned int i = 0; i < subset_view.len(); i++)
Garret Rieger3531efd2018-03-20 16:31:21 -070099 {
100 const HBUINT8 *width = subset_view[i];
101 if (!width)
102 {
103 DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
104 return_trace (false);
105 }
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200106 widthsZ[i].set (*width);
Garret Rieger3531efd2018-03-20 16:31:21 -0700107 }
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -0800108
109 return_trace (true);
110 }
111
112 inline bool sanitize (hb_sanitize_context_t *c, unsigned int size_device_record) const
113 {
114 TRACE_SANITIZE (this);
115 return_trace (likely (c->check_struct (this) &&
116 c->check_range (this, size_device_record)));
117 }
118
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200119 HBUINT8 pixel_size; /* Pixel size for following widths (as ppem). */
120 HBUINT8 max_width; /* Maximum width. */
121 UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
Behdad Esfahbod84d4bb92018-02-23 10:38:35 -0800122 public:
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200123 DEFINE_SIZE_ARRAY (2, widthsZ);
Behdad Esfahbodcf7a6e52018-02-23 10:34:26 -0800124};
125
126
Garret Riegerfe428622018-02-21 14:18:49 -0800127struct hdmx
128{
Garret Rieger6b372f42018-02-22 12:00:00 -0800129 static const hb_tag_t tableTag = HB_OT_TAG_hdmx;
Garret Riegerbd18b6a2018-02-21 17:42:58 -0800130
Garret Riegerfe428622018-02-21 14:18:49 -0800131 inline unsigned int get_size (void) const
132 {
133 return min_size + num_records * size_device_record;
134 }
135
136 inline const DeviceRecord& operator [] (unsigned int i) const
137 {
138 if (unlikely (i >= num_records)) return Null(DeviceRecord);
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200139 return StructAtOffset<DeviceRecord> (&this->dataZ, i * size_device_record);
Garret Riegerfe428622018-02-21 14:18:49 -0800140 }
141
Garret Riegerab7a8f32018-02-21 15:15:22 -0800142 inline bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
143 {
144 TRACE_SERIALIZE (this);
145
146 if (unlikely (!c->extend_min ((*this)))) return_trace (false);
147
148 this->version.set (source_hdmx->version);
149 this->num_records.set (source_hdmx->num_records);
Garret Rieger251cc972018-05-30 12:23:51 -0700150 this->size_device_record.set (DeviceRecord::get_size (plan->glyphs.len));
Garret Riegerab7a8f32018-02-21 15:15:22 -0800151
152 for (unsigned int i = 0; i < source_hdmx->num_records; i++)
153 {
154 DeviceRecord::SubsetView subset_view;
Garret Rieger3531efd2018-03-20 16:31:21 -0700155 subset_view.init (&(*source_hdmx)[i], source_hdmx->size_device_record, plan);
Garret Riegerab7a8f32018-02-21 15:15:22 -0800156
Garret Rieger3531efd2018-03-20 16:31:21 -0700157 if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view))
158 return_trace (false);
Garret Riegerab7a8f32018-02-21 15:15:22 -0800159 }
160
161 return_trace (true);
162 }
163
Garret Rieger21bf1472018-09-05 18:04:52 -0700164 static inline size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
Garret Rieger84b68e52018-02-21 15:43:47 -0800165 {
Garret Rieger21bf1472018-09-05 18:04:52 -0700166 return min_size + source_hdmx->num_records * DeviceRecord::get_size (plan->glyphs.len);
Garret Rieger84b68e52018-02-21 15:43:47 -0800167 }
168
Garret Riegerab7a8f32018-02-21 15:15:22 -0800169 inline bool subset (hb_subset_plan_t *plan) const
170 {
Garret Rieger21bf1472018-09-05 18:04:52 -0700171 size_t dest_size = get_subsetted_size (this, plan);
Garret Rieger6704cde2018-02-21 16:00:10 -0800172 hdmx *dest = (hdmx *) malloc (dest_size);
173 if (unlikely (!dest))
174 {
175 DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size);
176 return false;
177 }
178
179 hb_serialize_context_t c (dest, dest_size);
180 hdmx *hdmx_prime = c.start_serialize<hdmx> ();
Behdad Esfahboda1e5e072018-09-05 16:24:28 -0700181 if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
182 {
Garret Rieger6704cde2018-02-21 16:00:10 -0800183 free (dest);
Garret Rieger21bf1472018-09-05 18:04:52 -0700184 DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
Garret Rieger6704cde2018-02-21 16:00:10 -0800185 return false;
186 }
187 c.end_serialize ();
188
189 hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest,
Behdad Esfahbod84d4bb92018-02-23 10:38:35 -0800190 dest_size,
191 HB_MEMORY_MODE_READONLY,
192 dest,
193 free);
Garret Rieger251cc972018-05-30 12:23:51 -0700194 bool result = plan->add_table (HB_OT_TAG_hdmx, hdmx_prime_blob);
Garret Rieger6704cde2018-02-21 16:00:10 -0800195 hb_blob_destroy (hdmx_prime_blob);
196
197 return result;
Garret Riegerab7a8f32018-02-21 15:15:22 -0800198 }
199
Garret Riegerfe428622018-02-21 14:18:49 -0800200 inline bool sanitize (hb_sanitize_context_t *c) const
201 {
202 TRACE_SANITIZE (this);
Behdad Esfahbodc2e47132018-02-23 10:45:03 -0800203 return_trace (c->check_struct (this) && version == 0 &&
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +0200204 !hb_unsigned_mul_overflows (num_records, size_device_record) &&
Garret Rieger07851aa2018-03-26 20:56:56 -0600205 size_device_record >= DeviceRecord::min_size &&
Behdad Esfahbodc2e47132018-02-23 10:45:03 -0800206 c->check_range (this, get_size()));
Garret Riegerfe428622018-02-21 14:18:49 -0800207 }
208
Behdad Esfahbodc2e47132018-02-23 10:45:03 -0800209 protected:
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200210 HBUINT16 version; /* Table version number (0) */
211 HBUINT16 num_records; /* Number of device records. */
212 HBUINT32 size_device_record; /* Size of a device record, 32-bit aligned. */
213 UnsizedArrayOf<HBUINT8> dataZ; /* Array of device records. */
Behdad Esfahbodc2e47132018-02-23 10:45:03 -0800214 public:
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200215 DEFINE_SIZE_ARRAY (8, dataZ);
Garret Riegerfe428622018-02-21 14:18:49 -0800216};
217
218} /* namespace OT */
219
220
221#endif /* HB_OT_HDMX_TABLE_HH */