michael@0: // Copyright (c) 2009 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "head.h" michael@0: michael@0: #include michael@0: michael@0: // head - Font Header michael@0: // http://www.microsoft.com/typography/otspec/head.htm michael@0: michael@0: #define TABLE_NAME "head" michael@0: michael@0: namespace ots { michael@0: michael@0: bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { michael@0: Buffer table(data, length); michael@0: file->head = new OpenTypeHEAD; michael@0: michael@0: uint32_t version = 0; michael@0: if (!table.ReadU32(&version) || michael@0: !table.ReadU32(&file->head->revision)) { michael@0: return OTS_FAILURE_MSG("Failed to read head header"); michael@0: } michael@0: michael@0: if (version >> 16 != 1) { michael@0: return OTS_FAILURE_MSG("Bad head table version of %d", version); michael@0: } michael@0: michael@0: // Skip the checksum adjustment michael@0: if (!table.Skip(4)) { michael@0: return OTS_FAILURE_MSG("Failed to read checksum"); michael@0: } michael@0: michael@0: uint32_t magic; michael@0: if (!table.ReadTag(&magic) || michael@0: std::memcmp(&magic, "\x5F\x0F\x3C\xF5", 4)) { michael@0: return OTS_FAILURE_MSG("Failed to read font magic number"); michael@0: } michael@0: michael@0: if (!table.ReadU16(&file->head->flags)) { michael@0: return OTS_FAILURE_MSG("Failed to read head flags"); michael@0: } michael@0: michael@0: // We allow bits 0..4, 11..13 michael@0: file->head->flags &= 0x381f; michael@0: michael@0: if (!table.ReadU16(&file->head->ppem)) { michael@0: return OTS_FAILURE_MSG("Failed to read pixels per em"); michael@0: } michael@0: michael@0: // ppem must be in range michael@0: if (file->head->ppem < 16 || michael@0: file->head->ppem > 16384) { michael@0: return OTS_FAILURE_MSG("Bad ppm of %d", file->head->ppem); michael@0: } michael@0: michael@0: // ppem must be a power of two michael@0: #if 0 michael@0: // We don't call ots_failure() for now since lots of TrueType fonts are michael@0: // not following this rule. Putting OTS_WARNING here is too noisy. michael@0: if ((file->head->ppem - 1) & file->head->ppem) { michael@0: return OTS_FAILURE_MSG("ppm not a power of two: %d", file->head->ppem); michael@0: } michael@0: #endif michael@0: michael@0: if (!table.ReadR64(&file->head->created) || michael@0: !table.ReadR64(&file->head->modified)) { michael@0: return OTS_FAILURE_MSG("Can't read font dates"); michael@0: } michael@0: michael@0: if (!table.ReadS16(&file->head->xmin) || michael@0: !table.ReadS16(&file->head->ymin) || michael@0: !table.ReadS16(&file->head->xmax) || michael@0: !table.ReadS16(&file->head->ymax)) { michael@0: return OTS_FAILURE_MSG("Failed to read font bounding box"); michael@0: } michael@0: michael@0: if (file->head->xmin > file->head->xmax) { michael@0: return OTS_FAILURE_MSG("Bad x dimension in the font bounding box (%d, %d)", file->head->xmin, file->head->xmax); michael@0: } michael@0: if (file->head->ymin > file->head->ymax) { michael@0: return OTS_FAILURE_MSG("Bad y dimension in the font bounding box (%d, %d)", file->head->ymin, file->head->ymax); michael@0: } michael@0: michael@0: if (!table.ReadU16(&file->head->mac_style)) { michael@0: return OTS_FAILURE_MSG("Failed to read font style"); michael@0: } michael@0: michael@0: // We allow bits 0..6 michael@0: file->head->mac_style &= 0x7f; michael@0: michael@0: if (!table.ReadU16(&file->head->min_ppem)) { michael@0: return OTS_FAILURE_MSG("Failed to read font minimum ppm"); michael@0: } michael@0: michael@0: // We don't care about the font direction hint michael@0: if (!table.Skip(2)) { michael@0: return OTS_FAILURE_MSG("Failed to skip font direction hint"); michael@0: } michael@0: michael@0: if (!table.ReadS16(&file->head->index_to_loc_format)) { michael@0: return OTS_FAILURE_MSG("Failed to read index to loc format"); michael@0: } michael@0: if (file->head->index_to_loc_format < 0 || michael@0: file->head->index_to_loc_format > 1) { michael@0: return OTS_FAILURE_MSG("Bad index to loc format %d", file->head->index_to_loc_format); michael@0: } michael@0: michael@0: int16_t glyph_data_format; michael@0: if (!table.ReadS16(&glyph_data_format) || michael@0: glyph_data_format) { michael@0: return OTS_FAILURE_MSG("Failed to read glyph data format"); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool ots_head_should_serialise(OpenTypeFile *file) { michael@0: return file->head != NULL; michael@0: } michael@0: michael@0: bool ots_head_serialise(OTSStream *out, OpenTypeFile *file) { michael@0: if (!out->WriteU32(0x00010000) || michael@0: !out->WriteU32(file->head->revision) || michael@0: !out->WriteU32(0) || // check sum not filled in yet michael@0: !out->WriteU32(0x5F0F3CF5) || michael@0: !out->WriteU16(file->head->flags) || michael@0: !out->WriteU16(file->head->ppem) || michael@0: !out->WriteR64(file->head->created) || michael@0: !out->WriteR64(file->head->modified) || michael@0: !out->WriteS16(file->head->xmin) || michael@0: !out->WriteS16(file->head->ymin) || michael@0: !out->WriteS16(file->head->xmax) || michael@0: !out->WriteS16(file->head->ymax) || michael@0: !out->WriteU16(file->head->mac_style) || michael@0: !out->WriteU16(file->head->min_ppem) || michael@0: !out->WriteS16(2) || michael@0: !out->WriteS16(file->head->index_to_loc_format) || michael@0: !out->WriteS16(0)) { michael@0: return OTS_FAILURE_MSG("Failed to write head table"); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void ots_head_free(OpenTypeFile *file) { michael@0: delete file->head; michael@0: } michael@0: michael@0: } // namespace