Coverage Report

Created: 2025-08-03 06:45

/src/ots/src/avar.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2018 The OTS 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 "avar.h"
6
7
#include "fvar.h"
8
9
#include "variations.h"
10
11
namespace ots {
12
13
// -----------------------------------------------------------------------------
14
// OpenTypeAVAR
15
// -----------------------------------------------------------------------------
16
17
859
bool OpenTypeAVAR::Parse(const uint8_t* data, size_t length) {
18
859
  Buffer table(data, length);
19
859
  if (!table.ReadU16(&this->majorVersion) ||
20
859
      !table.ReadU16(&this->minorVersion) ||
21
859
      !table.ReadU16(&this->reserved) ||
22
859
      !table.ReadU16(&this->axisCount)) {
23
50
    return Drop("Failed to read table header");
24
50
  }
25
809
  if (this->majorVersion > 2) {
26
179
    return Drop("Unknown table version");
27
179
  }
28
630
  if (this->majorVersion == 1) {
29
    // We can fix table
30
281
    if (this->minorVersion > 0) {
31
      // we only know how to serialize version 1.0
32
33
      Warning("Downgrading minor version to 0");
33
33
      this->minorVersion = 0;
34
33
    }
35
281
    if (this->reserved != 0) {
36
40
      Warning("Expected reserved=0");
37
40
      this->reserved = 0;
38
40
    }
39
349
  } else {
40
    // We serialize data unchanged, so drop even for minor errors
41
349
    if (this->minorVersion > 0) {
42
75
      return Drop("Unknown minor table version");
43
75
    }
44
274
    if (this->reserved != 0) {
45
59
      return Drop("Expected reserved=0");
46
59
    }
47
274
  }
48
49
496
  OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>(
50
496
      GetFont()->GetTypedTable(OTS_TAG_FVAR));
51
496
  if (!fvar) {
52
121
    return DropVariations("Required fvar table is missing");
53
121
  }
54
375
  if (axisCount != fvar->AxisCount()) {
55
16
    return Drop("Axis count mismatch");
56
16
  }
57
58
990
  for (size_t i = 0; i < this->axisCount; i++) {
59
678
    this->axisSegmentMaps.emplace_back();
60
678
    uint16_t positionMapCount;
61
678
    if (!table.ReadU16(&positionMapCount)) {
62
1
      return Drop("Failed to read position map count");
63
1
    }
64
677
    int foundRequiredMappings = 0;
65
2.20k
    for (size_t j = 0; j < positionMapCount; j++) {
66
1.56k
      AxisValueMap map;
67
1.56k
      if (!table.ReadS16(&map.fromCoordinate) ||
68
1.56k
          !table.ReadS16(&map.toCoordinate)) {
69
5
        return Drop("Failed to read axis value map");
70
5
      }
71
1.56k
      if (map.fromCoordinate < -0x4000 ||
72
1.56k
          map.fromCoordinate > 0x4000 ||
73
1.56k
          map.toCoordinate < -0x4000 ||
74
1.56k
          map.toCoordinate > 0x4000) {
75
15
        return Drop("Axis value map coordinate out of range");
76
15
      }
77
1.54k
      if (j > 0) {
78
1.31k
        if (map.fromCoordinate <= this->axisSegmentMaps[i].back().fromCoordinate ||
79
1.31k
            map.toCoordinate < this->axisSegmentMaps[i].back().toCoordinate) {
80
19
          return Drop("Axis value map out of order");
81
19
        }
82
1.31k
      }
83
1.52k
      if ((map.fromCoordinate == -0x4000 && map.toCoordinate == -0x4000) ||
84
1.52k
          (map.fromCoordinate == 0 && map.toCoordinate == 0) ||
85
1.52k
          (map.fromCoordinate == 0x4000 && map.toCoordinate == 0x4000)) {
86
633
        ++foundRequiredMappings;
87
633
      }
88
1.52k
      this->axisSegmentMaps[i].push_back(map);
89
1.52k
    }
90
638
    if (positionMapCount > 0 && foundRequiredMappings != 3) {
91
7
      return Drop("A required mapping (for -1, 0 or 1) is missing");
92
7
    }
93
638
  }
94
95
312
  if (this->majorVersion < 2)
96
179
    return true;
97
98
133
  uint32_t axisIndexMapOffset;
99
133
  uint32_t varStoreOffset;
100
101
133
  if (!table.ReadU32(&axisIndexMapOffset) ||
102
133
      !table.ReadU32(&varStoreOffset)) {
103
3
    return Drop("Failed to read version 2 offsets");
104
3
  }
105
106
130
  Font *font = GetFont();
107
130
  uint32_t headerSize = table.offset();
108
109
130
  if (axisIndexMapOffset) {
110
124
    if (axisIndexMapOffset < headerSize || axisIndexMapOffset >= length) {
111
17
      return Drop("Bad delta set index offset in table header");
112
17
    }
113
107
    if (!ParseDeltaSetIndexMap(font, data + axisIndexMapOffset, length - axisIndexMapOffset)) {
114
4
      return Drop("Failed to parse delta set index map");
115
4
    }
116
107
  }
117
118
109
  if (varStoreOffset) {
119
105
    if (varStoreOffset < headerSize || varStoreOffset >= length) {
120
17
      return Drop("Bad item variation store offset in table header");
121
17
    }
122
88
    if (!ParseItemVariationStore(font, data + varStoreOffset, length - varStoreOffset)) {
123
49
      return Drop("Failed to parse item variation store");
124
49
    }
125
88
  }
126
127
43
  this->m_data = data;
128
43
  this->m_length = length;
129
130
43
  return true;
131
109
}
132
133
24
bool OpenTypeAVAR::Serialize(OTSStream* out) {
134
24
  if (this->majorVersion >= 2) {
135
6
    if (!out->Write(this->m_data, this->m_length)) {
136
0
      return Error("Failed to write table");
137
0
    }
138
6
    return true;
139
6
  }
140
141
18
  if (!out->WriteU16(this->majorVersion) ||
142
18
      !out->WriteU16(this->minorVersion) ||
143
18
      !out->WriteU16(this->reserved) ||
144
18
      !out->WriteU16(this->axisCount)) {
145
0
    return Error("Failed to write table");
146
0
  }
147
148
41
  for (size_t i = 0; i < this->axisCount; i++) {
149
23
    const auto& axisValueMap = this->axisSegmentMaps[i];
150
23
    if (!out->WriteU16(axisValueMap.size())) {
151
0
      return Error("Failed to write table");
152
0
    }
153
134
    for (size_t j = 0; j < axisValueMap.size(); j++) {
154
111
      if (!out->WriteS16(axisValueMap[j].fromCoordinate) ||
155
111
          !out->WriteS16(axisValueMap[j].toCoordinate)) {
156
0
        return Error("Failed to write table");
157
0
      }
158
111
    }
159
23
  }
160
161
18
  return true;
162
18
}
163
164
}  // namespace ots