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_format1.h"
18 
19 #include "sfntly/table/bitmap/eblc_table.h"
20 
21 namespace sfntly {
22 /******************************************************************************
23  * IndexSubTableFormat1 class
24  ******************************************************************************/
25 // static
GetDataLength(ReadableFontData * data,int32_t offset,int32_t first,int32_t last)26 int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data,
27                                             int32_t offset,
28                                             int32_t first,
29                                             int32_t last) {
30   UNREFERENCED_PARAMETER(data);
31   UNREFERENCED_PARAMETER(offset);
32   return (last - first + 1 + 1) * DataSize::kULONG;
33 }
34 
~IndexSubTableFormat1()35 IndexSubTableFormat1::~IndexSubTableFormat1() {
36 }
37 
NumGlyphs()38 int32_t IndexSubTableFormat1::NumGlyphs() {
39   return last_glyph_index() - first_glyph_index() + 1;
40 }
41 
GlyphStartOffset(int32_t glyph_id)42 int32_t IndexSubTableFormat1::GlyphStartOffset(int32_t glyph_id) {
43   int32_t loca = CheckGlyphRange(glyph_id);
44   if (loca == -1) {
45     return -1;
46   }
47   return Loca(loca);
48 }
49 
GlyphLength(int32_t glyph_id)50 int32_t IndexSubTableFormat1::GlyphLength(int32_t glyph_id) {
51   int32_t loca = CheckGlyphRange(glyph_id);
52   if (loca == -1) {
53     return -1;
54   }
55   return Loca(loca + 1) - Loca(loca);
56 }
57 
IndexSubTableFormat1(ReadableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)58 IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data,
59                                            int32_t first_glyph_index,
60                                            int32_t last_glyph_index)
61     : IndexSubTable(data, first_glyph_index, last_glyph_index) {
62 }
63 
Loca(int32_t loca)64 int32_t IndexSubTableFormat1::Loca(int32_t loca) {
65   return image_data_offset() +
66          data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable1_offsetArray +
67                                loca * DataSize::kULONG);
68 }
69 
70 /******************************************************************************
71  * IndexSubTableFormat1::Builder class
72  ******************************************************************************/
~Builder()73 IndexSubTableFormat1::Builder::~Builder() {
74 }
75 
NumGlyphs()76 int32_t IndexSubTableFormat1::Builder::NumGlyphs() {
77   return GetOffsetArray()->size() - 1;
78 }
79 
GlyphLength(int32_t glyph_id)80 int32_t IndexSubTableFormat1::Builder::GlyphLength(int32_t glyph_id) {
81   int32_t loca = CheckGlyphRange(glyph_id);
82   if (loca == -1) {
83     return 0;
84   }
85   IntegerList* offset_array = GetOffsetArray();
86   return offset_array->at(loca + 1) - offset_array->at(loca);
87 }
88 
GlyphStartOffset(int32_t glyph_id)89 int32_t IndexSubTableFormat1::Builder::GlyphStartOffset(int32_t glyph_id) {
90   int32_t loca = CheckGlyphRange(glyph_id);
91   if (loca == -1) {
92     return -1;
93   }
94   return GetOffsetArray()->at(loca);
95 }
96 
97 CALLER_ATTACH IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*
GetIterator()98     IndexSubTableFormat1::Builder::GetIterator() {
99   Ptr<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator> it =
100       new IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator(this);
101   return it.Detach();
102 }
103 
104 // static
105 CALLER_ATTACH IndexSubTableFormat1::Builder*
CreateBuilder()106 IndexSubTableFormat1::Builder::CreateBuilder() {
107   IndexSubTableFormat1BuilderPtr output = new IndexSubTableFormat1::Builder();
108   return output.Detach();
109 }
110 
111 // static
112 CALLER_ATTACH IndexSubTableFormat1::Builder*
CreateBuilder(ReadableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)113 IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data,
114                                              int32_t index_sub_table_offset,
115                                              int32_t first_glyph_index,
116                                              int32_t last_glyph_index) {
117   int32_t length = Builder::DataLength(data,
118                                        index_sub_table_offset,
119                                        first_glyph_index,
120                                        last_glyph_index);
121   ReadableFontDataPtr new_data;
122   new_data.Attach(down_cast<ReadableFontData*>(
123       data->Slice(index_sub_table_offset, length)));
124   if (new_data == NULL) {
125     return NULL;
126   }
127   IndexSubTableFormat1BuilderPtr output =
128       new IndexSubTableFormat1::Builder(new_data,
129                                         first_glyph_index,
130                                         last_glyph_index);
131   return output.Detach();
132 }
133 
134 
135 // static
136 CALLER_ATTACH IndexSubTableFormat1::Builder*
CreateBuilder(WritableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)137 IndexSubTableFormat1::Builder::CreateBuilder(WritableFontData* data,
138                                              int32_t index_sub_table_offset,
139                                              int32_t first_glyph_index,
140                                              int32_t last_glyph_index) {
141   int32_t length = Builder::DataLength(data,
142                                        index_sub_table_offset,
143                                        first_glyph_index,
144                                        last_glyph_index);
145   WritableFontDataPtr new_data;
146   new_data.Attach(down_cast<WritableFontData*>(
147       data->Slice(index_sub_table_offset, length)));
148   IndexSubTableFormat1BuilderPtr output =
149       new IndexSubTableFormat1::Builder(new_data,
150                                         first_glyph_index,
151                                         last_glyph_index);
152   return output.Detach();
153 }
154 
SubBuildTable(ReadableFontData * data)155 CALLER_ATTACH FontDataTable* IndexSubTableFormat1::Builder::SubBuildTable(
156     ReadableFontData* data) {
157   IndexSubTableFormat1Ptr output = new IndexSubTableFormat1(
158       data, first_glyph_index(), last_glyph_index());
159   return output.Detach();
160 }
161 
SubDataSet()162 void IndexSubTableFormat1::Builder::SubDataSet() {
163   Revert();
164 }
165 
SubDataSizeToSerialize()166 int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() {
167   if (offset_array_.empty()) {
168     return InternalReadData()->Length();
169   }
170   return EblcTable::Offset::kIndexSubHeaderLength +
171          offset_array_.size() * DataSize::kULONG;
172 }
173 
SubReadyToSerialize()174 bool IndexSubTableFormat1::Builder::SubReadyToSerialize() {
175   if (!offset_array_.empty()) {
176     return true;
177   }
178   return false;
179 }
180 
SubSerialize(WritableFontData * new_data)181 int32_t IndexSubTableFormat1::Builder::SubSerialize(
182     WritableFontData* new_data) {
183   int32_t size = SerializeIndexSubHeader(new_data);
184   if (!model_changed()) {
185     if (InternalReadData() == NULL) {
186       return size;
187     }
188     ReadableFontDataPtr source;
189     WritableFontDataPtr target;
190     source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
191         EblcTable::Offset::kIndexSubTable1_offsetArray)));
192     target.Attach(down_cast<WritableFontData*>(new_data->Slice(
193         EblcTable::Offset::kIndexSubTable1_offsetArray)));
194     size += source->CopyTo(target);
195   } else {
196     for (IntegerList::iterator b = GetOffsetArray()->begin(),
197                                e = GetOffsetArray()->end(); b != e; b++) {
198       size += new_data->WriteLong(size, *b);
199     }
200   }
201   return size;
202 }
203 
OffsetArray()204 IntegerList* IndexSubTableFormat1::Builder::OffsetArray() {
205   return GetOffsetArray();
206 }
207 
SetOffsetArray(const IntegerList & offset_array)208 void IndexSubTableFormat1::Builder::SetOffsetArray(
209     const IntegerList& offset_array) {
210   offset_array_.clear();
211   offset_array_ = offset_array;
212   set_model_changed();
213 }
214 
Revert()215 void IndexSubTableFormat1::Builder::Revert() {
216   offset_array_.clear();
217   IndexSubTable::Builder::Revert();
218 }
219 
Builder()220 IndexSubTableFormat1::Builder::Builder()
221     : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable1_builderDataSize,
222                              IndexSubTable::Format::FORMAT_1) {
223 }
224 
Builder(WritableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)225 IndexSubTableFormat1::Builder::Builder(WritableFontData* data,
226                                        int32_t first_glyph_index,
227                                        int32_t last_glyph_index)
228     : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
229 }
230 
Builder(ReadableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)231 IndexSubTableFormat1::Builder::Builder(ReadableFontData* data,
232                                        int32_t first_glyph_index,
233                                        int32_t last_glyph_index)
234     : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
235 }
236 
GetOffsetArray()237 IntegerList* IndexSubTableFormat1::Builder::GetOffsetArray() {
238   if (offset_array_.empty()) {
239     Initialize(InternalReadData());
240     set_model_changed();
241   }
242   return &offset_array_;
243 }
244 
Initialize(ReadableFontData * data)245 void IndexSubTableFormat1::Builder::Initialize(ReadableFontData* data) {
246   offset_array_.clear();
247   if (data) {
248     int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1;
249     for (int32_t i = 0; i < num_offsets; ++i) {
250       offset_array_.push_back(data->ReadULongAsInt(
251           EblcTable::Offset::kIndexSubTable1_offsetArray +
252           i * DataSize::kULONG));
253     }
254   }
255 }
256 
257 // static
DataLength(ReadableFontData * data,int32_t index_sub_table_offset,int32_t first_glyph_index,int32_t last_glyph_index)258 int32_t IndexSubTableFormat1::Builder::DataLength(
259     ReadableFontData* data,
260     int32_t index_sub_table_offset,
261     int32_t first_glyph_index,
262     int32_t last_glyph_index) {
263   UNREFERENCED_PARAMETER(data);
264   UNREFERENCED_PARAMETER(index_sub_table_offset);
265   return EblcTable::Offset::kIndexSubHeaderLength +
266          (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kULONG;
267 }
268 
269 /******************************************************************************
270  * IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator class
271  ******************************************************************************/
BitmapGlyphInfoIterator(IndexSubTableFormat1::Builder * container)272 IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
273     IndexSubTableFormat1::Builder* container)
274     : RefIterator<BitmapGlyphInfo, IndexSubTableFormat1::Builder,
275                   IndexSubTable::Builder>(container) {
276   glyph_id_ = container->first_glyph_index();
277 }
278 
HasNext()279 bool IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::HasNext() {
280   if (glyph_id_ <= container()->last_glyph_index()) {
281     return true;
282   }
283   return false;
284 }
285 
286 CALLER_ATTACH BitmapGlyphInfo*
Next()287 IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::Next() {
288   BitmapGlyphInfoPtr output;
289   if (!HasNext()) {
290     // Note: In C++, we do not throw exception when there's no element.
291     return NULL;
292   }
293   output = new BitmapGlyphInfo(glyph_id_,
294                                container()->image_data_offset(),
295                                container()->GlyphStartOffset(glyph_id_),
296                                container()->GlyphLength(glyph_id_),
297                                container()->image_format());
298   glyph_id_++;
299   return output.Detach();
300 }
301 
302 }  // namespace sfntly
303