1 /*
2  * Copyright 2011 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "sfntly/table/truetype/loca_table.h"
18 #include "sfntly/port/exception_type.h"
19 
20 namespace sfntly {
21 /******************************************************************************
22  * LocaTable class
23  ******************************************************************************/
~LocaTable()24 LocaTable::~LocaTable() {}
25 
GlyphOffset(int32_t glyph_id)26 int32_t LocaTable::GlyphOffset(int32_t glyph_id) {
27   if (glyph_id < 0 || glyph_id >= num_glyphs_) {
28 #if !defined (SFNTLY_NO_EXCEPTION)
29     throw IndexOutOfBoundException("Glyph ID is out of bounds.");
30 #endif
31     return 0;
32   }
33   return Loca(glyph_id);
34 }
35 
GlyphLength(int32_t glyph_id)36 int32_t LocaTable::GlyphLength(int32_t glyph_id) {
37   if (glyph_id < 0 || glyph_id >= num_glyphs_) {
38 #if !defined (SFNTLY_NO_EXCEPTION)
39     throw IndexOutOfBoundException("Glyph ID is out of bounds.");
40 #endif
41     return 0;
42   }
43   int32_t glyph_val = Loca(glyph_id);
44   int32_t glyph_next_val = Loca(glyph_id + 1);
45   if (glyph_val < 0 || glyph_next_val < 0 || glyph_next_val <= glyph_val)
46     return 0;
47   return glyph_next_val - glyph_val;
48 }
49 
NumLocas()50 int32_t LocaTable::NumLocas() {
51   return num_glyphs_ + 1;
52 }
53 
Loca(int32_t index)54 int32_t LocaTable::Loca(int32_t index) {
55   if (index > num_glyphs_) {
56 #if !defined (SFNTLY_NO_EXCEPTION)
57     throw IndexOutOfBoundException();
58 #endif
59     return 0;
60   }
61   if (format_version_ == IndexToLocFormat::kShortOffset) {
62     return 2 * data_->ReadUShort(index * DataSize::kUSHORT);
63   }
64   return data_->ReadULongAsInt(index * DataSize::kULONG);
65 }
66 
LocaTable(Header * header,ReadableFontData * data,int32_t format_version,int32_t num_glyphs)67 LocaTable::LocaTable(Header* header,
68                      ReadableFontData* data,
69                      int32_t format_version,
70                      int32_t num_glyphs)
71     : Table(header, data),
72       format_version_(format_version),
73       num_glyphs_(num_glyphs) {
74 }
75 
76 /******************************************************************************
77  * LocaTable::Iterator class
78  ******************************************************************************/
LocaIterator(LocaTable * table)79 LocaTable::LocaIterator::LocaIterator(LocaTable* table)
80     : PODIterator<int32_t, LocaTable>(table), index_(-1) {
81 }
82 
HasNext()83 bool LocaTable::LocaIterator::HasNext() {
84   return index_ <= container()->num_glyphs_;
85 }
86 
Next()87 int32_t LocaTable::LocaIterator::Next() {
88   return container()->Loca(index_++);
89 }
90 
91 /******************************************************************************
92  * LocaTable::Builder class
93  ******************************************************************************/
Builder(Header * header,WritableFontData * data)94 LocaTable::Builder::Builder(Header* header, WritableFontData* data)
95     : Table::Builder(header, data),
96       format_version_(IndexToLocFormat::kLongOffset),
97       num_glyphs_(-1) {
98 }
99 
Builder(Header * header,ReadableFontData * data)100 LocaTable::Builder::Builder(Header* header, ReadableFontData* data)
101     : Table::Builder(header, data),
102       format_version_(IndexToLocFormat::kLongOffset),
103       num_glyphs_(-1) {
104 }
105 
~Builder()106 LocaTable::Builder::~Builder() {}
107 
108 CALLER_ATTACH
CreateBuilder(Header * header,WritableFontData * data)109 LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header,
110                                                       WritableFontData* data) {
111   Ptr<LocaTable::Builder> builder;
112   builder = new LocaTable::Builder(header, data);
113   return builder.Detach();
114 }
115 
LocaList()116 std::vector<int32_t>* LocaTable::Builder::LocaList() {
117   return GetLocaList();
118 }
119 
SetLocaList(std::vector<int32_t> * list)120 void LocaTable::Builder::SetLocaList(std::vector<int32_t>* list) {
121   loca_.clear();
122   if (list) {
123     loca_ = *list;
124     set_model_changed();
125   }
126 }
127 
GlyphOffset(int32_t glyph_id)128 int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) {
129   if (CheckGlyphRange(glyph_id) == -1) {
130     return 0;
131   }
132   return GetLocaList()->at(glyph_id);
133 }
134 
GlyphLength(int32_t glyph_id)135 int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) {
136   if (CheckGlyphRange(glyph_id) == -1) {
137     return 0;
138   }
139   return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id);
140 }
141 
SetNumGlyphs(int32_t num_glyphs)142 void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) {
143   assert(num_glyphs >= 0);
144   num_glyphs_ = num_glyphs;
145 }
146 
NumGlyphs()147 int32_t LocaTable::Builder::NumGlyphs() {
148   return LastGlyphIndex() - 1;
149 }
150 
Revert()151 void LocaTable::Builder::Revert() {
152   loca_.clear();
153   set_model_changed(false);
154 }
155 
NumLocas()156 int32_t LocaTable::Builder::NumLocas() {
157   return GetLocaList()->size();
158 }
159 
Loca(int32_t index)160 int32_t LocaTable::Builder::Loca(int32_t index) {
161   return GetLocaList()->at(index);
162 }
163 
164 CALLER_ATTACH
SubBuildTable(ReadableFontData * data)165 FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) {
166   FontDataTablePtr table =
167       new LocaTable(header(), data, format_version_, num_glyphs_);
168   return table.Detach();
169 }
170 
SubDataSet()171 void LocaTable::Builder::SubDataSet() {
172   Initialize(InternalReadData());
173 }
174 
SubDataSizeToSerialize()175 int32_t LocaTable::Builder::SubDataSizeToSerialize() {
176   if (loca_.empty()) {
177     return 0;
178   }
179   if (format_version_ == IndexToLocFormat::kLongOffset) {
180     return loca_.size() * DataSize::kULONG;
181   }
182   return loca_.size() * DataSize::kUSHORT;
183 }
184 
SubReadyToSerialize()185 bool LocaTable::Builder::SubReadyToSerialize() {
186   return !loca_.empty();
187 }
188 
SubSerialize(WritableFontData * new_data)189 int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) {
190   int32_t size = 0;
191   for (std::vector<int32_t>::iterator l = loca_.begin(), end = loca_.end();
192                              l != end; ++l) {
193     if (format_version_ == IndexToLocFormat::kLongOffset) {
194       size += new_data->WriteULong(size, *l);
195     } else {
196       size += new_data->WriteUShort(size, *l / 2);
197     }
198   }
199   num_glyphs_ = loca_.size() - 1;
200   return size;
201 }
202 
Initialize(ReadableFontData * data)203 void LocaTable::Builder::Initialize(ReadableFontData* data) {
204   ClearLoca(false);
205   if (data) {
206     if (NumGlyphs() < 0) {
207 #if !defined (SFNTLY_NO_EXCEPTION)
208       throw IllegalStateException("numglyphs not set on LocaTable Builder.");
209 #endif
210       return;
211     }
212     LocaTablePtr table =
213         new LocaTable(header(), data, format_version_, num_glyphs_);
214     Ptr<LocaTable::LocaIterator> loca_iter =
215         new LocaTable::LocaIterator(table);
216     while (loca_iter->HasNext()) {
217       loca_.push_back(loca_iter->Next());
218     }
219   }
220 }
221 
CheckGlyphRange(int32_t glyph_id)222 int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) {
223   if (glyph_id < 0 || glyph_id > LastGlyphIndex()) {
224 #if !defined (SFNTLY_NO_EXCEPTION)
225     throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range");
226 #endif
227     return -1;
228   }
229   return glyph_id;
230 }
231 
LastGlyphIndex()232 int32_t LocaTable::Builder::LastGlyphIndex() {
233   return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1;
234 }
235 
GetLocaList()236 std::vector<int32_t>* LocaTable::Builder::GetLocaList() {
237   if (loca_.empty()) {
238     Initialize(InternalReadData());
239     set_model_changed();
240   }
241   return &loca_;
242 }
243 
ClearLoca(bool nullify)244 void LocaTable::Builder::ClearLoca(bool nullify) {
245   // Note: in C++ port, nullify is not used at all.
246   UNREFERENCED_PARAMETER(nullify);
247   loca_.clear();
248   set_model_changed(false);
249 }
250 
251 }  // namespace sfntly
252