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 "subtly/font_info.h" 18 19#include <stdio.h> 20 21#include <set> 22#include <map> 23 24#include "subtly/character_predicate.h" 25 26#include "sfntly/tag.h" 27#include "sfntly/font.h" 28#include "sfntly/font_factory.h" 29#include "sfntly/table/core/cmap_table.h" 30#include "sfntly/table/truetype/loca_table.h" 31#include "sfntly/table/truetype/glyph_table.h" 32#include "sfntly/table/core/maximum_profile_table.h" 33#include "sfntly/port/type.h" 34#include "sfntly/port/refcount.h" 35 36namespace subtly { 37using namespace sfntly; 38/****************************************************************************** 39 * GlyphId class 40 ******************************************************************************/ 41GlyphId::GlyphId(int32_t glyph_id, FontId font_id) 42 : glyph_id_(glyph_id), 43 font_id_(font_id) { 44} 45 46bool GlyphId::operator==(const GlyphId& other) const { 47 return glyph_id_ == other.glyph_id(); 48} 49 50bool GlyphId::operator<(const GlyphId& other) const { 51 return glyph_id_ < other.glyph_id(); 52} 53 54/****************************************************************************** 55 * FontInfo class 56 ******************************************************************************/ 57FontInfo::FontInfo() 58 : chars_to_glyph_ids_(new CharacterMap), 59 resolved_glyph_ids_(new GlyphIdSet), 60 fonts_(new FontIdMap) { 61} 62 63FontInfo::FontInfo(CharacterMap* chars_to_glyph_ids, 64 GlyphIdSet* resolved_glyph_ids, 65 FontIdMap* fonts) { 66 chars_to_glyph_ids_ = new CharacterMap(chars_to_glyph_ids->begin(), 67 chars_to_glyph_ids->end()); 68 resolved_glyph_ids_ = new GlyphIdSet(resolved_glyph_ids->begin(), 69 resolved_glyph_ids->end()); 70 fonts_ = new FontIdMap(fonts->begin(), fonts->end()); 71} 72 73FontInfo::~FontInfo() { 74 delete chars_to_glyph_ids_; 75 delete resolved_glyph_ids_; 76 delete fonts_; 77} 78 79FontDataTable* FontInfo::GetTable(FontId font_id, int32_t tag) { 80 if (!fonts_) 81 return NULL; 82 FontIdMap::iterator it = fonts_->find(font_id); 83 if (it == fonts_->end()) 84 return NULL; 85 return it->second->GetTable(tag); 86} 87 88const TableMap* FontInfo::GetTableMap(FontId font_id) { 89 if (!fonts_) 90 return NULL; 91 FontIdMap::iterator it = fonts_->find(font_id); 92 if (it == fonts_->end()) 93 return NULL; 94 return it->second->GetTableMap(); 95} 96 97void FontInfo::set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids) { 98 *chars_to_glyph_ids_ = *chars_to_glyph_ids; 99} 100 101void FontInfo::set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids) { 102 *resolved_glyph_ids_ = *resolved_glyph_ids; 103} 104 105void FontInfo::set_fonts(FontIdMap* fonts) { 106 *fonts_ = *fonts; 107} 108 109/****************************************************************************** 110 * FontSourcedInfoBuilder class 111 ******************************************************************************/ 112FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontId font_id) 113 : font_(font), 114 font_id_(font_id), 115 predicate_(NULL) { 116 Initialize(); 117} 118 119FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, 120 FontId font_id, 121 CharacterPredicate* predicate) 122 : font_(font), 123 font_id_(font_id), 124 predicate_(predicate) { 125 Initialize(); 126} 127 128void FontSourcedInfoBuilder::Initialize() { 129 Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font_->GetTable(Tag::cmap)); 130 // We prefer Windows BMP format 4 cmaps. 131 cmap_.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP)); 132 // But if none is found, 133 if (!cmap_) { 134 return; 135 } 136 loca_table_ = down_cast<LocaTable*>(font_->GetTable(Tag::loca)); 137 glyph_table_ = down_cast<GlyphTable*>(font_->GetTable(Tag::glyf)); 138} 139 140CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() { 141 CharacterMap* chars_to_glyph_ids = new CharacterMap; 142 bool success = GetCharacterMap(chars_to_glyph_ids); 143 if (!success) { 144 delete chars_to_glyph_ids; 145#if defined (SUBTLY_DEBUG) 146 fprintf(stderr, "Error creating character map.\n"); 147#endif 148 return NULL; 149 } 150 GlyphIdSet* resolved_glyph_ids = new GlyphIdSet; 151 success = ResolveCompositeGlyphs(chars_to_glyph_ids, resolved_glyph_ids); 152 if (!success) { 153 delete chars_to_glyph_ids; 154 delete resolved_glyph_ids; 155#if defined (SUBTLY_DEBUG) 156 fprintf(stderr, "Error resolving composite glyphs.\n"); 157#endif 158 return NULL; 159 } 160 Ptr<FontInfo> font_info = new FontInfo; 161 font_info->set_chars_to_glyph_ids(chars_to_glyph_ids); 162 font_info->set_resolved_glyph_ids(resolved_glyph_ids); 163 FontIdMap* font_id_map = new FontIdMap; 164 font_id_map->insert(std::make_pair(font_id_, font_)); 165 font_info->set_fonts(font_id_map); 166 delete chars_to_glyph_ids; 167 delete resolved_glyph_ids; 168 delete font_id_map; 169 return font_info.Detach(); 170} 171 172bool FontSourcedInfoBuilder::GetCharacterMap(CharacterMap* chars_to_glyph_ids) { 173 if (!cmap_ || !chars_to_glyph_ids) 174 return false; 175 chars_to_glyph_ids->clear(); 176 CMapTable::CMap::CharacterIterator* character_iterator = cmap_->Iterator(); 177 if (!character_iterator) 178 return false; 179 while (character_iterator->HasNext()) { 180 int32_t character = character_iterator->Next(); 181 if (!predicate_ || (*predicate_)(character)) { 182 chars_to_glyph_ids->insert 183 (std::make_pair(character, 184 GlyphId(cmap_->GlyphId(character), font_id_))); 185 } 186 } 187 delete character_iterator; 188 return true; 189} 190 191bool 192FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids, 193 GlyphIdSet* resolved_glyph_ids) { 194 if (!chars_to_glyph_ids || !resolved_glyph_ids) 195 return false; 196 resolved_glyph_ids->clear(); 197 resolved_glyph_ids->insert(GlyphId(0, font_id_)); 198 IntegerSet* unresolved_glyph_ids = new IntegerSet; 199 // Since composite glyph elements might themselves be composite, we would need 200 // to recursively resolve the elements too. To avoid the recursion we 201 // create two sets, |unresolved_glyph_ids| for the unresolved glyphs, 202 // initially containing all the ids and |resolved_glyph_ids|, initially empty. 203 // We'll remove glyph ids from |unresolved_glyph_ids| until it is empty and, 204 // if the glyph is composite, add its elements to the unresolved set. 205 for (CharacterMap::iterator it = chars_to_glyph_ids->begin(), 206 e = chars_to_glyph_ids->end(); it != e; ++it) { 207 unresolved_glyph_ids->insert(it->second.glyph_id()); 208 } 209 // As long as there are unresolved glyph ids. 210 while (!unresolved_glyph_ids->empty()) { 211 // Get the corresponding glyph. 212 int32_t glyph_id = *(unresolved_glyph_ids->begin()); 213 unresolved_glyph_ids->erase(unresolved_glyph_ids->begin()); 214 if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) { 215#if defined (SUBTLY_DEBUG) 216 fprintf(stderr, "%d larger than %d or smaller than 0\n", glyph_id, 217 loca_table_->num_glyphs()); 218#endif 219 continue; 220 } 221 int32_t length = loca_table_->GlyphLength(glyph_id); 222 if (length == 0) { 223#if defined (SUBTLY_DEBUG) 224 fprintf(stderr, "Zero length glyph %d\n", glyph_id); 225#endif 226 continue; 227 } 228 int32_t offset = loca_table_->GlyphOffset(glyph_id); 229 GlyphPtr glyph; 230 glyph.Attach(glyph_table_->GetGlyph(offset, length)); 231 if (glyph == NULL) { 232#if defined (SUBTLY_DEBUG) 233 fprintf(stderr, "GetGlyph returned NULL for %d\n", glyph_id); 234#endif 235 continue; 236 } 237 // Mark the glyph as resolved. 238 resolved_glyph_ids->insert(GlyphId(glyph_id, font_id_)); 239 // If it is composite, add all its components to the unresolved glyph set. 240 if (glyph->GlyphType() == GlyphType::kComposite) { 241 Ptr<GlyphTable::CompositeGlyph> composite_glyph = 242 down_cast<GlyphTable::CompositeGlyph*>(glyph.p_); 243 int32_t num_glyphs = composite_glyph->NumGlyphs(); 244 for (int32_t i = 0; i < num_glyphs; ++i) { 245 int32_t glyph_id = composite_glyph->GlyphIndex(i); 246 if (resolved_glyph_ids->find(GlyphId(glyph_id, -1)) 247 == resolved_glyph_ids->end()) { 248 unresolved_glyph_ids->insert(glyph_id); 249 } 250 } 251 } 252 } 253 delete unresolved_glyph_ids; 254 return true; 255} 256} 257