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/bitmap/index_sub_table_format5.h"
18
19 #include <algorithm>
20
21 #include "sfntly/table/bitmap/eblc_table.h"
22
23 namespace sfntly {
24 /******************************************************************************
25 * IndexSubTableFormat5 class
26 ******************************************************************************/
~IndexSubTableFormat5()27 IndexSubTableFormat5::~IndexSubTableFormat5() {
28 }
29
NumGlyphs()30 int32_t IndexSubTableFormat5::NumGlyphs() {
31 return NumGlyphs(data_, 0);
32 }
33
GlyphStartOffset(int32_t glyph_id)34 int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) {
35 int32_t check = CheckGlyphRange(glyph_id);
36 if (check == -1) {
37 return -1;
38 }
39 int32_t loca = ReadFontData()->SearchUShort(
40 EblcTable::Offset::kIndexSubTable5_glyphArray,
41 DataSize::kUSHORT,
42 NumGlyphs(),
43 glyph_id);
44 if (loca == -1) {
45 return loca;
46 }
47 return loca * ImageSize();
48 }
49
GlyphLength(int32_t glyph_id)50 int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) {
51 int32_t check = CheckGlyphRange(glyph_id);
52 if (check == -1) {
53 return 0;
54 }
55 return image_size_;
56 }
57
ImageSize()58 int32_t IndexSubTableFormat5::ImageSize() {
59 return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize);
60 }
61
BigMetrics()62 CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() {
63 ReadableFontDataPtr data;
64 data.Attach(down_cast<ReadableFontData*>(data_->Slice(
65 EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics,
66 BigGlyphMetrics::Offset::kMetricsLength)));
67 BigGlyphMetricsPtr output = new BigGlyphMetrics(data);
68 return output.Detach();
69 }
70
IndexSubTableFormat5(ReadableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)71 IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data,
72 int32_t first_glyph_index,
73 int32_t last_glyph_index)
74 : IndexSubTable(data, first_glyph_index, last_glyph_index) {
75 image_size_ = data_->ReadULongAsInt(
76 EblcTable::Offset::kIndexSubTable5_imageSize);
77 }
78
79 // static
NumGlyphs(ReadableFontData * data,int32_t table_offset)80 int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data,
81 int32_t table_offset) {
82 int32_t num_glyphs = data->ReadULongAsInt(table_offset +
83 EblcTable::Offset::kIndexSubTable5_numGlyphs);
84 return num_glyphs;
85 }
86
87 /******************************************************************************
88 * IndexSubTableFormat5::Builder class
89 ******************************************************************************/
~Builder()90 IndexSubTableFormat5::Builder::~Builder() {
91 }
92
NumGlyphs()93 int32_t IndexSubTableFormat5::Builder::NumGlyphs() {
94 return GetGlyphArray()->size();
95 }
96
GlyphLength(int32_t glyph_id)97 int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) {
98 UNREFERENCED_PARAMETER(glyph_id);
99 return ImageSize();
100 }
101
GlyphStartOffset(int32_t glyph_id)102 int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) {
103 int32_t check = CheckGlyphRange(glyph_id);
104 if (check == -1) {
105 return -1;
106 }
107 IntegerList* glyph_array = GetGlyphArray();
108 IntegerList::iterator it = std::find(glyph_array->begin(),
109 glyph_array->end(),
110 glyph_id);
111 if (it == glyph_array->end()) {
112 return -1;
113 }
114 return (it - glyph_array->begin()) * ImageSize();
115 }
116
117 CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*
GetIterator()118 IndexSubTableFormat5::Builder::GetIterator() {
119 Ptr<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator> it =
120 new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this);
121 return it.Detach();
122 }
123
124 // static
125 CALLER_ATTACH IndexSubTableFormat5::Builder*
CreateBuilder()126 IndexSubTableFormat5::Builder::CreateBuilder() {
127 IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder();
128 return output.Detach();
129 }
130
131 // static
132 CALLER_ATTACH IndexSubTableFormat5::Builder*
CreateBuilder(ReadableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)133 IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data,
134 int32_t index_sub_table_offset,
135 int32_t first_glyph_index,
136 int32_t last_glyph_index) {
137 int32_t length = Builder::DataLength(data,
138 index_sub_table_offset,
139 first_glyph_index,
140 last_glyph_index);
141 ReadableFontDataPtr new_data;
142 new_data.Attach(down_cast<ReadableFontData*>(
143 data->Slice(index_sub_table_offset, length)));
144 if (new_data == NULL) {
145 return NULL;
146 }
147 IndexSubTableFormat5BuilderPtr output =
148 new IndexSubTableFormat5::Builder(new_data,
149 first_glyph_index,
150 last_glyph_index);
151 return output.Detach();
152 }
153
154 // static
155 CALLER_ATTACH IndexSubTableFormat5::Builder*
CreateBuilder(WritableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)156 IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data,
157 int32_t index_sub_table_offset,
158 int32_t first_glyph_index,
159 int32_t last_glyph_index) {
160 int32_t length = Builder::DataLength(data,
161 index_sub_table_offset,
162 first_glyph_index,
163 last_glyph_index);
164 WritableFontDataPtr new_data;
165 new_data.Attach(down_cast<WritableFontData*>(
166 data->Slice(index_sub_table_offset, length)));
167 IndexSubTableFormat5BuilderPtr output =
168 new IndexSubTableFormat5::Builder(new_data,
169 first_glyph_index,
170 last_glyph_index);
171 return output.Detach();
172 }
173
SubBuildTable(ReadableFontData * data)174 CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable(
175 ReadableFontData* data) {
176 IndexSubTableFormat5Ptr output = new IndexSubTableFormat5(
177 data, first_glyph_index(), last_glyph_index());
178 return output.Detach();
179 }
180
SubDataSet()181 void IndexSubTableFormat5::Builder::SubDataSet() {
182 Revert();
183 }
184
SubDataSizeToSerialize()185 int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() {
186 if (glyph_array_.empty()) {
187 return InternalReadData()->Length();
188 }
189 return EblcTable::Offset::kIndexSubTable5_builderDataSize +
190 glyph_array_.size() * DataSize::kUSHORT;
191 }
192
SubReadyToSerialize()193 bool IndexSubTableFormat5::Builder::SubReadyToSerialize() {
194 if (!glyph_array_.empty()) {
195 return true;
196 }
197 return false;
198 }
199
SubSerialize(WritableFontData * new_data)200 int32_t IndexSubTableFormat5::Builder::SubSerialize(
201 WritableFontData* new_data) {
202 int32_t size = SerializeIndexSubHeader(new_data);
203 if (!model_changed()) {
204 ReadableFontDataPtr source;
205 WritableFontDataPtr target;
206 source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
207 EblcTable::Offset::kIndexSubTable5_imageSize)));
208 target.Attach(down_cast<WritableFontData*>(new_data->Slice(
209 EblcTable::Offset::kIndexSubTable5_imageSize)));
210 size += source->CopyTo(target);
211 } else {
212 size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize,
213 ImageSize());
214 WritableFontDataPtr slice;
215 slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
216 size += BigMetrics()->SubSerialize(slice);
217 size += new_data->WriteULong(size, glyph_array_.size());
218 for (IntegerList::iterator b = glyph_array_.begin(), e = glyph_array_.end();
219 b != e; b++) {
220 size += new_data->WriteUShort(size, *b);
221 }
222 }
223 return size;
224 }
225
ImageSize()226 int32_t IndexSubTableFormat5::Builder::ImageSize() {
227 return InternalReadData()->ReadULongAsInt(
228 EblcTable::Offset::kIndexSubTable5_imageSize);
229 }
230
SetImageSize(int32_t image_size)231 void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) {
232 InternalWriteData()->WriteULong(
233 EblcTable::Offset::kIndexSubTable5_imageSize, image_size);
234 }
235
BigMetrics()236 BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() {
237 if (metrics_ == NULL) {
238 WritableFontDataPtr data;
239 data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice(
240 EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics,
241 BigGlyphMetrics::Offset::kMetricsLength)));
242 metrics_ = new BigGlyphMetrics::Builder(data);
243 set_model_changed();
244 }
245 return metrics_;
246 }
247
GlyphArray()248 IntegerList* IndexSubTableFormat5::Builder::GlyphArray() {
249 return GetGlyphArray();
250 }
251
SetGlyphArray(const IntegerList & v)252 void IndexSubTableFormat5::Builder::SetGlyphArray(const IntegerList& v) {
253 glyph_array_.clear();
254 glyph_array_ = v;
255 set_model_changed();
256 }
257
Revert()258 void IndexSubTableFormat5::Builder::Revert() {
259 glyph_array_.clear();
260 IndexSubTable::Builder::Revert();
261 }
262
Builder()263 IndexSubTableFormat5::Builder::Builder()
264 : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize,
265 IndexSubTable::Format::FORMAT_5) {
266 }
267
Builder(WritableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)268 IndexSubTableFormat5::Builder::Builder(WritableFontData* data,
269 int32_t first_glyph_index,
270 int32_t last_glyph_index)
271 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
272 }
273
Builder(ReadableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)274 IndexSubTableFormat5::Builder::Builder(ReadableFontData* data,
275 int32_t first_glyph_index,
276 int32_t last_glyph_index)
277 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
278 }
279
GetGlyphArray()280 IntegerList* IndexSubTableFormat5::Builder::GetGlyphArray() {
281 if (glyph_array_.empty()) {
282 Initialize(InternalReadData());
283 set_model_changed();
284 }
285 return &glyph_array_;
286 }
287
Initialize(ReadableFontData * data)288 void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) {
289 glyph_array_.clear();
290 if (data) {
291 int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0);
292 for (int32_t i = 0; i < num_glyphs; ++i) {
293 glyph_array_.push_back(data->ReadUShort(
294 EblcTable::Offset::kIndexSubTable5_glyphArray +
295 i * DataSize::kUSHORT));
296 }
297 }
298 }
299
300 // static
DataLength(ReadableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)301 int32_t IndexSubTableFormat5::Builder::DataLength(
302 ReadableFontData* data,
303 int32_t index_sub_table_offset,
304 int32_t first_glyph_index,
305 int32_t last_glyph_index) {
306 int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data,
307 index_sub_table_offset);
308 UNREFERENCED_PARAMETER(first_glyph_index);
309 UNREFERENCED_PARAMETER(last_glyph_index);
310 return EblcTable::Offset::kIndexSubTable5_glyphArray +
311 num_glyphs * DataSize::kUSHORT;
312 }
313
314 /******************************************************************************
315 * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class
316 ******************************************************************************/
BitmapGlyphInfoIterator(IndexSubTableFormat5::Builder * container)317 IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
318 IndexSubTableFormat5::Builder* container)
319 : RefIterator<BitmapGlyphInfo, IndexSubTableFormat5::Builder,
320 IndexSubTable::Builder>(container),
321 offset_index_(0) {
322 }
323
HasNext()324 bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() {
325 if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) {
326 return true;
327 }
328 return false;
329 }
330
331 CALLER_ATTACH BitmapGlyphInfo*
Next()332 IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() {
333 BitmapGlyphInfoPtr output;
334 if (!HasNext()) {
335 // Note: In C++, we do not throw exception when there's no element.
336 return NULL;
337 }
338 output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_),
339 container()->image_data_offset(),
340 offset_index_ * container()->ImageSize(),
341 container()->ImageSize(),
342 container()->image_format());
343 offset_index_++;
344 return output.Detach();
345 }
346
347 } // namespace sfntly
348