1e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Use of this source code is governed by a BSD-style license that can be 3e9629bad30a9f478b336ab46b8e6e02f7f87af46Evan Chu// found in the LICENSE file. 4e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 5e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project#include "gpos.h" 6e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 7e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project#include <limits> 8e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project#include <vector> 9e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 10e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project#include "gdef.h" 11e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project#include "gsub.h" 12e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project#include "layout.h" 13e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project#include "maxp.h" 14e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 15e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// GPOS - The Glyph Positioning Table 16e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// http://www.microsoft.com/typography/otspec/gpos.htm 17e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 18e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectnamespace { 195c65c3a0f42e174e47fecd4e569606003217ff4eMartijn Coenen 20e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectenum GPOS_TYPE { 21e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_SINGLE_ADJUSTMENT = 1, 22e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_PAIR_ADJUSTMENT = 2, 23e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_CURSIVE_ATTACHMENT = 3, 24e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_MARK_TO_BASE_ATTACHMENT = 4, 25e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT = 5, 26e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_MARK_TO_MARK_ATTACHMENT = 6, 27e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_CONTEXT_POSITIONING = 7, 28e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_CHAINED_CONTEXT_POSITIONING = 8, 29e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_EXTENSION_POSITIONING = 9, 30e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_RESERVED = 10 31e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project}; 32e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 33e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// The size of gpos header. 34e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectconst unsigned kGposHeaderSize = 10; 35e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// The maximum format number for anchor tables. 36e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectconst uint16_t kMaxAnchorFormat = 3; 37e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// The maximum number of class value. 38e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectconst uint16_t kMaxClassDefValue = 0xFFFF; 39e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 40e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup type parsers. 41e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseSingleAdjustment(const ots::OpenTypeFile *file, 42e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 43e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParsePairAdjustment(const ots::OpenTypeFile *file, 44e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 45e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseCursiveAttachment(const ots::OpenTypeFile *file, 46e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 47e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseMarkToBaseAttachment(const ots::OpenTypeFile *file, 48e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 49e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseMarkToLigatureAttachment(const ots::OpenTypeFile *file, 50e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 51e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file, 52e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 53e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseContextPositioning(const ots::OpenTypeFile *file, 54e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 55e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseChainedContextPositioning(const ots::OpenTypeFile *file, 56e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 57e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseExtensionPositioning(const ots::OpenTypeFile *file, 58e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length); 59e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 60e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectconst ots::LookupSubtableParser::TypeParser kGposTypeParsers[] = { 61e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_SINGLE_ADJUSTMENT, ParseSingleAdjustment}, 62e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_PAIR_ADJUSTMENT, ParsePairAdjustment}, 63e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_CURSIVE_ATTACHMENT, ParseCursiveAttachment}, 64e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_MARK_TO_BASE_ATTACHMENT, ParseMarkToBaseAttachment}, 65e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT, ParseMarkToLigatureAttachment}, 66e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_MARK_TO_MARK_ATTACHMENT, ParseMarkToMarkAttachment}, 67e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_CONTEXT_POSITIONING, ParseContextPositioning}, 68e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_CHAINED_CONTEXT_POSITIONING, ParseChainedContextPositioning}, 69e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project {GPOS_TYPE_EXTENSION_POSITIONING, ParseExtensionPositioning} 70e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project}; 71e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 72e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectconst ots::LookupSubtableParser kGposLookupSubtableParser = { 73e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project arraysize(kGposTypeParsers), 74e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_EXTENSION_POSITIONING, kGposTypeParsers 75e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project}; 76e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 77e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Shared Tables: ValueRecord, Anchor Table, and MarkArray 78e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 79e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseValueRecord(ots::Buffer* subtable, const uint8_t *data, 80e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const size_t length, const uint16_t value_format) { 81e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Check existence of adjustment fields. 82e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < 4; ++i) { 83e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if ((value_format >> i) & 0x1) { 84e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Just read the field since these fileds could take an arbitrary values. 85e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable->Skip(2)) { 86e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 87e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 88e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 89e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 90e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 91e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Check existence of offsets to device table. 92e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < 4; ++i) { 93e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if ((value_format >> (i + 4)) & 0x1) { 94e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset = 0; 95e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable->ReadU16(&offset)) { 96e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 97e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 98e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset) { 99e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // TODO(bashi): Is it possible that device tables locate before 100e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // this record? No fonts contain such offset AKAIF. 101e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset >= length) { 102e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 103e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 104e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseDeviceTable(data + offset, length - offset)) { 105e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 106e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 107e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 108e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 109e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 110e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 111e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 112e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 113e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseAnchorTable(const uint8_t *data, const size_t length) { 114e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 115e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 116e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t format = 0; 117e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Read format and skip 2 2-byte fields that could be arbitrary values. 118e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&format) || 119e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.Skip(4)) { 120e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 121e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 122e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 123e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (format == 0 || format > kMaxAnchorFormat) { 124e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 125e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 126e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 127e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Format 2 and 3 has additional fields. 128e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (format == 2) { 129e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Format 2 provides an index to a glyph contour point, which will take 130e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // arbitrary value. 131e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t anchor_point = 0; 132e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&anchor_point)) { 133e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 134e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 135e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } else if (format == 3) { 136e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_x_device = 0; 137e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_y_device = 0; 138e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&offset_x_device) || 139e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_y_device)) { 140e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 141e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 142e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const unsigned format_end = static_cast<unsigned>(10); 143e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_x_device) { 144e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_x_device < format_end || offset_x_device >= length) { 145e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 146e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 147e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseDeviceTable(data + offset_x_device, 148e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_x_device)) { 149e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 150e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 151e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 152e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_y_device) { 153e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_y_device < format_end || offset_y_device >= length) { 154e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 155e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 156e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseDeviceTable(data + offset_y_device, 157e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_y_device)) { 158e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 159e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 160e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 161e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 162e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 163e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 164e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 165e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseMarkArrayTable(const uint8_t *data, const size_t length, 166e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t class_count) { 167e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 168e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 169e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t mark_count = 0; 170e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&mark_count)) { 171e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 172e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 173e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 174e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // MarkRecord consists of 4-bytes. 175e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const unsigned mark_records_end = 4 * static_cast<unsigned>(mark_count) + 2; 176e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (mark_records_end > std::numeric_limits<uint16_t>::max()) { 177e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 178e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 179e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < mark_count; ++i) { 180e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t class_value = 0; 181e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_mark_anchor = 0; 182e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&class_value) || 183e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_mark_anchor)) { 184e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 185e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 186e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // |class_value| may take arbitrary values including 0 here so we don't 187e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // check the value. 188e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_mark_anchor < mark_records_end || 189e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project offset_mark_anchor >= length) { 190e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 191e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 192e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseAnchorTable(data + offset_mark_anchor, 193e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_mark_anchor)) { 194e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 195e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 196e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 197e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 198e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 199e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 200e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 201e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup Type 1: 202e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Single Adjustment Positioning Subtable 203e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseSingleAdjustment(const ots::OpenTypeFile *file, const uint8_t *data, 204e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const size_t length) { 205e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 206e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 207e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t format = 0; 208e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_coverage = 0; 209e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t value_format = 0; 210e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&format) || 211e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_coverage) || 212e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&value_format)) { 213e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 214e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 215e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 216e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (format == 1) { 217e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Format 1 exactly one value record. 218e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseValueRecord(&subtable, data, length, value_format)) { 219e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 220e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 221e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } else if (format == 2) { 222e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t value_count = 0; 223e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&value_count)) { 224e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 225e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 226a24be4f06674b2707b57904deaa0dff5a95823bdEvan Chu for (unsigned i = 0; i < value_count; ++i) { 227e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseValueRecord(&subtable, data, length, value_format)) { 228e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 229e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 230e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 231e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } else { 232e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 233e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 234e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 235e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_coverage < subtable.offset() || offset_coverage >= length) { 236e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 237e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 238e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 239e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseCoverageTable(data + offset_coverage, 240e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_coverage, 241e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project file->maxp->num_glyphs)) { 242e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 243e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 244e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 245e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 246e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 247e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 248e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParsePairSetTable(const uint8_t *data, const size_t length, 249e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t value_format1, 250e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t value_format2, 251e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t num_glyphs) { 252e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 253e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 254e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t value_count = 0; 255e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&value_count)) { 256e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 257e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 258e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < value_count; ++i) { 259e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Check pair value record. 260e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t glyph_id = 0; 261e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&glyph_id)) { 262e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 263e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 264e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (glyph_id >= num_glyphs) { 265e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 266e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 267e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseValueRecord(&subtable, data, length, value_format1)) { 268e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 269e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 270e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseValueRecord(&subtable, data, length, value_format2)) { 271e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 272e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 273e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 274e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 275e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 276e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 277e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParsePairPosFormat1(const uint8_t *data, const size_t length, 278e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t value_format1, 279e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t value_format2, 280e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t num_glyphs) { 281e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 282e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 283e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Skip 8 bytes that are already read before. 284e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.Skip(8)) { 285e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 286e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 287e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 288e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t pair_set_count = 0; 289e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&pair_set_count)) { 290e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 291e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 292e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 293e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const unsigned pair_pos_end = 2 * static_cast<unsigned>(pair_set_count) + 10; 294e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (pair_pos_end > std::numeric_limits<uint16_t>::max()) { 295e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 296e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 297e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < pair_set_count; ++i) { 298e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t pair_set_offset = 0; 299e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&pair_set_offset)) { 300e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 301e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 302e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (pair_set_offset < pair_pos_end || pair_set_offset >= length) { 303e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 304e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 305e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Check pair set tables 306e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParsePairSetTable(data + pair_set_offset, length - pair_set_offset, 307e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project value_format1, value_format2, 308e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project num_glyphs)) { 309e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 310e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 311e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 312e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 313e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 314a24be4f06674b2707b57904deaa0dff5a95823bdEvan Chu} 315e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 316c95c79ccb65d82a65b960919077d5c359cf28cedEvan Chubool ParsePairPosFormat2(const uint8_t *data, const size_t length, 317e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t value_format1, 318e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t value_format2, 319e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t num_glyphs) { 320e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 321e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 322e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Skip 8 bytes that are already read before. 323e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.Skip(8)) { 324e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 325e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 326e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 327e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_class_def1 = 0; 328e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_class_def2 = 0; 329e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t class1_count = 0; 330e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t class2_count = 0; 331e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&offset_class_def1) || 332e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_class_def2) || 333e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&class1_count) || 334e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&class2_count)) { 335e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 336e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 337e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 338e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Check class 1 records. 339e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < class1_count; ++i) { 340e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Check class 2 records. 341e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned j = 0; j < class2_count; ++j) { 342e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (value_format1 && !ParseValueRecord(&subtable, data, length, 343e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project value_format1)) { 344e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 345e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 346e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (value_format2 && !ParseValueRecord(&subtable, data, length, 347e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project value_format2)) { 348e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 349e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 350e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 351e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 352e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 353e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Check class definition tables. 354e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_class_def1 < subtable.offset() || offset_class_def1 >= length || 355e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project offset_class_def2 < subtable.offset() || offset_class_def2 >= length) { 356e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 357e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 358e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseClassDefTable(data + offset_class_def1, 359e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_class_def1, 360e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project num_glyphs, kMaxClassDefValue)) { 361e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 362e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 363e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseClassDefTable(data + offset_class_def2, 364e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_class_def2, 365e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project num_glyphs, kMaxClassDefValue)) { 366e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 367e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 368e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 369e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 370e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 371e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 372e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup Type 2: 373e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Pair Adjustment Positioning Subtable 3745c65c3a0f42e174e47fecd4e569606003217ff4eMartijn Coenenbool ParsePairAdjustment(const ots::OpenTypeFile *file, const uint8_t *data, 375e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const size_t length) { 376e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 377e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 378e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t format = 0; 379818b56eda129e0370afe6bcb808b0ed55c898d13Sherry Smith uint16_t offset_coverage = 0; 380818b56eda129e0370afe6bcb808b0ed55c898d13Sherry Smith uint16_t value_format1 = 0; 381818b56eda129e0370afe6bcb808b0ed55c898d13Sherry Smith uint16_t value_format2 = 0; 382818b56eda129e0370afe6bcb808b0ed55c898d13Sherry Smith if (!subtable.ReadU16(&format) || 383818b56eda129e0370afe6bcb808b0ed55c898d13Sherry Smith !subtable.ReadU16(&offset_coverage) || 384818b56eda129e0370afe6bcb808b0ed55c898d13Sherry Smith !subtable.ReadU16(&value_format1) || 385e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&value_format2)) { 386e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 387e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 388e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 389e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (format == 1) { 390e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParsePairPosFormat1(data, length, value_format1, value_format2, 391e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project file->maxp->num_glyphs)) { 392e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 393e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 394e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } else if (format == 2) { 395e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParsePairPosFormat2(data, length, value_format1, value_format2, 396e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project file->maxp->num_glyphs)) { 397e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 398e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 399e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } else { 400e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 401e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 402e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 403e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_coverage < subtable.offset() || offset_coverage >= length) { 404e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 405e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 406e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseCoverageTable(data + offset_coverage, 407e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_coverage, 408e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project file->maxp->num_glyphs)) { 409e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 410e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 411e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 412e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 413e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 414e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 415e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup Type 3 416e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Cursive Attachment Positioning Subtable 417e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseCursiveAttachment(const ots::OpenTypeFile *file, const uint8_t *data, 418e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const size_t length) { 419e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 420e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 421e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t format = 0; 422e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_coverage = 0; 423e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t entry_exit_count = 0; 424e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&format) || 425e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_coverage) || 426e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&entry_exit_count)) { 427e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 428e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 429e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 430e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (format != 1) { 431e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 432e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 433e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 434e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // Check entry exit records. 435e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const unsigned entry_exit_records_end = 436e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 2 * static_cast<unsigned>(entry_exit_count) + 6; 437e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (entry_exit_records_end > std::numeric_limits<uint16_t>::max()) { 438e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 439e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 440e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < entry_exit_count; ++i) { 441e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_entry_anchor = 0; 442e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_exit_anchor = 0; 443e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&offset_entry_anchor) || 444e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_exit_anchor)) { 445e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 446e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 447e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // These offsets could be NULL. 448e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_entry_anchor) { 449e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_entry_anchor < entry_exit_records_end || 450e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project offset_entry_anchor >= length) { 451e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 452e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 453e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseAnchorTable(data + offset_entry_anchor, 454e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_entry_anchor)) { 455e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 456e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 457e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 458e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_exit_anchor) { 459e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_exit_anchor < entry_exit_records_end || 460e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project offset_exit_anchor >= length) { 461e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 462e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 463e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseAnchorTable(data + offset_exit_anchor, 464a24be4f06674b2707b57904deaa0dff5a95823bdEvan Chu length - offset_exit_anchor)) { 465e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 466e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 467e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 468e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 469e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 470e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_coverage < subtable.offset() || offset_coverage >= length) { 471e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 472e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 473e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseCoverageTable(data + offset_coverage, 474e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_coverage, 475e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project file->maxp->num_glyphs)) { 476e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 477e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 478e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 479e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 480e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 481e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 482e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseAnchorArrayTable(const uint8_t *data, const size_t length, 483e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t class_count) { 484e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 485e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 486e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t record_count = 0; 487e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&record_count)) { 488e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 489e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 490e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 491e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const unsigned anchor_array_end = 2 * static_cast<unsigned>(record_count) * 492e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project static_cast<unsigned>(class_count) + 2; 49385b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu if (anchor_array_end > std::numeric_limits<uint16_t>::max()) { 494e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 495e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 496e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < record_count; ++i) { 497e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned j = 0; j < class_count; ++j) { 498e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_record = 0; 499e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&offset_record)) { 500e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 501e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 502e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project // |offset_record| could be NULL. 503e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_record) { 504e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_record < anchor_array_end || offset_record >= length) { 505e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 506e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 507e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseAnchorTable(data + offset_record, 508e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_record)) { 509e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 51085b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu } 51185b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu } 51285b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu } 51385b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu } 51485b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu return true; 51585b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu} 51685b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu 51785b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chubool ParseLigatureArrayTable(const uint8_t *data, const size_t length, 518e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint16_t class_count) { 519e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 520e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 521e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t ligature_count = 0; 522e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&ligature_count)) { 523e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 524e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 525e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project for (unsigned i = 0; i < ligature_count; ++i) { 526e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_ligature_attach = 0; 52785b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu if (!subtable.ReadU16(&offset_ligature_attach)) { 52885b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu return OTS_FAILURE(); 529e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 530e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_ligature_attach < 2 || offset_ligature_attach >= length) { 531e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 532e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 533e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseAnchorArrayTable(data + offset_ligature_attach, 534e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_ligature_attach, class_count)) { 535e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 536e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 537e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 538e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 539e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 540e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 541e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Common parser for Lookup Type 4, 5 and 6. 542e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseMarkToAttachmentSubtables(const ots::OpenTypeFile *file, 543e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length, 544e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const GPOS_TYPE type) { 545e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project ots::Buffer subtable(data, length); 546e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 547e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t format = 0; 548e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_coverage1 = 0; 549e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_coverage2 = 0; 550e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t class_count = 0; 551e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_mark_array = 0; 552e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project uint16_t offset_type_specific_array = 0; 553e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!subtable.ReadU16(&format) || 554e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_coverage1) || 555e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_coverage2) || 556e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&class_count) || 557e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_mark_array) || 558e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project !subtable.ReadU16(&offset_type_specific_array)) { 559e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 560e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 561e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 562e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (format != 1) { 563e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 564e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 565e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 566e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const unsigned header_end = static_cast<unsigned>(subtable.offset()); 567e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (header_end > std::numeric_limits<uint16_t>::max()) { 568e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 569e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 570e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_coverage1 < header_end || offset_coverage1 >= length) { 571e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 572e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 573e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseCoverageTable(data + offset_coverage1, 574e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_coverage1, 575e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project file->maxp->num_glyphs)) { 576e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 577e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 578e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_coverage2 < header_end || offset_coverage2 >= length) { 579e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 580e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 581e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ots::ParseCoverageTable(data + offset_coverage2, 582e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_coverage2, 583e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project file->maxp->num_glyphs)) { 584e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 585e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 586e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 587e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_mark_array < header_end || offset_mark_array >= length) { 588e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 589e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 590e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseMarkArrayTable(data + offset_mark_array, 591e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_mark_array, class_count)) { 592e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 593e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 594e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 595e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (offset_type_specific_array < header_end || 596e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project offset_type_specific_array >= length) { 597e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 598e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 599e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (type == GPOS_TYPE_MARK_TO_BASE_ATTACHMENT || 600e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project type == GPOS_TYPE_MARK_TO_MARK_ATTACHMENT) { 601e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseAnchorArrayTable(data + offset_type_specific_array, 602e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_type_specific_array, 603e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project class_count)) { 604e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 605e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 606e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } else if (type == GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT) { 607e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project if (!ParseLigatureArrayTable(data + offset_type_specific_array, 608e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project length - offset_type_specific_array, 609e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project class_count)) { 610e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 611e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 612e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } else { 613e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return OTS_FAILURE(); 614e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project } 615e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 616e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return true; 617e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 618e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 619e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup Type 4: 620e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// MarkToBase Attachment Positioning Subtable 621e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseMarkToBaseAttachment(const ots::OpenTypeFile *file, 622e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length) { 623e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return ParseMarkToAttachmentSubtables(file, data, length, 624e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_MARK_TO_BASE_ATTACHMENT); 625e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 626e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 627e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup Type 5: 628e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// MarkToLigature Attachment Positioning Subtable 629e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseMarkToLigatureAttachment(const ots::OpenTypeFile *file, 630e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length) { 631e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return ParseMarkToAttachmentSubtables(file, data, length, 632e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT); 63385b7e84f6cc61506c94e98844cac9ce50bbbe9dcEvan Chu} 634e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 635e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup Type 6: 636e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// MarkToMark Attachment Positioning Subtable 637e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file, 638e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length) { 639e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return ParseMarkToAttachmentSubtables(file, data, length, 640e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project GPOS_TYPE_MARK_TO_MARK_ATTACHMENT); 641e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 642e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 643e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup Type 7: 644e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Contextual Positioning Subtables 645e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Projectbool ParseContextPositioning(const ots::OpenTypeFile *file, 646e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project const uint8_t *data, const size_t length) { 647e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project return ots::ParseContextSubtable(data, length, file->maxp->num_glyphs, 648e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project file->gpos->num_lookups); 649e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project} 650e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project 651e9df6ba5a8fcccf306a80b1670b423be8fe7746The Android Open Source Project// Lookup Type 8: 652// Chaining Contexual Positioning Subtable 653bool ParseChainedContextPositioning(const ots::OpenTypeFile *file, 654 const uint8_t *data, const size_t length) { 655 return ots::ParseChainingContextSubtable(data, length, 656 file->maxp->num_glyphs, 657 file->gpos->num_lookups); 658} 659 660// Lookup Type 9: 661// Extension Positioning 662bool ParseExtensionPositioning(const ots::OpenTypeFile *file, 663 const uint8_t *data, const size_t length) { 664 return ots::ParseExtensionSubtable(file, data, length, 665 &kGposLookupSubtableParser); 666} 667 668} // namespace 669 670#define DROP_THIS_TABLE \ 671 do { file->gpos->data = 0; file->gpos->length = 0; } while (0) 672 673namespace ots { 674 675// As far as I checked, following fonts contain invalid GPOS table and 676// OTS will drop their GPOS table. 677// 678// # invalid delta format in device table 679// samanata.ttf 680// 681// # bad size range in device table 682// Sarai_07.ttf 683// 684// # bad offset to PairSetTable 685// chandas1-2.ttf 686// 687// # bad offset to FeatureTable 688// glrso12.ttf 689// gllr12.ttf 690// glbo12.ttf 691// glb12.ttf 692// glro12.ttf 693// glbso12.ttf 694// glrc12.ttf 695// glrsc12.ttf 696// glbs12.ttf 697// glrs12.ttf 698// glr12.ttf 699// 700// # ScriptRecords aren't sorted by tag 701// Garogier_unhinted.otf 702// 703// # bad start coverage index in CoverageFormat2 704// AndBasR.ttf 705// CharisSILB.ttf 706// CharisSILBI.ttf 707// CharisSILI.ttf 708// CharisSILR.ttf 709// DoulosSILR.ttf 710// GenBasBI.ttf 711// GenBasI.ttf 712// GenBkBasI.ttf 713// GenBkBasB.ttf 714// GenBkBasR.ttf 715// Padauk-Bold.ttf 716// Padauk.ttf 717// 718// # Contour point indexes aren't sorted 719// Arial Unicode.ttf 720 721bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { 722 // Parsing GPOS table requires num_glyphs which is contained in maxp table. 723 if (!file->maxp) { 724 return OTS_FAILURE(); 725 } 726 727 Buffer table(data, length); 728 729 OpenTypeGPOS *gpos = new OpenTypeGPOS; 730 file->gpos = gpos; 731 732 uint32_t version = 0; 733 uint16_t offset_script_list = 0; 734 uint16_t offset_feature_list = 0; 735 uint16_t offset_lookup_list = 0; 736 if (!table.ReadU32(&version) || 737 !table.ReadU16(&offset_script_list) || 738 !table.ReadU16(&offset_feature_list) || 739 !table.ReadU16(&offset_lookup_list)) { 740 return OTS_FAILURE(); 741 } 742 743 if (version != 0x00010000) { 744 OTS_WARNING("bad GPOS version"); 745 DROP_THIS_TABLE; 746 return true; 747 } 748 if ((offset_script_list < kGposHeaderSize || 749 offset_script_list >= length) || 750 (offset_feature_list < kGposHeaderSize || 751 offset_feature_list >= length) || 752 (offset_lookup_list < kGposHeaderSize || 753 offset_lookup_list >= length)) { 754 OTS_WARNING("bad offset in GPOS header"); 755 DROP_THIS_TABLE; 756 return true; 757 } 758 759 if (!ParseLookupListTable(file, data + offset_lookup_list, 760 length - offset_lookup_list, 761 &kGposLookupSubtableParser, 762 &gpos->num_lookups)) { 763 OTS_WARNING("faild to parse lookup list table"); 764 DROP_THIS_TABLE; 765 return true; 766 } 767 768 uint16_t num_features = 0; 769 if (!ParseFeatureListTable(data + offset_feature_list, 770 length - offset_feature_list, gpos->num_lookups, 771 &num_features)) { 772 OTS_WARNING("faild to parse feature list table"); 773 DROP_THIS_TABLE; 774 return true; 775 } 776 777 if (!ParseScriptListTable(data + offset_script_list, 778 length - offset_script_list, num_features)) { 779 OTS_WARNING("faild to parse script list table"); 780 DROP_THIS_TABLE; 781 return true; 782 } 783 784 gpos->data = data; 785 gpos->length = length; 786 return true; 787} 788 789bool ots_gpos_should_serialise(OpenTypeFile *file) { 790 const bool needed_tables_dropped = 791 (file->gdef && file->gdef->data == NULL) || 792 (file->gsub && file->gsub->data == NULL); 793 return file->gpos != NULL && file->gpos->data != NULL && 794 !needed_tables_dropped; 795} 796 797bool ots_gpos_serialise(OTSStream *out, OpenTypeFile *file) { 798 if (!out->Write(file->gpos->data, file->gpos->length)) { 799 return OTS_FAILURE(); 800 } 801 802 return true; 803} 804 805void ots_gpos_free(OpenTypeFile *file) { 806 delete file->gpos; 807} 808 809} // namespace ots 810 811