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 20 namespace sfntly { 21 /****************************************************************************** 22 * LocaTable class 23 ******************************************************************************/ 24 LocaTable::~LocaTable() {} 25 26 int32_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 36 int32_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 46 int32_t LocaTable::NumLocas() { 47 return num_glyphs_ + 1; 48 } 49 50 int32_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 63 LocaTable::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 ******************************************************************************/ 75 LocaTable::LocaIterator::LocaIterator(LocaTable* table) 76 : PODIterator<int32_t, LocaTable>(table), index_(-1) { 77 } 78 79 bool LocaTable::LocaIterator::HasNext() { 80 return index_ <= container()->num_glyphs_; 81 } 82 83 int32_t LocaTable::LocaIterator::Next() { 84 return container()->Loca(index_++); 85 } 86 87 /****************************************************************************** 88 * LocaTable::Builder class 89 ******************************************************************************/ 90 LocaTable::Builder::Builder(Header* header, WritableFontData* data) 91 : Table::Builder(header, data), 92 format_version_(IndexToLocFormat::kLongOffset), 93 num_glyphs_(-1) { 94 } 95 96 LocaTable::Builder::Builder(Header* header, ReadableFontData* data) 97 : Table::Builder(header, data), 98 format_version_(IndexToLocFormat::kLongOffset), 99 num_glyphs_(-1) { 100 } 101 102 LocaTable::Builder::~Builder() {} 103 104 CALLER_ATTACH 105 LocaTable::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 112 IntegerList* LocaTable::Builder::LocaList() { 113 return GetLocaList(); 114 } 115 116 void LocaTable::Builder::SetLocaList(IntegerList* list) { 117 loca_.clear(); 118 if (list) { 119 loca_ = *list; 120 set_model_changed(); 121 } 122 } 123 124 int32_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 131 int32_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 138 void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) { 139 num_glyphs_ = num_glyphs; 140 } 141 142 int32_t LocaTable::Builder::NumGlyphs() { 143 return LastGlyphIndex() - 1; 144 } 145 146 void LocaTable::Builder::Revert() { 147 loca_.clear(); 148 set_model_changed(false); 149 } 150 151 int32_t LocaTable::Builder::NumLocas() { 152 return GetLocaList()->size(); 153 } 154 155 int32_t LocaTable::Builder::Loca(int32_t index) { 156 return GetLocaList()->at(index); 157 } 158 159 CALLER_ATTACH 160 FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) { 161 FontDataTablePtr table = 162 new LocaTable(header(), data, format_version_, num_glyphs_); 163 return table.Detach(); 164 } 165 166 void LocaTable::Builder::SubDataSet() { 167 Initialize(InternalReadData()); 168 } 169 170 int32_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 180 bool LocaTable::Builder::SubReadyToSerialize() { 181 return !loca_.empty(); 182 } 183 184 int32_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 198 void 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 217 int32_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 227 int32_t LocaTable::Builder::LastGlyphIndex() { 228 return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1; 229 } 230 231 IntegerList* LocaTable::Builder::GetLocaList() { 232 if (loca_.empty()) { 233 Initialize(InternalReadData()); 234 set_model_changed(); 235 } 236 return &loca_; 237 } 238 239 void 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