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 15namespace ots { 16 17bool 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 99bool 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 105bool 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 130void ots_hdmx_free(OpenTypeFile *file) { 131 delete file->hdmx; 132} 133 134} // namespace ots 135