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/truetype/loca_table.h" 18#include "sfntly/port/exception_type.h" 19 20namespace sfntly { 21/****************************************************************************** 22 * LocaTable class 23 ******************************************************************************/ 24LocaTable::~LocaTable() {} 25 26int32_t LocaTable::GlyphOffset(int32_t glyph_id) { 27 if (glyph_id < 0 || glyph_id >= num_glyphs_) { 28#if !defined (SFNTLY_NO_EXCEPTION) 29 throw IndexOutOfBoundException("Glyph ID is out of bounds."); 30#endif 31 return 0; 32 } 33 return Loca(glyph_id); 34} 35 36int32_t LocaTable::GlyphLength(int32_t glyph_id) { 37 if (glyph_id < 0 || glyph_id >= num_glyphs_) { 38#if !defined (SFNTLY_NO_EXCEPTION) 39 throw IndexOutOfBoundException("Glyph ID is out of bounds."); 40#endif 41 return 0; 42 } 43 return Loca(glyph_id + 1) - Loca(glyph_id); 44} 45 46int32_t LocaTable::NumLocas() { 47 return num_glyphs_ + 1; 48} 49 50int32_t LocaTable::Loca(int32_t index) { 51 if (index > num_glyphs_) { 52#if !defined (SFNTLY_NO_EXCEPTION) 53 throw IndexOutOfBoundException(); 54#endif 55 return 0; 56 } 57 if (format_version_ == IndexToLocFormat::kShortOffset) { 58 return 2 * data_->ReadUShort(index * DataSize::kUSHORT); 59 } 60 return data_->ReadULongAsInt(index * DataSize::kULONG); 61} 62 63LocaTable::LocaTable(Header* header, 64 ReadableFontData* data, 65 int32_t format_version, 66 int32_t num_glyphs) 67 : Table(header, data), 68 format_version_(format_version), 69 num_glyphs_(num_glyphs) { 70} 71 72/****************************************************************************** 73 * LocaTable::Iterator class 74 ******************************************************************************/ 75LocaTable::LocaIterator::LocaIterator(LocaTable* table) 76 : PODIterator<int32_t, LocaTable>(table), index_(-1) { 77} 78 79bool LocaTable::LocaIterator::HasNext() { 80 return index_ <= container()->num_glyphs_; 81} 82 83int32_t LocaTable::LocaIterator::Next() { 84 return container()->Loca(index_++); 85} 86 87/****************************************************************************** 88 * LocaTable::Builder class 89 ******************************************************************************/ 90LocaTable::Builder::Builder(Header* header, WritableFontData* data) 91 : Table::Builder(header, data), 92 format_version_(IndexToLocFormat::kLongOffset), 93 num_glyphs_(-1) { 94} 95 96LocaTable::Builder::Builder(Header* header, ReadableFontData* data) 97 : Table::Builder(header, data), 98 format_version_(IndexToLocFormat::kLongOffset), 99 num_glyphs_(-1) { 100} 101 102LocaTable::Builder::~Builder() {} 103 104CALLER_ATTACH 105LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header, 106 WritableFontData* data) { 107 Ptr<LocaTable::Builder> builder; 108 builder = new LocaTable::Builder(header, data); 109 return builder.Detach(); 110} 111 112IntegerList* LocaTable::Builder::LocaList() { 113 return GetLocaList(); 114} 115 116void LocaTable::Builder::SetLocaList(IntegerList* list) { 117 loca_.clear(); 118 if (list) { 119 loca_ = *list; 120 set_model_changed(); 121 } 122} 123 124int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) { 125 if (CheckGlyphRange(glyph_id) == -1) { 126 return 0; 127 } 128 return GetLocaList()->at(glyph_id); 129} 130 131int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) { 132 if (CheckGlyphRange(glyph_id) == -1) { 133 return 0; 134 } 135 return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id); 136} 137 138void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) { 139 num_glyphs_ = num_glyphs; 140} 141 142int32_t LocaTable::Builder::NumGlyphs() { 143 return LastGlyphIndex() - 1; 144} 145 146void LocaTable::Builder::Revert() { 147 loca_.clear(); 148 set_model_changed(false); 149} 150 151int32_t LocaTable::Builder::NumLocas() { 152 return GetLocaList()->size(); 153} 154 155int32_t LocaTable::Builder::Loca(int32_t index) { 156 return GetLocaList()->at(index); 157} 158 159CALLER_ATTACH 160FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) { 161 FontDataTablePtr table = 162 new LocaTable(header(), data, format_version_, num_glyphs_); 163 return table.Detach(); 164} 165 166void LocaTable::Builder::SubDataSet() { 167 Initialize(InternalReadData()); 168} 169 170int32_t LocaTable::Builder::SubDataSizeToSerialize() { 171 if (loca_.empty()) { 172 return 0; 173 } 174 if (format_version_ == IndexToLocFormat::kLongOffset) { 175 return loca_.size() * DataSize::kULONG; 176 } 177 return loca_.size() * DataSize::kUSHORT; 178} 179 180bool LocaTable::Builder::SubReadyToSerialize() { 181 return !loca_.empty(); 182} 183 184int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) { 185 int32_t size = 0; 186 for (IntegerList::iterator l = loca_.begin(), end = loca_.end(); 187 l != end; ++l) { 188 if (format_version_ == IndexToLocFormat::kLongOffset) { 189 size += new_data->WriteULong(size, *l); 190 } else { 191 size += new_data->WriteUShort(size, *l / 2); 192 } 193 } 194 num_glyphs_ = loca_.size() - 1; 195 return size; 196} 197 198void LocaTable::Builder::Initialize(ReadableFontData* data) { 199 ClearLoca(false); 200 if (data) { 201 if (NumGlyphs() < 0) { 202#if !defined (SFNTLY_NO_EXCEPTION) 203 throw IllegalStateException("numglyphs not set on LocaTable Builder."); 204#endif 205 return; 206 } 207 LocaTablePtr table = 208 new LocaTable(header(), data, format_version_, num_glyphs_); 209 Ptr<LocaTable::LocaIterator> loca_iter = 210 new LocaTable::LocaIterator(table); 211 while (loca_iter->HasNext()) { 212 loca_.push_back(loca_iter->Next()); 213 } 214 } 215} 216 217int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) { 218 if (glyph_id < 0 || glyph_id > LastGlyphIndex()) { 219#if !defined (SFNTLY_NO_EXCEPTION) 220 throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range"); 221#endif 222 return -1; 223 } 224 return glyph_id; 225} 226 227int32_t LocaTable::Builder::LastGlyphIndex() { 228 return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1; 229} 230 231IntegerList* LocaTable::Builder::GetLocaList() { 232 if (loca_.empty()) { 233 Initialize(InternalReadData()); 234 set_model_changed(); 235 } 236 return &loca_; 237} 238 239void LocaTable::Builder::ClearLoca(bool nullify) { 240 // Note: in C++ port, nullify is not used at all. 241 UNREFERENCED_PARAMETER(nullify); 242 loca_.clear(); 243 set_model_changed(false); 244} 245 246} // namespace sfntly 247