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   std::vector<int32_t>* glyph_array = GetGlyphArray();
108   std::vector<int32_t>::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 (std::vector<int32_t>::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 std::vector<int32_t>* IndexSubTableFormat5::Builder::GlyphArray() {
249   return GetGlyphArray();
250 }
251 
SetGlyphArray(const std::vector<int32_t> & v)252 void IndexSubTableFormat5::Builder::SetGlyphArray(const std::vector<int32_t>& 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 std::vector<int32_t>* 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