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 21namespace sfntly { 22/****************************************************************************** 23 * IndexSubTableFormat4 class 24 ******************************************************************************/ 25IndexSubTableFormat4::~IndexSubTableFormat4() { 26} 27 28int32_t IndexSubTableFormat4::NumGlyphs() { 29 return IndexSubTableFormat4::NumGlyphs(data_, 0); 30} 31 32int32_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 47int32_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 67IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data, 68 int32_t first, 69 int32_t last) 70 : IndexSubTable(data, first, last) { 71} 72 73int32_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 80int32_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 ******************************************************************************/ 90IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code, 91 int32_t offset) 92 : glyph_code_(glyph_code), offset_(offset) { 93} 94 95IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder() 96 : CodeOffsetPair(0, 0) { 97} 98 99IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder( 100 int32_t glyph_code, int32_t offset) 101 : CodeOffsetPair(glyph_code, offset) { 102} 103 104bool 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 ******************************************************************************/ 112IndexSubTableFormat4::Builder::~Builder() { 113} 114 115int32_t IndexSubTableFormat4::Builder::NumGlyphs() { 116 return GetOffsetArray()->size() - 1; 117} 118 119int32_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 132int32_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 144CALLER_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 152CALLER_ATTACH IndexSubTableFormat4::Builder* 153IndexSubTableFormat4::Builder::CreateBuilder() { 154 IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder(); 155 return output.Detach(); 156} 157 158// static 159CALLER_ATTACH IndexSubTableFormat4::Builder* 160IndexSubTableFormat4::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 182CALLER_ATTACH IndexSubTableFormat4::Builder* 183IndexSubTableFormat4::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 201CALLER_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 208void IndexSubTableFormat4::Builder::SubDataSet() { 209 Revert(); 210} 211 212int32_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 221bool IndexSubTableFormat4::Builder::SubReadyToSerialize() { 222 if (!offset_pair_array_.empty()) { 223 return true; 224 } 225 return false; 226} 227 228int32_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 254void IndexSubTableFormat4::Builder::Revert() { 255 offset_pair_array_.clear(); 256 IndexSubTable::Builder::Revert(); 257} 258 259void 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 266IndexSubTableFormat4::Builder::Builder() 267 : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize, 268 Format::FORMAT_4) { 269} 270 271IndexSubTableFormat4::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 277IndexSubTableFormat4::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 283std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>* 284IndexSubTableFormat4::Builder::GetOffsetArray() { 285 if (offset_pair_array_.empty()) { 286 Initialize(InternalReadData()); 287 set_model_changed(); 288 } 289 return &offset_pair_array_; 290} 291 292void 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 309int32_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 331int32_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 ******************************************************************************/ 348IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( 349 IndexSubTableFormat4::Builder* container) 350 : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder, 351 IndexSubTable::Builder>(container), 352 code_offset_pair_index_(0) { 353} 354 355bool 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 363CALLER_ATTACH BitmapGlyphInfo* 364IndexSubTableFormat4::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