1 /* 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <stdint.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 // For htons/ntohs 36 #include <arpa/inet.h> 37 38 // Buffer helper class 39 // 40 // This class perform some trival buffer operations while checking for 41 // out-of-bounds errors. As a family they return false if anything is amiss, 42 // updating the current offset otherwise. 43 class Buffer { 44 public: 45 Buffer(const uint8_t* buffer, size_t length) 46 : m_buffer(buffer) 47 , m_length(length) 48 , m_offset(0) { } 49 50 bool skip(size_t numBytes) 51 { 52 if (m_offset + numBytes > m_length) 53 return false; 54 m_offset += numBytes; 55 return true; 56 } 57 58 bool readU8(uint8_t* value) 59 { 60 if (m_offset + sizeof(uint8_t) > m_length) 61 return false; 62 *value = m_buffer[m_offset]; 63 m_offset += sizeof(uint8_t); 64 return true; 65 } 66 67 bool readU16(uint16_t* value) 68 { 69 if (m_offset + sizeof(uint16_t) > m_length) 70 return false; 71 memcpy(value, m_buffer + m_offset, sizeof(uint16_t)); 72 *value = ntohs(*value); 73 m_offset += sizeof(uint16_t); 74 return true; 75 } 76 77 bool readS16(int16_t* value) 78 { 79 return readU16(reinterpret_cast<uint16_t*>(value)); 80 } 81 82 size_t offset() const 83 { 84 return m_offset; 85 } 86 87 void setOffset(size_t newoffset) 88 { 89 m_offset = newoffset; 90 } 91 92 private: 93 const uint8_t *const m_buffer; 94 const size_t m_length; 95 size_t m_offset; 96 }; 97 98 // VDMX parsing code. 99 // 100 // VDMX tables are found in some TrueType/OpenType fonts and contain 101 // ascender/descender overrides for certain (usually small) sizes. This is 102 // needed in order to match font metrics on Windows. 103 // 104 // Freetype does not parse these tables so we do so here. 105 106 namespace WebCore { 107 108 // Parse a TrueType VDMX table. 109 // yMax: (output) the ascender value from the table 110 // yMin: (output) the descender value from the table (negative!) 111 // vdmx: the table bytes 112 // vdmxLength: length of @vdmx, in bytes 113 // targetPixelSize: the pixel size of the font (e.g. 16) 114 // 115 // Returns true iff a suitable match are found. Otherwise, *yMax and *yMin are 116 // untouched. size_t must be 32-bits to avoid overflow. 117 // 118 // See http://www.microsoft.com/opentype/otspec/vdmx.htm 119 bool parseVDMX(int* yMax, int* yMin, 120 const uint8_t* vdmx, size_t vdmxLength, 121 unsigned targetPixelSize) 122 { 123 Buffer buf(vdmx, vdmxLength); 124 125 // We ignore the version. Future tables should be backwards compatible with 126 // this layout. 127 uint16_t numRatios; 128 if (!buf.skip(4) || !buf.readU16(&numRatios)) 129 return false; 130 131 // Now we have two tables. Firstly we have @numRatios Ratio records, then a 132 // matching array of @numRatios offsets. We save the offset of the beginning 133 // of this second table. 134 // 135 // Range 6 <= x <= 262146 136 unsigned long offsetTableOffset = 137 buf.offset() + 4 /* sizeof struct ratio */ * numRatios; 138 139 unsigned desiredRatio = 0xffffffff; 140 // We read 4 bytes per record, so the offset range is 141 // 6 <= x <= 524286 142 for (unsigned i = 0; i < numRatios; ++i) { 143 uint8_t xRatio, yRatio1, yRatio2; 144 145 if (!buf.skip(1) 146 || !buf.readU8(&xRatio) 147 || !buf.readU8(&yRatio1) 148 || !buf.readU8(&yRatio2)) 149 return false; 150 151 // This either covers 1:1, or this is the default entry (0, 0, 0) 152 if ((xRatio == 1 && yRatio1 <= 1 && yRatio2 >= 1) 153 || (xRatio == 0 && yRatio1 == 0 && yRatio2 == 0)) { 154 desiredRatio = i; 155 break; 156 } 157 } 158 159 if (desiredRatio == 0xffffffff) // no ratio found 160 return false; 161 162 // Range 10 <= x <= 393216 163 buf.setOffset(offsetTableOffset + sizeof(uint16_t) * desiredRatio); 164 165 // Now we read from the offset table to get the offset of another array 166 uint16_t groupOffset; 167 if (!buf.readU16(&groupOffset)) 168 return false; 169 // Range 0 <= x <= 65535 170 buf.setOffset(groupOffset); 171 172 uint16_t numRecords; 173 if (!buf.readU16(&numRecords) || !buf.skip(sizeof(uint16_t))) 174 return false; 175 176 // We read 6 bytes per record, so the offset range is 177 // 4 <= x <= 458749 178 for (unsigned i = 0; i < numRecords; ++i) { 179 uint16_t pixelSize; 180 if (!buf.readU16(&pixelSize)) 181 return false; 182 // the entries are sorted, so we can abort early if need be 183 if (pixelSize > targetPixelSize) 184 return false; 185 186 if (pixelSize == targetPixelSize) { 187 int16_t tempYMax, tempYMin; 188 if (!buf.readS16(&tempYMax) 189 || !buf.readS16(&tempYMin)) 190 return false; 191 *yMin = tempYMin; 192 *yMax = tempYMax; 193 return true; 194 } 195 if (!buf.skip(2 * sizeof(int16_t))) 196 return false; 197 } 198 199 return false; 200 } 201 202 } // namespace WebCore 203