| /* |
| * 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/truetype/loca_table.h" |
| #include "sfntly/port/exception_type.h" |
| |
| namespace sfntly { |
| /****************************************************************************** |
| * LocaTable class |
| ******************************************************************************/ |
| LocaTable::~LocaTable() {} |
| |
| int32_t LocaTable::GlyphOffset(int32_t glyph_id) { |
| if (glyph_id < 0 || glyph_id >= num_glyphs_) { |
| #if !defined (SFNTLY_NO_EXCEPTION) |
| throw IndexOutOfBoundException("Glyph ID is out of bounds."); |
| #endif |
| return 0; |
| } |
| return Loca(glyph_id); |
| } |
| |
| int32_t LocaTable::GlyphLength(int32_t glyph_id) { |
| if (glyph_id < 0 || glyph_id >= num_glyphs_) { |
| #if !defined (SFNTLY_NO_EXCEPTION) |
| throw IndexOutOfBoundException("Glyph ID is out of bounds."); |
| #endif |
| return 0; |
| } |
| return Loca(glyph_id + 1) - Loca(glyph_id); |
| } |
| |
| int32_t LocaTable::NumLocas() { |
| return num_glyphs_ + 1; |
| } |
| |
| int32_t LocaTable::Loca(int32_t index) { |
| if (index > num_glyphs_) { |
| #if !defined (SFNTLY_NO_EXCEPTION) |
| throw IndexOutOfBoundException(); |
| #endif |
| return 0; |
| } |
| if (format_version_ == IndexToLocFormat::kShortOffset) { |
| return 2 * data_->ReadUShort(index * DataSize::kUSHORT); |
| } |
| return data_->ReadULongAsInt(index * DataSize::kULONG); |
| } |
| |
| LocaTable::LocaTable(Header* header, |
| ReadableFontData* data, |
| int32_t format_version, |
| int32_t num_glyphs) |
| : Table(header, data), |
| format_version_(format_version), |
| num_glyphs_(num_glyphs) { |
| } |
| |
| /****************************************************************************** |
| * LocaTable::Iterator class |
| ******************************************************************************/ |
| LocaTable::LocaIterator::LocaIterator(LocaTable* table) |
| : PODIterator<int32_t, LocaTable>(table), index_(-1) { |
| } |
| |
| bool LocaTable::LocaIterator::HasNext() { |
| return index_ <= container()->num_glyphs_; |
| } |
| |
| int32_t LocaTable::LocaIterator::Next() { |
| return container()->Loca(index_++); |
| } |
| |
| /****************************************************************************** |
| * LocaTable::Builder class |
| ******************************************************************************/ |
| LocaTable::Builder::Builder(Header* header, WritableFontData* data) |
| : Table::Builder(header, data), |
| format_version_(IndexToLocFormat::kLongOffset), |
| num_glyphs_(-1) { |
| } |
| |
| LocaTable::Builder::Builder(Header* header, ReadableFontData* data) |
| : Table::Builder(header, data), |
| format_version_(IndexToLocFormat::kLongOffset), |
| num_glyphs_(-1) { |
| } |
| |
| LocaTable::Builder::~Builder() {} |
| |
| CALLER_ATTACH |
| LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header, |
| WritableFontData* data) { |
| Ptr<LocaTable::Builder> builder; |
| builder = new LocaTable::Builder(header, data); |
| return builder.Detach(); |
| } |
| |
| IntegerList* LocaTable::Builder::LocaList() { |
| return GetLocaList(); |
| } |
| |
| void LocaTable::Builder::SetLocaList(IntegerList* list) { |
| loca_.clear(); |
| if (list) { |
| loca_ = *list; |
| set_model_changed(); |
| } |
| } |
| |
| int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) { |
| if (CheckGlyphRange(glyph_id) == -1) { |
| return 0; |
| } |
| return GetLocaList()->at(glyph_id); |
| } |
| |
| int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) { |
| if (CheckGlyphRange(glyph_id) == -1) { |
| return 0; |
| } |
| return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id); |
| } |
| |
| void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) { |
| num_glyphs_ = num_glyphs; |
| } |
| |
| int32_t LocaTable::Builder::NumGlyphs() { |
| return LastGlyphIndex() - 1; |
| } |
| |
| void LocaTable::Builder::Revert() { |
| loca_.clear(); |
| set_model_changed(false); |
| } |
| |
| int32_t LocaTable::Builder::NumLocas() { |
| return GetLocaList()->size(); |
| } |
| |
| int32_t LocaTable::Builder::Loca(int32_t index) { |
| return GetLocaList()->at(index); |
| } |
| |
| CALLER_ATTACH |
| FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) { |
| FontDataTablePtr table = |
| new LocaTable(header(), data, format_version_, num_glyphs_); |
| return table.Detach(); |
| } |
| |
| void LocaTable::Builder::SubDataSet() { |
| Initialize(InternalReadData()); |
| } |
| |
| int32_t LocaTable::Builder::SubDataSizeToSerialize() { |
| if (loca_.empty()) { |
| return 0; |
| } |
| if (format_version_ == IndexToLocFormat::kLongOffset) { |
| return loca_.size() * DataSize::kULONG; |
| } |
| return loca_.size() * DataSize::kUSHORT; |
| } |
| |
| bool LocaTable::Builder::SubReadyToSerialize() { |
| return !loca_.empty(); |
| } |
| |
| int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) { |
| int32_t size = 0; |
| for (IntegerList::iterator l = loca_.begin(), end = loca_.end(); |
| l != end; ++l) { |
| if (format_version_ == IndexToLocFormat::kLongOffset) { |
| size += new_data->WriteULong(size, *l); |
| } else { |
| size += new_data->WriteUShort(size, *l / 2); |
| } |
| } |
| num_glyphs_ = loca_.size() - 1; |
| return size; |
| } |
| |
| void LocaTable::Builder::Initialize(ReadableFontData* data) { |
| ClearLoca(false); |
| if (data) { |
| if (NumGlyphs() < 0) { |
| #if !defined (SFNTLY_NO_EXCEPTION) |
| throw IllegalStateException("numglyphs not set on LocaTable Builder."); |
| #endif |
| return; |
| } |
| LocaTablePtr table = |
| new LocaTable(header(), data, format_version_, num_glyphs_); |
| Ptr<LocaTable::LocaIterator> loca_iter = |
| new LocaTable::LocaIterator(table); |
| while (loca_iter->HasNext()) { |
| loca_.push_back(loca_iter->Next()); |
| } |
| } |
| } |
| |
| int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) { |
| if (glyph_id < 0 || glyph_id > LastGlyphIndex()) { |
| #if !defined (SFNTLY_NO_EXCEPTION) |
| throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range"); |
| #endif |
| return -1; |
| } |
| return glyph_id; |
| } |
| |
| int32_t LocaTable::Builder::LastGlyphIndex() { |
| return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1; |
| } |
| |
| IntegerList* LocaTable::Builder::GetLocaList() { |
| if (loca_.empty()) { |
| Initialize(InternalReadData()); |
| set_model_changed(); |
| } |
| return &loca_; |
| } |
| |
| void LocaTable::Builder::ClearLoca(bool nullify) { |
| // Note: in C++ port, nullify is not used at all. |
| UNREFERENCED_PARAMETER(nullify); |
| loca_.clear(); |
| set_model_changed(false); |
| } |
| |
| } // namespace sfntly |