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_format4.h" 18 19 #include "sfntly/table/bitmap/eblc_table.h" 20 21 namespace sfntly { 22 /****************************************************************************** 23 * IndexSubTableFormat4 class 24 ******************************************************************************/ 25 IndexSubTableFormat4::~IndexSubTableFormat4() { 26 } 27 28 int32_t IndexSubTableFormat4::NumGlyphs() { 29 return IndexSubTableFormat4::NumGlyphs(data_, 0); 30 } 31 32 int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) { 33 int32_t loca = CheckGlyphRange(glyph_id); 34 if (loca == -1) { 35 return -1; 36 } 37 int32_t pair_index = FindCodeOffsetPair(glyph_id); 38 if (pair_index < 0) { 39 return -1; 40 } 41 return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray + 42 pair_index * 43 EblcTable::Offset::kCodeOffsetPairLength + 44 EblcTable::Offset::kCodeOffsetPair_offset); 45 } 46 47 int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) { 48 int32_t loca = CheckGlyphRange(glyph_id); 49 if (loca == -1) { 50 return -1; 51 } 52 53 int32_t pair_index = FindCodeOffsetPair(glyph_id); 54 if (pair_index < 0) { 55 return -1; 56 } 57 return data_->ReadUShort( 58 EblcTable::Offset::kIndexSubTable4_glyphArray + 59 (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength + 60 EblcTable::Offset::kCodeOffsetPair_offset) - 61 data_->ReadUShort( 62 EblcTable::Offset::kIndexSubTable4_glyphArray + 63 (pair_index) * EblcTable::Offset::kCodeOffsetPairLength + 64 EblcTable::Offset::kCodeOffsetPair_offset); 65 } 66 67 IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data, 68 int32_t first, 69 int32_t last) 70 : IndexSubTable(data, first, last) { 71 } 72 73 int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) { 74 return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray, 75 EblcTable::Offset::kCodeOffsetPairLength, 76 NumGlyphs(), 77 glyph_id); 78 } 79 80 int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data, 81 int32_t table_offset) { 82 int32_t num_glyphs = data->ReadULongAsInt(table_offset + 83 EblcTable::Offset::kIndexSubTable4_numGlyphs); 84 return num_glyphs; 85 } 86 87 /****************************************************************************** 88 * IndexSubTableFormat4::CodeOffsetPair related class 89 ******************************************************************************/ 90 IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code, 91 int32_t offset) 92 : glyph_code_(glyph_code), offset_(offset) { 93 } 94 95 IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder() 96 : CodeOffsetPair(0, 0) { 97 } 98 99 IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder( 100 int32_t glyph_code, int32_t offset) 101 : CodeOffsetPair(glyph_code, offset) { 102 } 103 104 bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()( 105 const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) { 106 return lhs.glyph_code() < rhs.glyph_code(); 107 } 108 109 /****************************************************************************** 110 * IndexSubTableFormat4::Builder class 111 ******************************************************************************/ 112 IndexSubTableFormat4::Builder::~Builder() { 113 } 114 115 int32_t IndexSubTableFormat4::Builder::NumGlyphs() { 116 return GetOffsetArray()->size() - 1; 117 } 118 119 int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) { 120 int32_t loca = CheckGlyphRange(glyph_id); 121 if (loca == -1) { 122 return 0; 123 } 124 int32_t pair_index = FindCodeOffsetPair(glyph_id); 125 if (pair_index == -1) { 126 return 0; 127 } 128 return GetOffsetArray()->at(pair_index + 1).offset() - 129 GetOffsetArray()->at(pair_index).offset(); 130 } 131 132 int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) { 133 int32_t loca = CheckGlyphRange(glyph_id); 134 if (loca == -1) { 135 return -1; 136 } 137 int32_t pair_index = FindCodeOffsetPair(glyph_id); 138 if (pair_index == -1) { 139 return -1; 140 } 141 return GetOffsetArray()->at(pair_index).offset(); 142 } 143 144 CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* 145 IndexSubTableFormat4::Builder::GetIterator() { 146 Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it = 147 new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this); 148 return it.Detach(); 149 } 150 151 // static 152 CALLER_ATTACH IndexSubTableFormat4::Builder* 153 IndexSubTableFormat4::Builder::CreateBuilder() { 154 IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder(); 155 return output.Detach(); 156 } 157 158 // static 159 CALLER_ATTACH IndexSubTableFormat4::Builder* 160 IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data, 161 int32_t index_sub_table_offset, 162 int32_t first_glyph_index, 163 int32_t last_glyph_index) { 164 int32_t length = Builder::DataLength(data, 165 index_sub_table_offset, 166 first_glyph_index, 167 last_glyph_index); 168 ReadableFontDataPtr new_data; 169 new_data.Attach(down_cast<ReadableFontData*>( 170 data->Slice(index_sub_table_offset, length))); 171 if (new_data == NULL) { 172 return NULL; 173 } 174 IndexSubTableFormat4BuilderPtr output = 175 new IndexSubTableFormat4::Builder(new_data, 176 first_glyph_index, 177 last_glyph_index); 178 return output.Detach(); 179 } 180 181 // static 182 CALLER_ATTACH IndexSubTableFormat4::Builder* 183 IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data, 184 int32_t index_sub_table_offset, 185 int32_t first_glyph_index, 186 int32_t last_glyph_index) { 187 int32_t length = Builder::DataLength(data, 188 index_sub_table_offset, 189 first_glyph_index, 190 last_glyph_index); 191 WritableFontDataPtr new_data; 192 new_data.Attach(down_cast<WritableFontData*>( 193 data->Slice(index_sub_table_offset, length))); 194 IndexSubTableFormat4BuilderPtr output = 195 new IndexSubTableFormat4::Builder(new_data, 196 first_glyph_index, 197 last_glyph_index); 198 return output.Detach(); 199 } 200 201 CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable( 202 ReadableFontData* data) { 203 IndexSubTableFormat4Ptr output = new IndexSubTableFormat4( 204 data, first_glyph_index(), last_glyph_index()); 205 return output.Detach(); 206 } 207 208 void IndexSubTableFormat4::Builder::SubDataSet() { 209 Revert(); 210 } 211 212 int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() { 213 if (offset_pair_array_.empty()) { 214 return InternalReadData()->Length(); 215 } 216 return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG + 217 GetOffsetArray()->size() * 218 EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; 219 } 220 221 bool IndexSubTableFormat4::Builder::SubReadyToSerialize() { 222 if (!offset_pair_array_.empty()) { 223 return true; 224 } 225 return false; 226 } 227 228 int32_t IndexSubTableFormat4::Builder::SubSerialize( 229 WritableFontData* new_data) { 230 int32_t size = SerializeIndexSubHeader(new_data); 231 if (!model_changed()) { 232 if (InternalReadData() == NULL) { 233 return size; 234 } 235 ReadableFontDataPtr source; 236 WritableFontDataPtr target; 237 source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( 238 EblcTable::Offset::kIndexSubTable4_glyphArray))); 239 target.Attach(down_cast<WritableFontData*>(new_data->Slice( 240 EblcTable::Offset::kIndexSubTable4_glyphArray))); 241 size += source->CopyTo(target); 242 } else { 243 size += new_data->WriteLong(size, offset_pair_array_.size() - 1); 244 for (std::vector<CodeOffsetPairBuilder>::iterator 245 b = GetOffsetArray()->begin(), e = GetOffsetArray()->end(); 246 b != e; b++) { 247 size += new_data->WriteUShort(size, b->glyph_code()); 248 size += new_data->WriteUShort(size, b->offset()); 249 } 250 } 251 return size; 252 } 253 254 void IndexSubTableFormat4::Builder::Revert() { 255 offset_pair_array_.clear(); 256 IndexSubTable::Builder::Revert(); 257 } 258 259 void IndexSubTableFormat4::Builder::SetOffsetArray( 260 const std::vector<CodeOffsetPairBuilder>& pair_array) { 261 offset_pair_array_.clear(); 262 offset_pair_array_ = pair_array; 263 set_model_changed(); 264 } 265 266 IndexSubTableFormat4::Builder::Builder() 267 : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize, 268 Format::FORMAT_4) { 269 } 270 271 IndexSubTableFormat4::Builder::Builder(WritableFontData* data, 272 int32_t first_glyph_index, 273 int32_t last_glyph_index) 274 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { 275 } 276 277 IndexSubTableFormat4::Builder::Builder(ReadableFontData* data, 278 int32_t first_glyph_index, 279 int32_t last_glyph_index) 280 : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { 281 } 282 283 std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>* 284 IndexSubTableFormat4::Builder::GetOffsetArray() { 285 if (offset_pair_array_.empty()) { 286 Initialize(InternalReadData()); 287 set_model_changed(); 288 } 289 return &offset_pair_array_; 290 } 291 292 void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) { 293 offset_pair_array_.clear(); 294 if (data) { 295 int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1; 296 int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray; 297 for (int32_t i = 0; i < num_pairs; ++i) { 298 int32_t glyph_code = data->ReadUShort(offset + 299 EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode); 300 int32_t glyph_offset = data->ReadUShort(offset + 301 EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset); 302 offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; 303 CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset); 304 offset_pair_array_.push_back(pair_builder); 305 } 306 } 307 } 308 309 int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) { 310 std::vector<CodeOffsetPairBuilder>* pair_list = GetOffsetArray(); 311 int32_t location = 0; 312 int32_t bottom = 0; 313 int32_t top = pair_list->size(); 314 while (top != bottom) { 315 location = (top + bottom) / 2; 316 CodeOffsetPairBuilder* pair = &(pair_list->at(location)); 317 if (glyph_id < pair->glyph_code()) { 318 // location is below current location 319 top = location; 320 } else if (glyph_id > pair->glyph_code()) { 321 // location is above current location 322 bottom = location + 1; 323 } else { 324 return location; 325 } 326 } 327 return -1; 328 } 329 330 // static 331 int32_t IndexSubTableFormat4::Builder::DataLength( 332 ReadableFontData* data, 333 int32_t index_sub_table_offset, 334 int32_t first_glyph_index, 335 int32_t last_glyph_index) { 336 int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data, 337 index_sub_table_offset); 338 UNREFERENCED_PARAMETER(first_glyph_index); 339 UNREFERENCED_PARAMETER(last_glyph_index); 340 return EblcTable::Offset::kIndexSubTable4_glyphArray + 341 num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset; 342 } 343 344 345 /****************************************************************************** 346 * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class 347 ******************************************************************************/ 348 IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( 349 IndexSubTableFormat4::Builder* container) 350 : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder, 351 IndexSubTable::Builder>(container), 352 code_offset_pair_index_(0) { 353 } 354 355 bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() { 356 if (code_offset_pair_index_ < 357 (int32_t)(container()->GetOffsetArray()->size() - 1)) { 358 return true; 359 } 360 return false; 361 } 362 363 CALLER_ATTACH BitmapGlyphInfo* 364 IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() { 365 BitmapGlyphInfoPtr output; 366 if (!HasNext()) { 367 // Note: In C++, we do not throw exception when there's no element. 368 return NULL; 369 } 370 std::vector<CodeOffsetPairBuilder>* offset_array = 371 container()->GetOffsetArray(); 372 int32_t offset = offset_array->at(code_offset_pair_index_).offset(); 373 int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset(); 374 int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code(); 375 output = new BitmapGlyphInfo(glyph_code, 376 container()->image_data_offset(), 377 offset, 378 next_offset - offset, 379 container()->image_format()); 380 code_offset_pair_index_++; 381 return output.Detach(); 382 } 383 384 } // namespace sfntly 385