130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/*
230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Copyright 2011 Google Inc. All Rights Reserved.
330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *
430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Licensed under the Apache License, Version 2.0 (the "License");
530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * you may not use this file except in compliance with the License.
630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * You may obtain a copy of the License at
730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *
830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *      http://www.apache.org/licenses/LICENSE-2.0
930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun *
1030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Unless required by applicable law or agreed to in writing, software
1130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * distributed under the License is distributed on an "AS IS" BASIS,
1230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * See the License for the specific language governing permissions and
1430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * limitations under the License.
1530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun */
1630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
1730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "subtly/font_info.h"
1830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
1930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <stdio.h>
2030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
2130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <set>
2230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <map>
2330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
2430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "subtly/character_predicate.h"
2530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
2630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/tag.h"
2730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/font.h"
2830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/font_factory.h"
2930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/table/core/cmap_table.h"
3030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/table/truetype/loca_table.h"
3130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/table/truetype/glyph_table.h"
3230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/table/core/maximum_profile_table.h"
3330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/port/type.h"
3430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/port/refcount.h"
3530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
3630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunnamespace subtly {
3730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunusing namespace sfntly;
3830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/******************************************************************************
3930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * GlyphId class
4030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ******************************************************************************/
4130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunGlyphId::GlyphId(int32_t glyph_id, FontId font_id)
4230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    : glyph_id_(glyph_id),
4330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      font_id_(font_id) {
4430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
4530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
4630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunbool GlyphId::operator==(const GlyphId& other) const {
4730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return glyph_id_ == other.glyph_id();
4830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
4930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
5030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunbool GlyphId::operator<(const GlyphId& other) const {
5130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return glyph_id_ < other.glyph_id();
5230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
5330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
5430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/******************************************************************************
5530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * FontInfo class
5630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ******************************************************************************/
5730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontInfo::FontInfo()
5830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    : chars_to_glyph_ids_(new CharacterMap),
5930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      resolved_glyph_ids_(new GlyphIdSet),
6030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      fonts_(new FontIdMap) {
6130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
6230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
6330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontInfo::FontInfo(CharacterMap* chars_to_glyph_ids,
6430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                   GlyphIdSet* resolved_glyph_ids,
6530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                   FontIdMap* fonts) {
6630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  chars_to_glyph_ids_ = new CharacterMap(chars_to_glyph_ids->begin(),
6730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                         chars_to_glyph_ids->end());
6830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  resolved_glyph_ids_ = new GlyphIdSet(resolved_glyph_ids->begin(),
6930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                       resolved_glyph_ids->end());
7030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  fonts_ = new FontIdMap(fonts->begin(), fonts->end());
7130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
7230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
7330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontInfo::~FontInfo() {
7430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete chars_to_glyph_ids_;
7530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete resolved_glyph_ids_;
7630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete fonts_;
7730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
7830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
7930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontDataTable* FontInfo::GetTable(FontId font_id, int32_t tag) {
8030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!fonts_)
8130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return NULL;
8230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  FontIdMap::iterator it = fonts_->find(font_id);
8330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (it == fonts_->end())
8430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return NULL;
8530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return it->second->GetTable(tag);
8630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
8730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
8830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunconst TableMap* FontInfo::GetTableMap(FontId font_id) {
8930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!fonts_)
9030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return NULL;
9130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  FontIdMap::iterator it = fonts_->find(font_id);
9230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (it == fonts_->end())
9330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return NULL;
9430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return it->second->GetTableMap();
9530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
9630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
9730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunvoid FontInfo::set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids) {
9830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  *chars_to_glyph_ids_ = *chars_to_glyph_ids;
9930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
10030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
10130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunvoid FontInfo::set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids) {
10230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  *resolved_glyph_ids_ = *resolved_glyph_ids;
10330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
10430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
10530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunvoid FontInfo::set_fonts(FontIdMap* fonts) {
10630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  *fonts_ = *fonts;
10730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
10830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
10930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/******************************************************************************
11030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * FontSourcedInfoBuilder class
11130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ******************************************************************************/
11230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontId font_id)
11330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    : font_(font),
11430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      font_id_(font_id),
11530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      predicate_(NULL) {
11630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  Initialize();
11730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
11830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
11930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font,
12030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                               FontId font_id,
12130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                               CharacterPredicate* predicate)
12230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    : font_(font),
12330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      font_id_(font_id),
12430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      predicate_(predicate) {
12530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  Initialize();
12630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
12730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
12830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunvoid FontSourcedInfoBuilder::Initialize() {
12930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font_->GetTable(Tag::cmap));
13030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // We prefer Windows BMP format 4 cmaps.
13130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  cmap_.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP));
13230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // But if none is found,
13330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!cmap_) {
13430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return;
13530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
13630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  loca_table_ = down_cast<LocaTable*>(font_->GetTable(Tag::loca));
13730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  glyph_table_ = down_cast<GlyphTable*>(font_->GetTable(Tag::glyf));
13830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
13930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
14030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunCALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() {
14130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  CharacterMap* chars_to_glyph_ids = new CharacterMap;
14230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  bool success = GetCharacterMap(chars_to_glyph_ids);
14330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!success) {
14430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    delete chars_to_glyph_ids;
14530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (SUBTLY_DEBUG)
14630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    fprintf(stderr, "Error creating character map.\n");
14730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif
14830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return NULL;
14930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
15030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  GlyphIdSet* resolved_glyph_ids = new GlyphIdSet;
15130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  success = ResolveCompositeGlyphs(chars_to_glyph_ids, resolved_glyph_ids);
15230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!success) {
15330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    delete chars_to_glyph_ids;
15430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    delete resolved_glyph_ids;
15530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (SUBTLY_DEBUG)
15630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    fprintf(stderr, "Error resolving composite glyphs.\n");
15730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif
15830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return NULL;
15930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
16030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  Ptr<FontInfo> font_info = new FontInfo;
16130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  font_info->set_chars_to_glyph_ids(chars_to_glyph_ids);
16230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  font_info->set_resolved_glyph_ids(resolved_glyph_ids);
16330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  FontIdMap* font_id_map = new FontIdMap;
16430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  font_id_map->insert(std::make_pair(font_id_, font_));
16530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  font_info->set_fonts(font_id_map);
16630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete chars_to_glyph_ids;
16730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete resolved_glyph_ids;
16830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete font_id_map;
16930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return font_info.Detach();
17030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
17130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
17230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunbool FontSourcedInfoBuilder::GetCharacterMap(CharacterMap* chars_to_glyph_ids) {
17330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!cmap_ || !chars_to_glyph_ids)
17430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return false;
17530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  chars_to_glyph_ids->clear();
17630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  CMapTable::CMap::CharacterIterator* character_iterator = cmap_->Iterator();
17730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!character_iterator)
17830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return false;
17930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  while (character_iterator->HasNext()) {
18030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    int32_t character = character_iterator->Next();
18130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    if (!predicate_ || (*predicate_)(character)) {
18230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      chars_to_glyph_ids->insert
18330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun          (std::make_pair(character,
18430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                          GlyphId(cmap_->GlyphId(character), font_id_)));
18530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    }
18630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
18730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete character_iterator;
18830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return true;
18930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
19030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
19130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunbool
19230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids,
19330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun                                               GlyphIdSet* resolved_glyph_ids) {
19430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  if (!chars_to_glyph_ids || !resolved_glyph_ids)
19530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    return false;
19630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  resolved_glyph_ids->clear();
19730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  resolved_glyph_ids->insert(GlyphId(0, font_id_));
19830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  IntegerSet* unresolved_glyph_ids = new IntegerSet;
19930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // Since composite glyph elements might themselves be composite, we would need
20030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // to recursively resolve the elements too. To avoid the recursion we
20130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // create two sets, |unresolved_glyph_ids| for the unresolved glyphs,
20230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // initially containing all the ids and |resolved_glyph_ids|, initially empty.
20330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // We'll remove glyph ids from |unresolved_glyph_ids| until it is empty and,
20430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // if the glyph is composite, add its elements to the unresolved set.
20530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  for (CharacterMap::iterator it = chars_to_glyph_ids->begin(),
20630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun           e = chars_to_glyph_ids->end(); it != e; ++it) {
20730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    unresolved_glyph_ids->insert(it->second.glyph_id());
20830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
20930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  // As long as there are unresolved glyph ids.
21030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  while (!unresolved_glyph_ids->empty()) {
21130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    // Get the corresponding glyph.
21230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    int32_t glyph_id = *(unresolved_glyph_ids->begin());
21330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    unresolved_glyph_ids->erase(unresolved_glyph_ids->begin());
21430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) {
21530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (SUBTLY_DEBUG)
21630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      fprintf(stderr, "%d larger than %d or smaller than 0\n", glyph_id,
21730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun              loca_table_->num_glyphs());
21830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif
21930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      continue;
22030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    }
22130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    int32_t length = loca_table_->GlyphLength(glyph_id);
22230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    if (length == 0) {
22330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (SUBTLY_DEBUG)
22430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      fprintf(stderr, "Zero length glyph %d\n", glyph_id);
22530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif
22630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      continue;
22730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    }
22830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    int32_t offset = loca_table_->GlyphOffset(glyph_id);
22930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    GlyphPtr glyph;
23030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    glyph.Attach(glyph_table_->GetGlyph(offset, length));
23130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    if (glyph == NULL) {
23230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined (SUBTLY_DEBUG)
23330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      fprintf(stderr, "GetGlyph returned NULL for %d\n", glyph_id);
23430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif
23530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      continue;
23630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    }
23730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    // Mark the glyph as resolved.
23830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    resolved_glyph_ids->insert(GlyphId(glyph_id, font_id_));
23930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    // If it is composite, add all its components to the unresolved glyph set.
24030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    if (glyph->GlyphType() == GlyphType::kComposite) {
24130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      Ptr<GlyphTable::CompositeGlyph> composite_glyph =
24230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun          down_cast<GlyphTable::CompositeGlyph*>(glyph.p_);
24330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      int32_t num_glyphs = composite_glyph->NumGlyphs();
24430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      for (int32_t i = 0; i < num_glyphs; ++i) {
24530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun        int32_t glyph_id = composite_glyph->GlyphIndex(i);
24630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun        if (resolved_glyph_ids->find(GlyphId(glyph_id, -1))
24730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun            == resolved_glyph_ids->end()) {
24830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun          unresolved_glyph_ids->insert(glyph_id);
24930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun        }
25030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun      }
25130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun    }
25230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  }
25330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  delete unresolved_glyph_ids;
25430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun  return true;
25530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
25630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun}
257