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.h"
18 
19 #include "sfntly/table/bitmap/eblc_table.h"
20 #include "sfntly/table/bitmap/index_sub_table_format1.h"
21 #include "sfntly/table/bitmap/index_sub_table_format2.h"
22 #include "sfntly/table/bitmap/index_sub_table_format3.h"
23 #include "sfntly/table/bitmap/index_sub_table_format4.h"
24 #include "sfntly/table/bitmap/index_sub_table_format5.h"
25 
26 namespace sfntly {
27 /******************************************************************************
28  * IndexSubTable class
29  ******************************************************************************/
GlyphInfo(int32_t glyph_id)30 CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::GlyphInfo(int32_t glyph_id) {
31   int32_t loca = CheckGlyphRange(glyph_id);
32   if (loca == -1) {
33     return NULL;
34   }
35   if (GlyphStartOffset(glyph_id) == -1) {
36     return NULL;
37   }
38   BitmapGlyphInfoPtr output = new BitmapGlyphInfo(glyph_id,
39                                                   image_data_offset(),
40                                                   GlyphStartOffset(glyph_id),
41                                                   GlyphLength(glyph_id),
42                                                   image_format());
43   return output.Detach();
44 }
45 
GlyphOffset(int32_t glyph_id)46 int32_t IndexSubTable::GlyphOffset(int32_t glyph_id) {
47   int32_t glyph_start_offset = GlyphStartOffset(glyph_id);
48   if (glyph_start_offset == -1) {
49     return -1;
50   }
51   return image_data_offset() + glyph_start_offset;
52 }
53 
54 // static
55 CALLER_ATTACH IndexSubTable*
CreateIndexSubTable(ReadableFontData * data,int32_t offset_to_index_sub_table_array,int32_t array_index)56     IndexSubTable::CreateIndexSubTable(ReadableFontData* data,
57                                        int32_t offset_to_index_sub_table_array,
58                                        int32_t array_index) {
59   IndexSubTableBuilderPtr builder;
60   builder.Attach(IndexSubTable::Builder::CreateBuilder(
61       data, offset_to_index_sub_table_array, array_index));
62   return down_cast<IndexSubTable*>(builder->Build());
63 }
64 
IndexSubTable(ReadableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)65 IndexSubTable::IndexSubTable(ReadableFontData* data,
66                              int32_t first_glyph_index,
67                              int32_t last_glyph_index)
68     : SubTable(data),
69       first_glyph_index_(first_glyph_index),
70       last_glyph_index_(last_glyph_index) {
71   index_format_ =
72       data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat);
73   image_format_ =
74       data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat);
75   image_data_offset_ =
76       data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset);
77 }
78 
CheckGlyphRange(int32_t glyph_id)79 int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id) {
80   return CheckGlyphRange(glyph_id, first_glyph_index(), last_glyph_index());
81 }
82 
83 // static
CheckGlyphRange(int32_t glyph_id,int32_t first_glyph_id,int32_t last_glyph_id)84 int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id,
85                                        int32_t first_glyph_id,
86                                        int32_t last_glyph_id) {
87   if (glyph_id < first_glyph_id || glyph_id > last_glyph_id) {
88 #if !defined (SFNTLY_NO_EXCEPTION)
89     throw IndexOutOfBoundException("Glyph ID is outside of the allowed range.");
90 #endif
91     return -1;
92   }
93   return glyph_id - first_glyph_id;
94 }
95 
96 /******************************************************************************
97  * IndexSubTable::Builder class
98  ******************************************************************************/
~Builder()99 IndexSubTable::Builder::~Builder() {
100 }
101 
Revert()102 void IndexSubTable::Builder::Revert() {
103   set_model_changed(false);
104   Initialize(InternalReadData());
105 }
106 
GlyphInfo(int32_t glyph_id)107 CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::Builder::GlyphInfo(
108     int32_t glyph_id) {
109   BitmapGlyphInfoPtr glyph_info =
110       new BitmapGlyphInfo(glyph_id,
111                           image_data_offset(),
112                           GlyphStartOffset(glyph_id),
113                           GlyphLength(glyph_id),
114                           image_format());
115   return glyph_info.Detach();
116 }
117 
GlyphOffset(int32_t glyph_id)118 int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) {
119   return image_data_offset() + GlyphStartOffset(glyph_id);
120 }
121 
122 // static
123 CALLER_ATTACH IndexSubTable::Builder*
CreateBuilder(int32_t index_format)124 IndexSubTable::Builder::CreateBuilder(int32_t index_format) {
125   switch (index_format) {
126     case Format::FORMAT_1:
127       return IndexSubTableFormat1::Builder::CreateBuilder();
128     case Format::FORMAT_2:
129       return IndexSubTableFormat2::Builder::CreateBuilder();
130     case Format::FORMAT_3:
131       return IndexSubTableFormat3::Builder::CreateBuilder();
132     case Format::FORMAT_4:
133       return IndexSubTableFormat4::Builder::CreateBuilder();
134     case Format::FORMAT_5:
135       return IndexSubTableFormat5::Builder::CreateBuilder();
136     default:
137 #if !defined (SFNTLY_NO_EXCEPTION)
138       throw IllegalArgumentException("Invalid index subtable format");
139 #endif
140       return NULL;
141   }
142 }
143 
144 // static
145 CALLER_ATTACH IndexSubTable::Builder*
CreateBuilder(ReadableFontData * data,int32_t offset_to_index_sub_table_array,int32_t array_index)146 IndexSubTable::Builder::CreateBuilder(ReadableFontData* data,
147     int32_t offset_to_index_sub_table_array, int32_t array_index) {
148   int32_t index_sub_table_entry_offset =
149       offset_to_index_sub_table_array +
150       array_index * EblcTable::Offset::kIndexSubTableEntryLength;
151   int32_t first_glyph_index =
152       data->ReadUShort(index_sub_table_entry_offset +
153                        EblcTable::Offset::kIndexSubTableEntry_firstGlyphIndex);
154   int32_t last_glyph_index =
155       data->ReadUShort(index_sub_table_entry_offset +
156                        EblcTable::Offset::kIndexSubTableEntry_lastGlyphIndex);
157   int32_t additional_offset_to_index_subtable = data->ReadULongAsInt(
158       index_sub_table_entry_offset +
159       EblcTable::Offset::kIndexSubTableEntry_additionalOffsetToIndexSubTable);
160   int32_t index_sub_table_offset = offset_to_index_sub_table_array +
161                                    additional_offset_to_index_subtable;
162   int32_t index_format = data->ReadUShort(index_sub_table_offset);
163   switch (index_format) {
164     case 1:
165       return IndexSubTableFormat1::Builder::CreateBuilder(
166           data, index_sub_table_offset, first_glyph_index, last_glyph_index);
167     case 2:
168       return IndexSubTableFormat2::Builder::CreateBuilder(
169           data, index_sub_table_offset, first_glyph_index, last_glyph_index);
170     case 3:
171       return IndexSubTableFormat3::Builder::CreateBuilder(
172           data, index_sub_table_offset, first_glyph_index, last_glyph_index);
173     case 4:
174       return IndexSubTableFormat4::Builder::CreateBuilder(
175           data, index_sub_table_offset, first_glyph_index, last_glyph_index);
176     case 5:
177       return IndexSubTableFormat5::Builder::CreateBuilder(
178           data, index_sub_table_offset, first_glyph_index, last_glyph_index);
179     default:
180       // Unknown format and unable to process.
181 #if !defined (SFNTLY_NO_EXCEPTION)
182       throw IllegalArgumentException("Invalid Index Subtable Format");
183 #endif
184       break;
185   }
186   return NULL;
187 }
188 
189 CALLER_ATTACH
SubBuildTable(ReadableFontData * data)190 FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) {
191   UNREFERENCED_PARAMETER(data);
192   return NULL;
193 }
194 
SubDataSet()195 void IndexSubTable::Builder::SubDataSet() {
196   // NOP
197 }
198 
SubDataSizeToSerialize()199 int32_t IndexSubTable::Builder::SubDataSizeToSerialize() {
200   return 0;
201 }
202 
SubReadyToSerialize()203 bool IndexSubTable::Builder::SubReadyToSerialize() {
204   return false;
205 }
206 
SubSerialize(WritableFontData * new_data)207 int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) {
208   UNREFERENCED_PARAMETER(new_data);
209   return 0;
210 }
211 
Builder(int32_t data_size,int32_t index_format)212 IndexSubTable::Builder::Builder(int32_t data_size, int32_t index_format)
213     : SubTable::Builder(data_size),
214       first_glyph_index_(0),
215       last_glyph_index_(0),
216       index_format_(index_format),
217       image_format_(0),
218       image_data_offset_(0) {
219 }
220 
Builder(int32_t index_format,int32_t image_format,int32_t image_data_offset,int32_t data_size)221 IndexSubTable::Builder::Builder(int32_t index_format,
222                                 int32_t image_format,
223                                 int32_t image_data_offset,
224                                 int32_t data_size)
225     : SubTable::Builder(data_size),
226       first_glyph_index_(0),
227       last_glyph_index_(0),
228       index_format_(index_format),
229       image_format_(image_format),
230       image_data_offset_(image_data_offset) {
231 }
232 
Builder(WritableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)233 IndexSubTable::Builder::Builder(WritableFontData* data,
234                                 int32_t first_glyph_index,
235                                 int32_t last_glyph_index)
236     : SubTable::Builder(data),
237       first_glyph_index_(first_glyph_index),
238       last_glyph_index_(last_glyph_index) {
239   Initialize(data);
240 }
241 
Builder(ReadableFontData * data,int32_t first_glyph_index,int32_t last_glyph_index)242 IndexSubTable::Builder::Builder(ReadableFontData* data,
243                                 int32_t first_glyph_index,
244                                 int32_t last_glyph_index)
245     : SubTable::Builder(data),
246       first_glyph_index_(first_glyph_index),
247       last_glyph_index_(last_glyph_index) {
248   Initialize(data);
249 }
250 
CheckGlyphRange(int32_t glyph_id)251 int32_t IndexSubTable::Builder::CheckGlyphRange(int32_t glyph_id) {
252   return IndexSubTable::CheckGlyphRange(glyph_id,
253                                         first_glyph_index(),
254                                         last_glyph_index());
255 }
256 
SerializeIndexSubHeader(WritableFontData * data)257 int32_t IndexSubTable::Builder::SerializeIndexSubHeader(
258     WritableFontData* data) {
259   int32_t size =
260       data->WriteUShort(EblcTable::Offset::kIndexSubHeader_indexFormat,
261                         index_format());
262   size += data->WriteUShort(EblcTable::Offset::kIndexSubHeader_imageFormat,
263                             image_format());
264   size += data->WriteULong(EblcTable::Offset::kIndexSubHeader_imageDataOffset,
265                            image_data_offset());
266   return size;
267 }
268 
Initialize(ReadableFontData * data)269 void IndexSubTable::Builder::Initialize(ReadableFontData* data) {
270   index_format_ =
271       data->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat);
272   image_format_ =
273       data->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat);
274   image_data_offset_ =
275       data->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset);
276 }
277 
278 }  // namespace sfntly
279