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   return Loca(glyph_id + 1) - Loca(glyph_id);
44 }
45 
NumLocas()46 int32_t LocaTable::NumLocas() {
47   return num_glyphs_ + 1;
48 }
49 
Loca(int32_t index)50 int32_t LocaTable::Loca(int32_t index) {
51   if (index > num_glyphs_) {
52 #if !defined (SFNTLY_NO_EXCEPTION)
53     throw IndexOutOfBoundException();
54 #endif
55     return 0;
56   }
57   if (format_version_ == IndexToLocFormat::kShortOffset) {
58     return 2 * data_->ReadUShort(index * DataSize::kUSHORT);
59   }
60   return data_->ReadULongAsInt(index * DataSize::kULONG);
61 }
62 
LocaTable(Header * header,ReadableFontData * data,int32_t format_version,int32_t num_glyphs)63 LocaTable::LocaTable(Header* header,
64                      ReadableFontData* data,
65                      int32_t format_version,
66                      int32_t num_glyphs)
67     : Table(header, data),
68       format_version_(format_version),
69       num_glyphs_(num_glyphs) {
70 }
71 
72 /******************************************************************************
73  * LocaTable::Iterator class
74  ******************************************************************************/
LocaIterator(LocaTable * table)75 LocaTable::LocaIterator::LocaIterator(LocaTable* table)
76     : PODIterator<int32_t, LocaTable>(table), index_(-1) {
77 }
78 
HasNext()79 bool LocaTable::LocaIterator::HasNext() {
80   return index_ <= container()->num_glyphs_;
81 }
82 
Next()83 int32_t LocaTable::LocaIterator::Next() {
84   return container()->Loca(index_++);
85 }
86 
87 /******************************************************************************
88  * LocaTable::Builder class
89  ******************************************************************************/
Builder(Header * header,WritableFontData * data)90 LocaTable::Builder::Builder(Header* header, WritableFontData* data)
91     : Table::Builder(header, data),
92       format_version_(IndexToLocFormat::kLongOffset),
93       num_glyphs_(-1) {
94 }
95 
Builder(Header * header,ReadableFontData * data)96 LocaTable::Builder::Builder(Header* header, ReadableFontData* data)
97     : Table::Builder(header, data),
98       format_version_(IndexToLocFormat::kLongOffset),
99       num_glyphs_(-1) {
100 }
101 
~Builder()102 LocaTable::Builder::~Builder() {}
103 
104 CALLER_ATTACH
CreateBuilder(Header * header,WritableFontData * data)105 LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header,
106                                                       WritableFontData* data) {
107   Ptr<LocaTable::Builder> builder;
108   builder = new LocaTable::Builder(header, data);
109   return builder.Detach();
110 }
111 
LocaList()112 IntegerList* LocaTable::Builder::LocaList() {
113   return GetLocaList();
114 }
115 
SetLocaList(IntegerList * list)116 void LocaTable::Builder::SetLocaList(IntegerList* list) {
117   loca_.clear();
118   if (list) {
119     loca_ = *list;
120     set_model_changed();
121   }
122 }
123 
GlyphOffset(int32_t glyph_id)124 int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) {
125   if (CheckGlyphRange(glyph_id) == -1) {
126     return 0;
127   }
128   return GetLocaList()->at(glyph_id);
129 }
130 
GlyphLength(int32_t glyph_id)131 int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) {
132   if (CheckGlyphRange(glyph_id) == -1) {
133     return 0;
134   }
135   return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id);
136 }
137 
SetNumGlyphs(int32_t num_glyphs)138 void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) {
139   num_glyphs_ = num_glyphs;
140 }
141 
NumGlyphs()142 int32_t LocaTable::Builder::NumGlyphs() {
143   return LastGlyphIndex() - 1;
144 }
145 
Revert()146 void LocaTable::Builder::Revert() {
147   loca_.clear();
148   set_model_changed(false);
149 }
150 
NumLocas()151 int32_t LocaTable::Builder::NumLocas() {
152   return GetLocaList()->size();
153 }
154 
Loca(int32_t index)155 int32_t LocaTable::Builder::Loca(int32_t index) {
156   return GetLocaList()->at(index);
157 }
158 
159 CALLER_ATTACH
SubBuildTable(ReadableFontData * data)160 FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) {
161   FontDataTablePtr table =
162       new LocaTable(header(), data, format_version_, num_glyphs_);
163   return table.Detach();
164 }
165 
SubDataSet()166 void LocaTable::Builder::SubDataSet() {
167   Initialize(InternalReadData());
168 }
169 
SubDataSizeToSerialize()170 int32_t LocaTable::Builder::SubDataSizeToSerialize() {
171   if (loca_.empty()) {
172     return 0;
173   }
174   if (format_version_ == IndexToLocFormat::kLongOffset) {
175     return loca_.size() * DataSize::kULONG;
176   }
177   return loca_.size() * DataSize::kUSHORT;
178 }
179 
SubReadyToSerialize()180 bool LocaTable::Builder::SubReadyToSerialize() {
181   return !loca_.empty();
182 }
183 
SubSerialize(WritableFontData * new_data)184 int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) {
185   int32_t size = 0;
186   for (IntegerList::iterator l = loca_.begin(), end = loca_.end();
187                              l != end; ++l) {
188     if (format_version_ == IndexToLocFormat::kLongOffset) {
189       size += new_data->WriteULong(size, *l);
190     } else {
191       size += new_data->WriteUShort(size, *l / 2);
192     }
193   }
194   num_glyphs_ = loca_.size() - 1;
195   return size;
196 }
197 
Initialize(ReadableFontData * data)198 void LocaTable::Builder::Initialize(ReadableFontData* data) {
199   ClearLoca(false);
200   if (data) {
201     if (NumGlyphs() < 0) {
202 #if !defined (SFNTLY_NO_EXCEPTION)
203       throw IllegalStateException("numglyphs not set on LocaTable Builder.");
204 #endif
205       return;
206     }
207     LocaTablePtr table =
208         new LocaTable(header(), data, format_version_, num_glyphs_);
209     Ptr<LocaTable::LocaIterator> loca_iter =
210         new LocaTable::LocaIterator(table);
211     while (loca_iter->HasNext()) {
212       loca_.push_back(loca_iter->Next());
213     }
214   }
215 }
216 
CheckGlyphRange(int32_t glyph_id)217 int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) {
218   if (glyph_id < 0 || glyph_id > LastGlyphIndex()) {
219 #if !defined (SFNTLY_NO_EXCEPTION)
220     throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range");
221 #endif
222     return -1;
223   }
224   return glyph_id;
225 }
226 
LastGlyphIndex()227 int32_t LocaTable::Builder::LastGlyphIndex() {
228   return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1;
229 }
230 
GetLocaList()231 IntegerList* LocaTable::Builder::GetLocaList() {
232   if (loca_.empty()) {
233     Initialize(InternalReadData());
234     set_model_changed();
235   }
236   return &loca_;
237 }
238 
ClearLoca(bool nullify)239 void LocaTable::Builder::ClearLoca(bool nullify) {
240   // Note: in C++ port, nullify is not used at all.
241   UNREFERENCED_PARAMETER(nullify);
242   loca_.clear();
243   set_model_changed(false);
244 }
245 
246 }  // namespace sfntly
247