54232
|
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.hh"
|
|
31 |
|
|
32 |
/*
|
|
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 |
|
|
39 |
namespace OT {
|
|
40 |
|
|
41 |
|
|
42 |
struct DeviceRecord
|
|
43 |
{
|
|
44 |
struct SubsetView
|
|
45 |
{
|
|
46 |
const DeviceRecord *source_device_record;
|
|
47 |
unsigned int sizeDeviceRecord;
|
|
48 |
hb_subset_plan_t *subset_plan;
|
|
49 |
|
|
50 |
void init (const DeviceRecord *source_device_record,
|
|
51 |
unsigned int sizeDeviceRecord,
|
|
52 |
hb_subset_plan_t *subset_plan)
|
|
53 |
{
|
|
54 |
this->source_device_record = source_device_record;
|
|
55 |
this->sizeDeviceRecord = sizeDeviceRecord;
|
|
56 |
this->subset_plan = subset_plan;
|
|
57 |
}
|
|
58 |
|
|
59 |
unsigned int len () const
|
|
60 |
{ return this->subset_plan->glyphs.length; }
|
|
61 |
|
|
62 |
const HBUINT8* operator [] (unsigned int i) const
|
|
63 |
{
|
|
64 |
if (unlikely (i >= len ())) return nullptr;
|
|
65 |
hb_codepoint_t gid = this->subset_plan->glyphs [i];
|
|
66 |
|
|
67 |
if (gid >= sizeDeviceRecord - DeviceRecord::min_size)
|
|
68 |
return nullptr;
|
|
69 |
return &(this->source_device_record->widthsZ[gid]);
|
|
70 |
}
|
|
71 |
};
|
|
72 |
|
|
73 |
static unsigned int get_size (unsigned int count)
|
|
74 |
{ return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); }
|
|
75 |
|
|
76 |
bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
|
|
77 |
{
|
|
78 |
TRACE_SERIALIZE (this);
|
|
79 |
|
|
80 |
unsigned int size = get_size (subset_view.len ());
|
|
81 |
if (unlikely (!c->allocate_size<DeviceRecord> (size)))
|
|
82 |
{
|
|
83 |
DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
|
|
84 |
size);
|
|
85 |
return_trace (false);
|
|
86 |
}
|
|
87 |
|
|
88 |
this->pixelSize.set (subset_view.source_device_record->pixelSize);
|
|
89 |
this->maxWidth.set (subset_view.source_device_record->maxWidth);
|
|
90 |
|
|
91 |
for (unsigned int i = 0; i < subset_view.len (); i++)
|
|
92 |
{
|
|
93 |
const HBUINT8 *width = subset_view[i];
|
|
94 |
if (!width)
|
|
95 |
{
|
|
96 |
DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
|
|
97 |
return_trace (false);
|
|
98 |
}
|
|
99 |
widthsZ[i].set (*width);
|
|
100 |
}
|
|
101 |
|
|
102 |
return_trace (true);
|
|
103 |
}
|
|
104 |
|
|
105 |
bool sanitize (hb_sanitize_context_t *c, unsigned int sizeDeviceRecord) const
|
|
106 |
{
|
|
107 |
TRACE_SANITIZE (this);
|
|
108 |
return_trace (likely (c->check_struct (this) &&
|
|
109 |
c->check_range (this, sizeDeviceRecord)));
|
|
110 |
}
|
|
111 |
|
|
112 |
HBUINT8 pixelSize; /* Pixel size for following widths (as ppem). */
|
|
113 |
HBUINT8 maxWidth; /* Maximum width. */
|
|
114 |
UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
|
|
115 |
public:
|
|
116 |
DEFINE_SIZE_ARRAY (2, widthsZ);
|
|
117 |
};
|
|
118 |
|
|
119 |
|
|
120 |
struct hdmx
|
|
121 |
{
|
|
122 |
static constexpr hb_tag_t tableTag = HB_OT_TAG_hdmx;
|
|
123 |
|
|
124 |
unsigned int get_size () const
|
|
125 |
{ return min_size + numRecords * sizeDeviceRecord; }
|
|
126 |
|
|
127 |
const DeviceRecord& operator [] (unsigned int i) const
|
|
128 |
{
|
|
129 |
/* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed.
|
|
130 |
* https://github.com/harfbuzz/harfbuzz/issues/1300 */
|
|
131 |
if (unlikely (i >= numRecords)) return Null (DeviceRecord);
|
|
132 |
return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
|
|
133 |
}
|
|
134 |
|
|
135 |
bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
|
|
136 |
{
|
|
137 |
TRACE_SERIALIZE (this);
|
|
138 |
|
|
139 |
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
|
|
140 |
|
|
141 |
this->version.set (source_hdmx->version);
|
|
142 |
this->numRecords.set (source_hdmx->numRecords);
|
|
143 |
this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->glyphs.length));
|
|
144 |
|
|
145 |
for (unsigned int i = 0; i < source_hdmx->numRecords; i++)
|
|
146 |
{
|
|
147 |
DeviceRecord::SubsetView subset_view;
|
|
148 |
subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan);
|
|
149 |
|
|
150 |
if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view))
|
|
151 |
return_trace (false);
|
|
152 |
}
|
|
153 |
|
|
154 |
return_trace (true);
|
|
155 |
}
|
|
156 |
|
|
157 |
static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
|
|
158 |
{
|
|
159 |
return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->glyphs.length);
|
|
160 |
}
|
|
161 |
|
|
162 |
bool subset (hb_subset_plan_t *plan) const
|
|
163 |
{
|
|
164 |
size_t dest_size = get_subsetted_size (this, plan);
|
|
165 |
hdmx *dest = (hdmx *) malloc (dest_size);
|
|
166 |
if (unlikely (!dest))
|
|
167 |
{
|
|
168 |
DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size);
|
|
169 |
return false;
|
|
170 |
}
|
|
171 |
|
|
172 |
hb_serialize_context_t c (dest, dest_size);
|
|
173 |
hdmx *hdmx_prime = c.start_serialize<hdmx> ();
|
|
174 |
if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
|
|
175 |
{
|
|
176 |
free (dest);
|
|
177 |
DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
|
|
178 |
return false;
|
|
179 |
}
|
|
180 |
c.end_serialize ();
|
|
181 |
|
|
182 |
hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest,
|
|
183 |
dest_size,
|
|
184 |
HB_MEMORY_MODE_READONLY,
|
|
185 |
dest,
|
|
186 |
free);
|
|
187 |
bool result = plan->add_table (HB_OT_TAG_hdmx, hdmx_prime_blob);
|
|
188 |
hb_blob_destroy (hdmx_prime_blob);
|
|
189 |
|
|
190 |
return result;
|
|
191 |
}
|
|
192 |
|
|
193 |
bool sanitize (hb_sanitize_context_t *c) const
|
|
194 |
{
|
|
195 |
TRACE_SANITIZE (this);
|
|
196 |
return_trace (c->check_struct (this) &&
|
|
197 |
!hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) &&
|
|
198 |
sizeDeviceRecord >= DeviceRecord::min_size &&
|
|
199 |
c->check_range (this, get_size ()));
|
|
200 |
}
|
|
201 |
|
|
202 |
protected:
|
|
203 |
HBUINT16 version; /* Table version number (0) */
|
|
204 |
HBUINT16 numRecords; /* Number of device records. */
|
|
205 |
HBUINT32 sizeDeviceRecord; /* Size of a device record, 32-bit aligned. */
|
|
206 |
DeviceRecord firstDeviceRecord; /* Array of device records. */
|
|
207 |
public:
|
|
208 |
DEFINE_SIZE_MIN (8);
|
|
209 |
};
|
|
210 |
|
|
211 |
} /* namespace OT */
|
|
212 |
|
|
213 |
|
|
214 |
#endif /* HB_OT_HDMX_TABLE_HH */
|