1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/ots/src/hdmx.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,140 @@ 1.4 +// Copyright (c) 2009 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "hdmx.h" 1.9 +#include "head.h" 1.10 +#include "maxp.h" 1.11 + 1.12 +// hdmx - Horizontal Device Metrics 1.13 +// http://www.microsoft.com/typography/otspec/hdmx.htm 1.14 + 1.15 +#define TABLE_NAME "hdmx" 1.16 + 1.17 +#define DROP_THIS_TABLE \ 1.18 + do { \ 1.19 + delete file->hdmx; \ 1.20 + file->hdmx = 0; \ 1.21 + OTS_FAILURE_MSG("Table discarded"); \ 1.22 + } while (0) 1.23 + 1.24 +namespace ots { 1.25 + 1.26 +bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { 1.27 + Buffer table(data, length); 1.28 + file->hdmx = new OpenTypeHDMX; 1.29 + OpenTypeHDMX * const hdmx = file->hdmx; 1.30 + 1.31 + if (!file->head || !file->maxp) { 1.32 + return OTS_FAILURE_MSG("Missing maxp or head tables in font, needed by hdmx"); 1.33 + } 1.34 + 1.35 + if ((file->head->flags & 0x14) == 0) { 1.36 + // http://www.microsoft.com/typography/otspec/recom.htm 1.37 + OTS_WARNING("the table should not be present when bit 2 and 4 of the " 1.38 + "head->flags are not set"); 1.39 + DROP_THIS_TABLE; 1.40 + return true; 1.41 + } 1.42 + 1.43 + int16_t num_recs; 1.44 + if (!table.ReadU16(&hdmx->version) || 1.45 + !table.ReadS16(&num_recs) || 1.46 + !table.ReadS32(&hdmx->size_device_record)) { 1.47 + return OTS_FAILURE_MSG("Failed to read hdmx header"); 1.48 + } 1.49 + if (hdmx->version != 0) { 1.50 + OTS_WARNING("bad version: %u", hdmx->version); 1.51 + DROP_THIS_TABLE; 1.52 + return true; 1.53 + } 1.54 + if (num_recs <= 0) { 1.55 + OTS_WARNING("bad num_recs: %d", num_recs); 1.56 + DROP_THIS_TABLE; 1.57 + return true; 1.58 + } 1.59 + const int32_t actual_size_device_record = file->maxp->num_glyphs + 2; 1.60 + if (hdmx->size_device_record < actual_size_device_record) { 1.61 + OTS_WARNING("bad hdmx->size_device_record: %d", hdmx->size_device_record); 1.62 + DROP_THIS_TABLE; 1.63 + return true; 1.64 + } 1.65 + 1.66 + hdmx->pad_len = hdmx->size_device_record - actual_size_device_record; 1.67 + if (hdmx->pad_len > 3) { 1.68 + return OTS_FAILURE_MSG("Bad padding %d", hdmx->pad_len); 1.69 + } 1.70 + 1.71 + uint8_t last_pixel_size = 0; 1.72 + hdmx->records.reserve(num_recs); 1.73 + for (int i = 0; i < num_recs; ++i) { 1.74 + OpenTypeHDMXDeviceRecord rec; 1.75 + 1.76 + if (!table.ReadU8(&rec.pixel_size) || 1.77 + !table.ReadU8(&rec.max_width)) { 1.78 + return OTS_FAILURE_MSG("Failed to read hdmx record %d", i); 1.79 + } 1.80 + if ((i != 0) && 1.81 + (rec.pixel_size <= last_pixel_size)) { 1.82 + OTS_WARNING("records are not sorted"); 1.83 + DROP_THIS_TABLE; 1.84 + return true; 1.85 + } 1.86 + last_pixel_size = rec.pixel_size; 1.87 + 1.88 + rec.widths.reserve(file->maxp->num_glyphs); 1.89 + for (unsigned j = 0; j < file->maxp->num_glyphs; ++j) { 1.90 + uint8_t width; 1.91 + if (!table.ReadU8(&width)) { 1.92 + return OTS_FAILURE_MSG("Failed to read glyph width %d in record %d", j, i); 1.93 + } 1.94 + rec.widths.push_back(width); 1.95 + } 1.96 + 1.97 + if ((hdmx->pad_len > 0) && 1.98 + !table.Skip(hdmx->pad_len)) { 1.99 + return OTS_FAILURE_MSG("Failed to skip padding %d", hdmx->pad_len); 1.100 + } 1.101 + 1.102 + hdmx->records.push_back(rec); 1.103 + } 1.104 + 1.105 + return true; 1.106 +} 1.107 + 1.108 +bool ots_hdmx_should_serialise(OpenTypeFile *file) { 1.109 + if (!file->hdmx) return false; 1.110 + if (!file->glyf) return false; // this table is not for CFF fonts. 1.111 + return true; 1.112 +} 1.113 + 1.114 +bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) { 1.115 + OpenTypeHDMX * const hdmx = file->hdmx; 1.116 + 1.117 + if (!out->WriteU16(hdmx->version) || 1.118 + !out->WriteS16(hdmx->records.size()) || 1.119 + !out->WriteS32(hdmx->size_device_record)) { 1.120 + return OTS_FAILURE_MSG("Failed to write hdmx header"); 1.121 + } 1.122 + 1.123 + for (unsigned i = 0; i < hdmx->records.size(); ++i) { 1.124 + const OpenTypeHDMXDeviceRecord& rec = hdmx->records[i]; 1.125 + if (!out->Write(&rec.pixel_size, 1) || 1.126 + !out->Write(&rec.max_width, 1) || 1.127 + !out->Write(&rec.widths[0], rec.widths.size())) { 1.128 + return OTS_FAILURE_MSG("Failed to write hdmx record %d", i); 1.129 + } 1.130 + if ((hdmx->pad_len > 0) && 1.131 + !out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) { 1.132 + return OTS_FAILURE_MSG("Failed to write hdmx padding of length %d", hdmx->pad_len); 1.133 + } 1.134 + } 1.135 + 1.136 + return true; 1.137 +} 1.138 + 1.139 +void ots_hdmx_free(OpenTypeFile *file) { 1.140 + delete file->hdmx; 1.141 +} 1.142 + 1.143 +} // namespace ots