• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "hdmx.h"
6 #include "head.h"
7 #include "maxp.h"
8 
9 // hdmx - Horizontal Device Metrics
10 // http://www.microsoft.com/opentype/otspec/hdmx.htm
11 
12 #define DROP_THIS_TABLE \
13   do { delete file->hdmx; file->hdmx = 0; } while (0)
14 
15 namespace ots {
16 
ots_hdmx_parse(OpenTypeFile * file,const uint8_t * data,size_t length)17 bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
18   Buffer table(data, length);
19   file->hdmx = new OpenTypeHDMX;
20   OpenTypeHDMX * const hdmx = file->hdmx;
21 
22   if (!file->head || !file->maxp) {
23     return OTS_FAILURE();
24   }
25 
26   if ((file->head->flags & 0x14) == 0) {
27     // http://www.microsoft.com/typography/otspec/recom.htm
28     OTS_WARNING("the table should not be present when bit 2 and 4 of the "
29                 "head->flags are not set");
30     DROP_THIS_TABLE;
31     return true;
32   }
33 
34   int16_t num_recs;
35   if (!table.ReadU16(&hdmx->version) ||
36       !table.ReadS16(&num_recs) ||
37       !table.ReadS32(&hdmx->size_device_record)) {
38     return OTS_FAILURE();
39   }
40   if (hdmx->version != 0) {
41     OTS_WARNING("bad version: %u", hdmx->version);
42     DROP_THIS_TABLE;
43     return true;
44   }
45   if (num_recs <= 0) {
46     OTS_WARNING("bad num_recs: %d", num_recs);
47     DROP_THIS_TABLE;
48     return true;
49   }
50   const int32_t actual_size_device_record = file->maxp->num_glyphs + 2;
51   if (hdmx->size_device_record < actual_size_device_record) {
52     OTS_WARNING("bad hdmx->size_device_record: %d", hdmx->size_device_record);
53     DROP_THIS_TABLE;
54     return true;
55   }
56 
57   hdmx->pad_len = hdmx->size_device_record - actual_size_device_record;
58   if (hdmx->pad_len > 3) {
59     return OTS_FAILURE();
60   }
61 
62   uint8_t last_pixel_size = 0;
63   hdmx->records.reserve(num_recs);
64   for (int i = 0; i < num_recs; ++i) {
65     OpenTypeHDMXDeviceRecord rec;
66 
67     if (!table.ReadU8(&rec.pixel_size) ||
68         !table.ReadU8(&rec.max_width)) {
69       return OTS_FAILURE();
70     }
71     if ((i != 0) &&
72         (rec.pixel_size <= last_pixel_size)) {
73       OTS_WARNING("records are not sorted");
74       DROP_THIS_TABLE;
75       return true;
76     }
77     last_pixel_size = rec.pixel_size;
78 
79     rec.widths.reserve(file->maxp->num_glyphs);
80     for (unsigned j = 0; j < file->maxp->num_glyphs; ++j) {
81       uint8_t width;
82       if (!table.ReadU8(&width)) {
83         return OTS_FAILURE();
84       }
85       rec.widths.push_back(width);
86     }
87 
88     if ((hdmx->pad_len > 0) &&
89         !table.Skip(hdmx->pad_len)) {
90       return OTS_FAILURE();
91     }
92 
93     hdmx->records.push_back(rec);
94   }
95 
96   return true;
97 }
98 
ots_hdmx_should_serialise(OpenTypeFile * file)99 bool ots_hdmx_should_serialise(OpenTypeFile *file) {
100   if (!file->hdmx) return false;
101   if (!file->glyf) return false;  // this table is not for CFF fonts.
102   return true;
103 }
104 
ots_hdmx_serialise(OTSStream * out,OpenTypeFile * file)105 bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
106   OpenTypeHDMX * const hdmx = file->hdmx;
107 
108   if (!out->WriteU16(hdmx->version) ||
109       !out->WriteS16(hdmx->records.size()) ||
110       !out->WriteS32(hdmx->size_device_record)) {
111     return OTS_FAILURE();
112   }
113 
114   for (unsigned i = 0; i < hdmx->records.size(); ++i) {
115     const OpenTypeHDMXDeviceRecord& rec = hdmx->records[i];
116     if (!out->Write(&rec.pixel_size, 1) ||
117         !out->Write(&rec.max_width, 1) ||
118         !out->Write(&rec.widths[0], rec.widths.size())) {
119       return OTS_FAILURE();
120     }
121     if ((hdmx->pad_len > 0) &&
122         !out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) {
123       return OTS_FAILURE();
124     }
125   }
126 
127   return true;
128 }
129 
ots_hdmx_free(OpenTypeFile * file)130 void ots_hdmx_free(OpenTypeFile *file) {
131   delete file->hdmx;
132 }
133 
134 }  // namespace ots
135