LCOV - code coverage report
Current view: top level - gfx/ots/src - kern.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 119 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "kern.h"
       6             : 
       7             : // kern - Kerning
       8             : // http://www.microsoft.com/typography/otspec/kern.htm
       9             : 
      10             : #define TABLE_NAME "kern"
      11             : 
      12             : #define DROP_THIS_TABLE(msg_) \
      13             :   do { \
      14             :     OTS_FAILURE_MSG(msg_ ", table discarded"); \
      15             :     delete font->kern; \
      16             :     font->kern = 0; \
      17             :   } while (0)
      18             : 
      19             : namespace ots {
      20             : 
      21           0 : bool ots_kern_parse(Font *font, const uint8_t *data, size_t length) {
      22           0 :   Buffer table(data, length);
      23             : 
      24           0 :   OpenTypeKERN *kern = new OpenTypeKERN;
      25           0 :   font->kern = kern;
      26             : 
      27           0 :   uint16_t num_tables = 0;
      28           0 :   if (!table.ReadU16(&kern->version) ||
      29           0 :       !table.ReadU16(&num_tables)) {
      30           0 :     return OTS_FAILURE_MSG("Failed to read kern header");
      31             :   }
      32             : 
      33           0 :   if (kern->version > 0) {
      34           0 :     DROP_THIS_TABLE("bad table version");
      35           0 :     return true;
      36             :   }
      37             : 
      38           0 :   if (num_tables == 0) {
      39           0 :     DROP_THIS_TABLE("num_tables is zero");
      40           0 :     return true;
      41             :   }
      42             : 
      43           0 :   kern->subtables.reserve(num_tables);
      44           0 :   for (unsigned i = 0; i < num_tables; ++i) {
      45           0 :     OpenTypeKERNFormat0 subtable;
      46           0 :     uint16_t sub_length = 0;
      47             : 
      48           0 :     if (!table.ReadU16(&subtable.version) ||
      49           0 :         !table.ReadU16(&sub_length)) {
      50           0 :       return OTS_FAILURE_MSG("Failed to read kern subtable %d header", i);
      51             :     }
      52             : 
      53           0 :     if (subtable.version > 0) {
      54           0 :       OTS_WARNING("Bad subtable version: %d", subtable.version);
      55           0 :       continue;
      56             :     }
      57             : 
      58           0 :     const size_t current_offset = table.offset();
      59           0 :     if (current_offset - 4 + sub_length > length) {
      60           0 :       return OTS_FAILURE_MSG("Bad kern subtable %d offset %ld", i, current_offset);
      61             :     }
      62             : 
      63           0 :     if (!table.ReadU16(&subtable.coverage)) {
      64           0 :       return OTS_FAILURE_MSG("Cailed to read kern subtable %d coverage", i);
      65             :     }
      66             : 
      67           0 :     if (!(subtable.coverage & 0x1)) {
      68           0 :       OTS_WARNING(
      69           0 :           "We don't support vertical data as the renderer doesn't support it.");
      70           0 :       continue;
      71             :     }
      72           0 :     if (subtable.coverage & 0xF0) {
      73           0 :       DROP_THIS_TABLE("Reserved fields should zero-filled");
      74           0 :       return true;
      75             :     }
      76           0 :     const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
      77           0 :     if (format != 0) {
      78           0 :       OTS_WARNING("Format %d is not supported.", format);
      79           0 :       continue;
      80             :     }
      81             : 
      82             :     // Parse the format 0 field.
      83           0 :     uint16_t num_pairs = 0;
      84           0 :     if (!table.ReadU16(&num_pairs) ||
      85           0 :         !table.ReadU16(&subtable.search_range) ||
      86           0 :         !table.ReadU16(&subtable.entry_selector) ||
      87           0 :         !table.ReadU16(&subtable.range_shift)) {
      88           0 :       return OTS_FAILURE_MSG("Failed to read kern subtable %d format 0 fields", i);
      89             :     }
      90             : 
      91           0 :     if (!num_pairs) {
      92           0 :       DROP_THIS_TABLE("Zero length subtable is found");
      93           0 :       return true;
      94             :     }
      95             : 
      96             :     // Sanity checks for search_range, entry_selector, and range_shift. See the
      97             :     // comment in ots.cc for details.
      98           0 :     const size_t kFormat0PairSize = 6;  // left, right, and value. 2 bytes each.
      99           0 :     if (num_pairs > (65536 / kFormat0PairSize)) {
     100             :       // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923.
     101           0 :       DROP_THIS_TABLE("Too large subtable");
     102           0 :       return true;
     103             :     }
     104           0 :     unsigned max_pow2 = 0;
     105           0 :     while (1u << (max_pow2 + 1) <= num_pairs) {
     106           0 :       ++max_pow2;
     107             :     }
     108           0 :     const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
     109           0 :     if (subtable.search_range != expected_search_range) {
     110           0 :       OTS_WARNING("bad search range");
     111           0 :       subtable.search_range = expected_search_range;
     112             :     }
     113           0 :     if (subtable.entry_selector != max_pow2) {
     114           0 :       return OTS_FAILURE_MSG("Bad subtable %d entry selector %d", i, subtable.entry_selector);
     115             :     }
     116             :     const uint16_t expected_range_shift =
     117           0 :         kFormat0PairSize * num_pairs - subtable.search_range;
     118           0 :     if (subtable.range_shift != expected_range_shift) {
     119           0 :       OTS_WARNING("bad range shift");
     120           0 :       subtable.range_shift = expected_range_shift;
     121             :     }
     122             : 
     123             :     // Read kerning pairs.
     124           0 :     subtable.pairs.reserve(num_pairs);
     125           0 :     uint32_t last_pair = 0;
     126           0 :     for (unsigned j = 0; j < num_pairs; ++j) {
     127             :       OpenTypeKERNFormat0Pair kerning_pair;
     128           0 :       if (!table.ReadU16(&kerning_pair.left) ||
     129           0 :           !table.ReadU16(&kerning_pair.right) ||
     130           0 :           !table.ReadS16(&kerning_pair.value)) {
     131           0 :         return OTS_FAILURE_MSG("Failed to read subtable %d kerning pair %d", i, j);
     132             :       }
     133             :       const uint32_t current_pair
     134           0 :           = (kerning_pair.left << 16) + kerning_pair.right;
     135           0 :       if (j != 0 && current_pair <= last_pair) {
     136             :         // Many free fonts don't follow this rule, so we don't call OTS_FAILURE
     137             :         // in order to support these fonts.
     138           0 :         DROP_THIS_TABLE("Kerning pairs are not sorted");
     139           0 :         return true;
     140             :       }
     141           0 :       last_pair = current_pair;
     142           0 :       subtable.pairs.push_back(kerning_pair);
     143             :     }
     144             : 
     145           0 :     kern->subtables.push_back(subtable);
     146             :   }
     147             : 
     148           0 :   if (!kern->subtables.size()) {
     149           0 :     DROP_THIS_TABLE("All subtables are removed");
     150           0 :     return true;
     151             :   }
     152             : 
     153           0 :   return true;
     154             : }
     155             : 
     156           0 : bool ots_kern_should_serialise(Font *font) {
     157           0 :   if (!font->glyf) return false;  // this table is not for CFF fonts.
     158           0 :   return font->kern != NULL;
     159             : }
     160             : 
     161           0 : bool ots_kern_serialise(OTSStream *out, Font *font) {
     162           0 :   const OpenTypeKERN *kern = font->kern;
     163             : 
     164           0 :   const uint16_t num_subtables = static_cast<uint16_t>(kern->subtables.size());
     165           0 :   if (num_subtables != kern->subtables.size() ||
     166           0 :       !out->WriteU16(kern->version) ||
     167           0 :       !out->WriteU16(num_subtables)) {
     168           0 :     return OTS_FAILURE_MSG("Can't write kern table header");
     169             :   }
     170             : 
     171           0 :   for (uint16_t i = 0; i < num_subtables; ++i) {
     172           0 :     const size_t length = 14 + (6 * kern->subtables[i].pairs.size());
     173           0 :     if (length > std::numeric_limits<uint16_t>::max() ||
     174           0 :         !out->WriteU16(kern->subtables[i].version) ||
     175           0 :         !out->WriteU16(static_cast<uint16_t>(length)) ||
     176           0 :         !out->WriteU16(kern->subtables[i].coverage) ||
     177           0 :         !out->WriteU16(
     178           0 :             static_cast<uint16_t>(kern->subtables[i].pairs.size())) ||
     179           0 :         !out->WriteU16(kern->subtables[i].search_range) ||
     180           0 :         !out->WriteU16(kern->subtables[i].entry_selector) ||
     181           0 :         !out->WriteU16(kern->subtables[i].range_shift)) {
     182           0 :       return OTS_FAILURE_MSG("Failed to write kern subtable %d", i);
     183             :     }
     184           0 :     for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) {
     185           0 :       if (!out->WriteU16(kern->subtables[i].pairs[j].left) ||
     186           0 :           !out->WriteU16(kern->subtables[i].pairs[j].right) ||
     187           0 :           !out->WriteS16(kern->subtables[i].pairs[j].value)) {
     188           0 :         return OTS_FAILURE_MSG("Failed to write kern pair %d for subtable %d", j, i);
     189             :       }
     190             :     }
     191             :   }
     192             : 
     193           0 :   return true;
     194             : }
     195             : 
     196           0 : void ots_kern_reuse(Font *font, Font *other) {
     197           0 :   font->kern = other->kern;
     198           0 :   font->kern_reused = true;
     199           0 : }
     200             : 
     201           0 : void ots_kern_free(Font *font) {
     202           0 :   delete font->kern;
     203           0 : }
     204             : 
     205             : }  // namespace ots
     206             : 
     207             : #undef TABLE_NAME
     208             : #undef DROP_THIS_TABLE

Generated by: LCOV version 1.13