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 "loca.h"
6
7#include "head.h"
8#include "maxp.h"
9
10// loca - Index to Location
11// http://www.microsoft.com/opentype/otspec/loca.htm
12
13namespace ots {
14
15bool ots_loca_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
16  Buffer table(data, length);
17
18  // We can't do anything useful in validating this data except to ensure that
19  // the values are monotonically increasing.
20
21  OpenTypeLOCA *loca = new OpenTypeLOCA;
22  file->loca = loca;
23
24  if (!file->maxp || !file->head) {
25    return OTS_FAILURE();
26  }
27
28  const unsigned num_glyphs = file->maxp->num_glyphs;
29  unsigned last_offset = 0;
30  loca->offsets.resize(num_glyphs + 1);
31  // maxp->num_glyphs is uint16_t, thus the addition never overflows.
32
33  if (file->head->index_to_loc_format == 0) {
34    // Note that the <= here (and below) is correct. There is one more offset
35    // than the number of glyphs in order to give the length of the final
36    // glyph.
37    for (unsigned i = 0; i <= num_glyphs; ++i) {
38      uint16_t offset = 0;
39      if (!table.ReadU16(&offset)) {
40        return OTS_FAILURE();
41      }
42      if (offset < last_offset) {
43        return OTS_FAILURE();
44      }
45      last_offset = offset;
46      loca->offsets[i] = offset * 2;
47    }
48  } else {
49    for (unsigned i = 0; i <= num_glyphs; ++i) {
50      uint32_t offset = 0;
51      if (!table.ReadU32(&offset)) {
52        return OTS_FAILURE();
53      }
54      if (offset < last_offset) {
55        return OTS_FAILURE();
56      }
57      last_offset = offset;
58      loca->offsets[i] = offset;
59    }
60  }
61
62  return true;
63}
64
65bool ots_loca_should_serialise(OpenTypeFile *file) {
66  return file->loca != NULL;
67}
68
69bool ots_loca_serialise(OTSStream *out, OpenTypeFile *file) {
70  const OpenTypeLOCA *loca = file->loca;
71  const OpenTypeHEAD *head = file->head;
72
73  if (!head) {
74    return OTS_FAILURE();
75  }
76
77  if (head->index_to_loc_format == 0) {
78    for (unsigned i = 0; i < loca->offsets.size(); ++i) {
79      if (!out->WriteU16(loca->offsets[i] >> 1)) {
80        return OTS_FAILURE();
81      }
82    }
83  } else {
84    for (unsigned i = 0; i < loca->offsets.size(); ++i) {
85      if (!out->WriteU32(loca->offsets[i])) {
86        return OTS_FAILURE();
87      }
88    }
89  }
90
91  return true;
92}
93
94void ots_loca_free(OpenTypeFile *file) {
95  delete file->loca;
96}
97
98}  // namespace ots
99