14dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org// Copyright (c) 2011 The Chromium Authors. All rights reserved.
24dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org// Use of this source code is governed by a BSD-style license that can be
34dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org// found in the LICENSE file.
44dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
54dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org#include "metrics.h"
64dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
74dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org#include "head.h"
84dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org#include "maxp.h"
94dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
104dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org// OpenType horizontal and vertical common header format
114dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org// http://www.microsoft.com/opentype/otspec/hhea.htm
124dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org// http://www.microsoft.com/opentype/otspec/vhea.htm
134dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
144dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.orgnamespace ots {
154dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
164dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.orgbool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
174dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org                        OpenTypeMetricsHeader *header) {
184dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!table->ReadS16(&header->ascent) ||
194dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadS16(&header->descent) ||
204dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadS16(&header->linegap) ||
214dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadU16(&header->adv_width_max) ||
224dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadS16(&header->min_sb1) ||
234dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadS16(&header->min_sb2) ||
244dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadS16(&header->max_extent) ||
254dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadS16(&header->caret_slope_rise) ||
264dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadS16(&header->caret_slope_run) ||
274dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !table->ReadS16(&header->caret_offset)) {
284dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
294dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
304dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
314dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (header->ascent < 0) {
324dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    OTS_WARNING("bad ascent: %d", header->ascent);
334dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    header->ascent = 0;
344dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
354dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (header->linegap < 0) {
364dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    OTS_WARNING("bad linegap: %d", header->linegap);
374dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    header->linegap = 0;
384dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
394dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
404dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!file->head) {
414dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
424dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
434dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
444dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  // if the font is non-slanted, caret_offset should be zero.
454dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!(file->head->mac_style & 2) &&
464dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      (header->caret_offset != 0)) {
474dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    OTS_WARNING("bad caret offset: %d", header->caret_offset);
484dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    header->caret_offset = 0;
494dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
504dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
514dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  // skip the reserved bytes
524dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!table->Skip(8)) {
534dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
544dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
554dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
564dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  int16_t data_format;
574dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!table->ReadS16(&data_format)) {
584dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
594dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
604dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (data_format) {
614dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
624dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
634dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
644dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!table->ReadU16(&header->num_metrics)) {
654dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
664dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
674dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
684dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!file->maxp) {
694dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
704dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
714dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
724dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (header->num_metrics > file->maxp->num_glyphs) {
734dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
744dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
754dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
764dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  return true;
774dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org}
784dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
794dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.orgbool SerialiseMetricsHeader(OTSStream *out,
804dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org                            const OpenTypeMetricsHeader *header) {
814dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!out->WriteU32(header->version) ||
824dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->ascent) ||
834dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->descent) ||
844dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->linegap) ||
854dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteU16(header->adv_width_max) ||
864dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->min_sb1) ||
874dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->min_sb2) ||
884dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->max_extent) ||
894dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->caret_slope_rise) ||
904dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->caret_slope_run) ||
914dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(header->caret_offset) ||
924dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteR64(0) ||  // reserved
934dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteS16(0) ||  // metric data format
944dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      !out->WriteU16(header->num_metrics)) {
954dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
964dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
974dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
984dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  return true;
994dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org}
1004dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1014dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.orgbool ParseMetricsTable(Buffer *table,
1024dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org                       const uint16_t num_glyphs,
1034dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org                       const OpenTypeMetricsHeader *header,
1044dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org                       OpenTypeMetricsTable *metrics) {
1054dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that
1064dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  // amount of memory that we'll allocate for this to a sane amount.
1074dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  const unsigned num_metrics = header->num_metrics;
1084dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1094dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (num_metrics > num_glyphs) {
1104dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
1114dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
1124dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  if (!num_metrics) {
1134dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    return OTS_FAILURE();
1144dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
1154dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  const unsigned num_sbs = num_glyphs - num_metrics;
1164dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1174dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  metrics->entries.reserve(num_metrics);
1184dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  for (unsigned i = 0; i < num_metrics; ++i) {
1194dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    uint16_t adv = 0;
1204dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    int16_t sb = 0;
1214dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) {
1224dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      return OTS_FAILURE();
1234dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    }
1244dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1254dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    // Since so many fonts don't have proper value on |adv| and |sb|,
1264dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    // we should not call ots_failure() here. For example, about 20% of fonts
1274dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests.
1284dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    if (adv > header->adv_width_max) {
1294dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      OTS_WARNING("bad adv: %u > %u", adv, header->adv_width_max);
1304dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      adv = header->adv_width_max;
1314dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    }
1324dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1334dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    if (sb < header->min_sb1) {
1344dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      OTS_WARNING("bad sb: %d < %d", sb, header->min_sb1);
1354dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      sb = header->min_sb1;
1364dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    }
1374dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1384dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    metrics->entries.push_back(std::make_pair(adv, sb));
1394dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
1404dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1414dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  metrics->sbs.reserve(num_sbs);
1424dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  for (unsigned i = 0; i < num_sbs; ++i) {
1434dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    int16_t sb;
1444dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    if (!table->ReadS16(&sb)) {
1454dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      // Some Japanese fonts (e.g., mona.ttf) fail this test.
1464dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      return OTS_FAILURE();
1474dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    }
1484dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1494dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    if (sb < header->min_sb1) {
1504dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      // The same as above. Three fonts in http://www.fontsquirrel.com/fontface
1514dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      // (e.g., Notice2Std.otf) have weird lsb values.
1524dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      OTS_WARNING("bad lsb: %d < %d", sb, header->min_sb1);
1534dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      sb = header->min_sb1;
1544dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    }
1554dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1564dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    metrics->sbs.push_back(sb);
1574dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
1584dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1594dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  return true;
1604dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org}
1614dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1624dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.orgbool SerialiseMetricsTable(OTSStream *out,
1634dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org                           const OpenTypeMetricsTable *metrics) {
1644dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  for (unsigned i = 0; i < metrics->entries.size(); ++i) {
1654dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    if (!out->WriteU16(metrics->entries[i].first) ||
1664dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org        !out->WriteS16(metrics->entries[i].second)) {
1674dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      return OTS_FAILURE();
1684dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    }
1694dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
1704dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1714dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  for (unsigned i = 0; i < metrics->sbs.size(); ++i) {
1724dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    if (!out->WriteS16(metrics->sbs[i])) {
1734dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org      return OTS_FAILURE();
1744dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org    }
1754dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  }
1764dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1774dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org  return true;
1784dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org}
1794dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
1804dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org}  // namespace ots
1814dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org
182