| /* |
| * Copyright 2011 Google Inc. All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "sfntly/table/bitmap/index_sub_table_format4.h" |
| |
| #include "sfntly/table/bitmap/eblc_table.h" |
| |
| namespace sfntly { |
| /****************************************************************************** |
| * IndexSubTableFormat4 class |
| ******************************************************************************/ |
| IndexSubTableFormat4::~IndexSubTableFormat4() { |
| } |
| |
| int32_t IndexSubTableFormat4::NumGlyphs() { |
| return IndexSubTableFormat4::NumGlyphs(data_, 0); |
| } |
| |
| int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) { |
| int32_t loca = CheckGlyphRange(glyph_id); |
| if (loca == -1) { |
| return -1; |
| } |
| int32_t pair_index = FindCodeOffsetPair(glyph_id); |
| if (pair_index < 0) { |
| return -1; |
| } |
| return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray + |
| pair_index * |
| EblcTable::Offset::kCodeOffsetPairLength + |
| EblcTable::Offset::kCodeOffsetPair_offset); |
| } |
| |
| int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) { |
| int32_t loca = CheckGlyphRange(glyph_id); |
| if (loca == -1) { |
| return -1; |
| } |
| |
| int32_t pair_index = FindCodeOffsetPair(glyph_id); |
| if (pair_index < 0) { |
| return -1; |
| } |
| return data_->ReadUShort( |
| EblcTable::Offset::kIndexSubTable4_glyphArray + |
| (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength + |
| EblcTable::Offset::kCodeOffsetPair_offset) - |
| data_->ReadUShort( |
| EblcTable::Offset::kIndexSubTable4_glyphArray + |
| (pair_index) * EblcTable::Offset::kCodeOffsetPairLength + |
| EblcTable::Offset::kCodeOffsetPair_offset); |
| } |
| |
| IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data, |
| int32_t first, |
| int32_t last) |
| : IndexSubTable(data, first, last) { |
| } |
| |
| int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) { |
| return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray, |
| EblcTable::Offset::kCodeOffsetPairLength, |
| NumGlyphs(), |
| glyph_id); |
| } |
| |
| int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data, |
| int32_t table_offset) { |
| int32_t num_glyphs = data->ReadULongAsInt(table_offset + |
| EblcTable::Offset::kIndexSubTable4_numGlyphs); |
| return num_glyphs; |
| } |
| |
| /****************************************************************************** |
| * IndexSubTableFormat4::CodeOffsetPair related class |
| ******************************************************************************/ |
| IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code, |
| int32_t offset) |
| : glyph_code_(glyph_code), offset_(offset) { |
| } |
| |
| IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder() |
| : CodeOffsetPair(0, 0) { |
| } |
| |
| IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder( |
| int32_t glyph_code, int32_t offset) |
| : CodeOffsetPair(glyph_code, offset) { |
| } |
| |
| bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()( |
| const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) { |
| return lhs.glyph_code() < rhs.glyph_code(); |
| } |
| |
| /****************************************************************************** |
| * IndexSubTableFormat4::Builder class |
| ******************************************************************************/ |
| IndexSubTableFormat4::Builder::~Builder() { |
| } |
| |
| int32_t IndexSubTableFormat4::Builder::NumGlyphs() { |
| return GetOffsetArray()->size() - 1; |
| } |
| |
| int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) { |
| int32_t loca = CheckGlyphRange(glyph_id); |
| if (loca == -1) { |
| return 0; |
| } |
| int32_t pair_index = FindCodeOffsetPair(glyph_id); |
| if (pair_index == -1) { |
| return 0; |
| } |
| return GetOffsetArray()->at(pair_index + 1).offset() - |
| GetOffsetArray()->at(pair_index).offset(); |
| } |
| |
| int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) { |
| int32_t loca = CheckGlyphRange(glyph_id); |
| if (loca == -1) { |
| return -1; |
| } |
| int32_t pair_index = FindCodeOffsetPair(glyph_id); |
| if (pair_index == -1) { |
| return -1; |
| } |
| return GetOffsetArray()->at(pair_index).offset(); |
| } |
| |
| CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* |
| IndexSubTableFormat4::Builder::GetIterator() { |
| Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it = |
| new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this); |
| return it.Detach(); |
| } |
| |
| // static |
| CALLER_ATTACH IndexSubTableFormat4::Builder* |
| IndexSubTableFormat4::Builder::CreateBuilder() { |
| IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder(); |
| return output.Detach(); |
| } |
| |
| // static |
| CALLER_ATTACH IndexSubTableFormat4::Builder* |
| IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data, |
| int32_t index_sub_table_offset, |
| int32_t first_glyph_index, |
| int32_t last_glyph_index) { |
| int32_t length = Builder::DataLength(data, |
| index_sub_table_offset, |
| first_glyph_index, |
| last_glyph_index); |
| ReadableFontDataPtr new_data; |
| new_data.Attach(down_cast<ReadableFontData*>( |
| data->Slice(index_sub_table_offset, length))); |
| if (new_data == NULL) { |
| return NULL; |
| } |
| IndexSubTableFormat4BuilderPtr output = |
| new IndexSubTableFormat4::Builder(new_data, |
| first_glyph_index, |
| last_glyph_index); |
| return output.Detach(); |
| } |
| |
| // static |
| CALLER_ATTACH IndexSubTableFormat4::Builder* |
| IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data, |
| int32_t index_sub_table_offset, |
| int32_t first_glyph_index, |
| int32_t last_glyph_index) { |
| int32_t length = Builder::DataLength(data, |
| index_sub_table_offset, |
| first_glyph_index, |
| last_glyph_index); |
| WritableFontDataPtr new_data; |
| new_data.Attach(down_cast<WritableFontData*>( |
| data->Slice(index_sub_table_offset, length))); |
| IndexSubTableFormat4BuilderPtr output = |
| new IndexSubTableFormat4::Builder(new_data, |
| first_glyph_index, |
| last_glyph_index); |
| return output.Detach(); |
| } |
| |
| CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable( |
| ReadableFontData* data) { |
| IndexSubTableFormat4Ptr output = new IndexSubTableFormat4( |
| data, first_glyph_index(), last_glyph_index()); |
| return output.Detach(); |
| } |
| |
| void IndexSubTableFormat4::Builder::SubDataSet() { |
| Revert(); |
| } |
| |
| int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() { |
| if (offset_pair_array_.empty()) { |
| return InternalReadData()->Length(); |
| } |
| return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG + |
| GetOffsetArray()->size() * |
| EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; |
| } |
| |
| bool IndexSubTableFormat4::Builder::SubReadyToSerialize() { |
| if (!offset_pair_array_.empty()) { |
| return true; |
| } |
| return false; |
| } |
| |
| int32_t IndexSubTableFormat4::Builder::SubSerialize( |
| WritableFontData* new_data) { |
| int32_t size = SerializeIndexSubHeader(new_data); |
| if (!model_changed()) { |
| if (InternalReadData() == NULL) { |
| return size; |
| } |
| ReadableFontDataPtr source; |
| WritableFontDataPtr target; |
| source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice( |
| EblcTable::Offset::kIndexSubTable4_glyphArray))); |
| target.Attach(down_cast<WritableFontData*>(new_data->Slice( |
| EblcTable::Offset::kIndexSubTable4_glyphArray))); |
| size += source->CopyTo(target); |
| } else { |
| size += new_data->WriteLong(size, offset_pair_array_.size() - 1); |
| for (std::vector<CodeOffsetPairBuilder>::iterator |
| b = GetOffsetArray()->begin(), e = GetOffsetArray()->end(); |
| b != e; b++) { |
| size += new_data->WriteUShort(size, b->glyph_code()); |
| size += new_data->WriteUShort(size, b->offset()); |
| } |
| } |
| return size; |
| } |
| |
| void IndexSubTableFormat4::Builder::Revert() { |
| offset_pair_array_.clear(); |
| IndexSubTable::Builder::Revert(); |
| } |
| |
| void IndexSubTableFormat4::Builder::SetOffsetArray( |
| const std::vector<CodeOffsetPairBuilder>& pair_array) { |
| offset_pair_array_.clear(); |
| offset_pair_array_ = pair_array; |
| set_model_changed(); |
| } |
| |
| IndexSubTableFormat4::Builder::Builder() |
| : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize, |
| Format::FORMAT_4) { |
| } |
| |
| IndexSubTableFormat4::Builder::Builder(WritableFontData* data, |
| int32_t first_glyph_index, |
| int32_t last_glyph_index) |
| : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { |
| } |
| |
| IndexSubTableFormat4::Builder::Builder(ReadableFontData* data, |
| int32_t first_glyph_index, |
| int32_t last_glyph_index) |
| : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) { |
| } |
| |
| std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>* |
| IndexSubTableFormat4::Builder::GetOffsetArray() { |
| if (offset_pair_array_.empty()) { |
| Initialize(InternalReadData()); |
| set_model_changed(); |
| } |
| return &offset_pair_array_; |
| } |
| |
| void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) { |
| offset_pair_array_.clear(); |
| if (data) { |
| int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1; |
| int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray; |
| for (int32_t i = 0; i < num_pairs; ++i) { |
| int32_t glyph_code = data->ReadUShort(offset + |
| EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode); |
| int32_t glyph_offset = data->ReadUShort(offset + |
| EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset); |
| offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength; |
| CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset); |
| offset_pair_array_.push_back(pair_builder); |
| } |
| } |
| } |
| |
| int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) { |
| std::vector<CodeOffsetPairBuilder>* pair_list = GetOffsetArray(); |
| int32_t location = 0; |
| int32_t bottom = 0; |
| int32_t top = pair_list->size(); |
| while (top != bottom) { |
| location = (top + bottom) / 2; |
| CodeOffsetPairBuilder* pair = &(pair_list->at(location)); |
| if (glyph_id < pair->glyph_code()) { |
| // location is below current location |
| top = location; |
| } else if (glyph_id > pair->glyph_code()) { |
| // location is above current location |
| bottom = location + 1; |
| } else { |
| return location; |
| } |
| } |
| return -1; |
| } |
| |
| // static |
| int32_t IndexSubTableFormat4::Builder::DataLength( |
| ReadableFontData* data, |
| int32_t index_sub_table_offset, |
| int32_t first_glyph_index, |
| int32_t last_glyph_index) { |
| int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data, |
| index_sub_table_offset); |
| UNREFERENCED_PARAMETER(first_glyph_index); |
| UNREFERENCED_PARAMETER(last_glyph_index); |
| return EblcTable::Offset::kIndexSubTable4_glyphArray + |
| num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset; |
| } |
| |
| |
| /****************************************************************************** |
| * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class |
| ******************************************************************************/ |
| IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator( |
| IndexSubTableFormat4::Builder* container) |
| : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder, |
| IndexSubTable::Builder>(container), |
| code_offset_pair_index_(0) { |
| } |
| |
| bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() { |
| if (code_offset_pair_index_ < |
| (int32_t)(container()->GetOffsetArray()->size() - 1)) { |
| return true; |
| } |
| return false; |
| } |
| |
| CALLER_ATTACH BitmapGlyphInfo* |
| IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() { |
| BitmapGlyphInfoPtr output; |
| if (!HasNext()) { |
| // Note: In C++, we do not throw exception when there's no element. |
| return NULL; |
| } |
| std::vector<CodeOffsetPairBuilder>* offset_array = |
| container()->GetOffsetArray(); |
| int32_t offset = offset_array->at(code_offset_pair_index_).offset(); |
| int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset(); |
| int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code(); |
| output = new BitmapGlyphInfo(glyph_code, |
| container()->image_data_offset(), |
| offset, |
| next_offset - offset, |
| container()->image_format()); |
| code_offset_pair_index_++; |
| return output.Detach(); |
| } |
| |
| } // namespace sfntly |