blob: 6c7d7315a453a1d146f61fa98e9d5e965c82e2fc [file] [log] [blame]
/*
* 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/bitmap/bitmap_size_table.h"
#include <stdio.h>
#include <stdlib.h>
#include "sfntly/math/font_math.h"
#include "sfntly/table/bitmap/eblc_table.h"
#include "sfntly/table/bitmap/index_sub_table_format1.h"
#include "sfntly/table/bitmap/index_sub_table_format2.h"
#include "sfntly/table/bitmap/index_sub_table_format3.h"
#include "sfntly/table/bitmap/index_sub_table_format4.h"
#include "sfntly/table/bitmap/index_sub_table_format5.h"
namespace sfntly {
/******************************************************************************
* BitmapSizeTable class
******************************************************************************/
BitmapSizeTable::~BitmapSizeTable() {
}
int32_t BitmapSizeTable::IndexSubTableArrayOffset() {
return data_->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset);
}
int32_t BitmapSizeTable::IndexTableSize() {
return data_->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_indexTableSize);
}
int32_t BitmapSizeTable::NumberOfIndexSubTables() {
return NumberOfIndexSubTables(data_, 0);
}
int32_t BitmapSizeTable::ColorRef() {
return data_->ReadULongAsInt(EblcTable::Offset::kBitmapSizeTable_colorRef);
}
int32_t BitmapSizeTable::StartGlyphIndex() {
return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_startGlyphIndex);
}
int32_t BitmapSizeTable::EndGlyphIndex() {
return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_endGlyphIndex);
}
int32_t BitmapSizeTable::PpemX() {
return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemX);
}
int32_t BitmapSizeTable::PpemY() {
return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemY);
}
int32_t BitmapSizeTable::BitDepth() {
return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_bitDepth);
}
int32_t BitmapSizeTable::FlagsAsInt() {
return data_->ReadChar(EblcTable::Offset::kBitmapSizeTable_flags);
}
IndexSubTable* BitmapSizeTable::GetIndexSubTable(int32_t index) {
IndexSubTableList* subtable_list = GetIndexSubTableList();
if (index >= 0 && (size_t)index < subtable_list->size()) {
return (*subtable_list)[index];
}
return NULL;
}
int32_t BitmapSizeTable::GlyphOffset(int32_t glyph_id) {
IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->GlyphOffset(glyph_id);
}
int32_t BitmapSizeTable::GlyphLength(int32_t glyph_id) {
IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->GlyphLength(glyph_id);
}
CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::GlyphInfo(int32_t glyph_id) {
IndexSubTable* sub_table = SearchIndexSubTables(glyph_id);
if (sub_table == NULL) {
return NULL;
}
return sub_table->GlyphInfo(glyph_id);
}
int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) {
IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->image_format();
}
BitmapSizeTable::BitmapSizeTable(ReadableFontData* data,
ReadableFontData* master_data)
: SubTable(data, master_data) {
}
// static
int32_t BitmapSizeTable::NumberOfIndexSubTables(ReadableFontData* data,
int32_t table_offset) {
return data->ReadULongAsInt(table_offset +
EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables);
}
IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) {
// would be faster to binary search but too many size tables don't have
// sorted subtables
#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH)
return BinarySearchIndexSubTables(glyph_id);
#else
return LinearSearchIndexSubTables(glyph_id);
#endif
}
IndexSubTable* BitmapSizeTable::LinearSearchIndexSubTables(int32_t glyph_id) {
IndexSubTableList* subtable_list = GetIndexSubTableList();
for (IndexSubTableList::iterator b = subtable_list->begin(),
e = subtable_list->end(); b != e; b++) {
if ((*b)->first_glyph_index() <= glyph_id &&
(*b)->last_glyph_index() >= glyph_id) {
return *b;
}
}
return NULL;
}
IndexSubTable* BitmapSizeTable::BinarySearchIndexSubTables(int32_t glyph_id) {
IndexSubTableList* subtable_list = GetIndexSubTableList();
int32_t index = 0;
int32_t bottom = 0;
int32_t top = subtable_list->size();
while (top != bottom) {
index = (top + bottom) / 2;
IndexSubTable* subtable = (*subtable_list)[index];
if (glyph_id < subtable->first_glyph_index()) {
// Location beow current location
top = index;
} else {
if (glyph_id <= subtable->last_glyph_index()) {
return subtable;
} else {
bottom = index + 1;
}
}
}
return NULL;
}
CALLER_ATTACH
IndexSubTable* BitmapSizeTable::CreateIndexSubTable(int32_t index) {
return IndexSubTable::CreateIndexSubTable(master_read_data(),
IndexSubTableArrayOffset(),
index);
}
IndexSubTableList* BitmapSizeTable::GetIndexSubTableList() {
AutoLock lock(index_subtables_lock_);
if (index_subtables_.empty()) {
for (int32_t i = 0; i < NumberOfIndexSubTables(); ++i) {
IndexSubTablePtr table;
table.Attach(CreateIndexSubTable(i));
index_subtables_.push_back(table);
}
}
return &index_subtables_;
}
/******************************************************************************
* BitmapSizeTable::Builder class
******************************************************************************/
BitmapSizeTable::Builder::~Builder() {
}
CALLER_ATTACH
FontDataTable* BitmapSizeTable::Builder::SubBuildTable(ReadableFontData* data) {
BitmapSizeTablePtr output = new BitmapSizeTable(data, master_read_data());
return output.Detach();
}
void BitmapSizeTable::Builder::SubDataSet() {
Revert();
}
int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() {
IndexSubTableBuilderList* builders = IndexSubTableBuilders();
if (builders->empty()) {
return 0;
}
int32_t size = EblcTable::Offset::kBitmapSizeTableLength;
bool variable = false;
for (IndexSubTableBuilderList::iterator b = builders->begin(),
e = builders->end(); b != e; b++) {
size += EblcTable::Offset::kIndexSubTableEntryLength;
int32_t sub_table_size = (*b)->SubDataSizeToSerialize();
int32_t padding = FontMath::PaddingRequired(abs(sub_table_size),
DataSize::kULONG);
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "subtable size=%d\n", sub_table_size);
#endif
variable = (sub_table_size > 0) ? variable : true;
size += abs(sub_table_size) + padding;
}
#if defined (SFNTLY_DEBUG_BITMAP)
fprintf(stderr, "bitmap table size=%d\n", variable ? -size : size);
#endif
return variable ? -size : size;
}
bool BitmapSizeTable::Builder::SubReadyToSerialize() {
if (IndexSubTableBuilders()->empty()) {
return false;
}
return true;
}
int32_t BitmapSizeTable::Builder::SubSerialize(WritableFontData* new_data) {
SetNumberOfIndexSubTables(IndexSubTableBuilders()->size());
int32_t size = InternalReadData()->CopyTo(new_data);
return size;
}
CALLER_ATTACH BitmapSizeTable::Builder*
BitmapSizeTable::Builder::CreateBuilder(WritableFontData* data,
ReadableFontData* master_data) {
BitmapSizeTableBuilderPtr output =
new BitmapSizeTable::Builder(data, master_data);
return output.Detach();
}
CALLER_ATTACH BitmapSizeTable::Builder*
BitmapSizeTable::Builder::CreateBuilder(ReadableFontData* data,
ReadableFontData* master_data) {
BitmapSizeTableBuilderPtr output =
new BitmapSizeTable::Builder(data, master_data);
return output.Detach();
}
int32_t BitmapSizeTable::Builder::IndexSubTableArrayOffset() {
return InternalReadData()->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset);
}
void BitmapSizeTable::Builder::SetIndexSubTableArrayOffset(int32_t offset) {
InternalWriteData()->WriteULong(
EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset, offset);
}
int32_t BitmapSizeTable::Builder::IndexTableSize() {
return InternalReadData()->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_indexTableSize);
}
void BitmapSizeTable::Builder::SetIndexTableSize(int32_t size) {
InternalWriteData()->WriteULong(
EblcTable::Offset::kBitmapSizeTable_indexTableSize, size);
}
int32_t BitmapSizeTable::Builder::NumberOfIndexSubTables() {
return GetIndexSubTableBuilders()->size();
}
int32_t BitmapSizeTable::Builder::ColorRef() {
return InternalReadData()->ReadULongAsInt(
EblcTable::Offset::kBitmapSizeTable_colorRef);
}
int32_t BitmapSizeTable::Builder::StartGlyphIndex() {
return InternalReadData()->ReadUShort(
EblcTable::Offset::kBitmapSizeTable_startGlyphIndex);
}
int32_t BitmapSizeTable::Builder::EndGlyphIndex() {
return InternalReadData()->ReadUShort(
EblcTable::Offset::kBitmapSizeTable_endGlyphIndex);
}
int32_t BitmapSizeTable::Builder::PpemX() {
return InternalReadData()->ReadByte(
EblcTable::Offset::kBitmapSizeTable_ppemX);
}
int32_t BitmapSizeTable::Builder::PpemY() {
return InternalReadData()->ReadByte(
EblcTable::Offset::kBitmapSizeTable_ppemY);
}
int32_t BitmapSizeTable::Builder::BitDepth() {
return InternalReadData()->ReadByte(
EblcTable::Offset::kBitmapSizeTable_bitDepth);
}
int32_t BitmapSizeTable::Builder::FlagsAsInt() {
return InternalReadData()->ReadChar(
EblcTable::Offset::kBitmapSizeTable_flags);
}
IndexSubTable::Builder* BitmapSizeTable::Builder::IndexSubTableBuilder(
int32_t index) {
IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders();
return sub_table_list->at(index);
}
CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::Builder::GlyphInfo(
int32_t glyph_id) {
IndexSubTable::Builder* sub_table = SearchIndexSubTables(glyph_id);
if (sub_table == NULL) {
return NULL;
}
return sub_table->GlyphInfo(glyph_id);
}
int32_t BitmapSizeTable::Builder::GlyphOffset(int32_t glyph_id) {
IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->GlyphOffset(glyph_id);
}
int32_t BitmapSizeTable::Builder::GlyphLength(int32_t glyph_id) {
IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->GlyphLength(glyph_id);
}
int32_t BitmapSizeTable::Builder::GlyphFormat(int32_t glyph_id) {
IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
if (subtable == NULL) {
return -1;
}
return subtable->image_format();
}
IndexSubTableBuilderList* BitmapSizeTable::Builder::IndexSubTableBuilders() {
return GetIndexSubTableBuilders();
}
CALLER_ATTACH BitmapSizeTable::Builder::BitmapGlyphInfoIterator*
BitmapSizeTable::Builder::GetIterator() {
Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> output =
new BitmapSizeTable::Builder::BitmapGlyphInfoIterator(this);
return output.Detach();
}
void BitmapSizeTable::Builder::GenerateLocaMap(BitmapGlyphInfoMap* output) {
assert(output);
Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> it;
it.Attach(GetIterator());
while (it->HasNext()) {
BitmapGlyphInfoPtr info;
info.Attach(it->Next());
(*output)[info->glyph_id()] = info;
}
}
void BitmapSizeTable::Builder::Revert() {
index_sub_tables_.clear();
set_model_changed(false);
}
BitmapSizeTable::Builder::Builder(WritableFontData* data,
ReadableFontData* master_data)
: SubTable::Builder(data, master_data) {
}
BitmapSizeTable::Builder::Builder(ReadableFontData* data,
ReadableFontData* master_data)
: SubTable::Builder(data, master_data) {
}
void BitmapSizeTable::Builder::SetNumberOfIndexSubTables(int32_t count) {
InternalWriteData()->WriteULong(
EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables, count);
}
IndexSubTable::Builder* BitmapSizeTable::Builder::SearchIndexSubTables(
int32_t glyph_id) {
// would be faster to binary search but too many size tables don't have
// sorted subtables
#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH)
return BinarySearchIndexSubTables(glyph_id);
#else
return LinearSearchIndexSubTables(glyph_id);
#endif
}
IndexSubTable::Builder* BitmapSizeTable::Builder::LinearSearchIndexSubTables(
int32_t glyph_id) {
IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders();
for (IndexSubTableBuilderList::iterator b = subtable_list->begin(),
e = subtable_list->end();
b != e; b++) {
if ((*b)->first_glyph_index() <= glyph_id &&
(*b)->last_glyph_index() >= glyph_id) {
return *b;
}
}
return NULL;
}
IndexSubTable::Builder* BitmapSizeTable::Builder::BinarySearchIndexSubTables(
int32_t glyph_id) {
IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders();
int32_t index = 0;
int32_t bottom = 0;
int32_t top = subtable_list->size();
while (top != bottom) {
index = (top + bottom) / 2;
IndexSubTable::Builder* subtable = subtable_list->at(index);
if (glyph_id < subtable->first_glyph_index()) {
// Location beow current location
top = index;
} else {
if (glyph_id <= subtable->last_glyph_index()) {
return subtable;
} else {
bottom = index + 1;
}
}
}
return NULL;
}
IndexSubTableBuilderList* BitmapSizeTable::Builder::GetIndexSubTableBuilders() {
if (index_sub_tables_.empty()) {
Initialize(InternalReadData());
set_model_changed();
}
return &index_sub_tables_;
}
void BitmapSizeTable::Builder::Initialize(ReadableFontData* data) {
index_sub_tables_.clear();
if (data) {
int32_t number_of_index_subtables =
BitmapSizeTable::NumberOfIndexSubTables(data, 0);
index_sub_tables_.resize(number_of_index_subtables);
for (int32_t i = 0; i < number_of_index_subtables; ++i) {
index_sub_tables_[i].Attach(CreateIndexSubTableBuilder(i));
}
}
}
CALLER_ATTACH IndexSubTable::Builder*
BitmapSizeTable::Builder::CreateIndexSubTableBuilder(int32_t index) {
return IndexSubTable::Builder::CreateBuilder(master_read_data(),
IndexSubTableArrayOffset(),
index);
}
/******************************************************************************
* BitmapSizeTable::Builder::BitmapGlyphInfoIterator class
******************************************************************************/
BitmapSizeTable::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
BitmapSizeTable::Builder* container)
: RefIterator<BitmapGlyphInfo, BitmapSizeTable::Builder>(container) {
sub_table_iter_ = container->IndexSubTableBuilders()->begin();
sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator());
}
bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext() {
if (sub_table_glyph_info_iter_ && HasNext(sub_table_glyph_info_iter_)) {
return true;
}
while (++sub_table_iter_ != container()->IndexSubTableBuilders()->end()) {
sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator());
if (HasNext(sub_table_glyph_info_iter_)) {
return true;
}
}
return false;
}
CALLER_ATTACH
BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next() {
if (!HasNext()) {
// Note: In C++, we do not throw exception when there's no element.
return NULL;
}
return Next(sub_table_glyph_info_iter_);
}
bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext(
BitmapGlyphInfoIter* iterator_base) {
if (iterator_base) {
switch (iterator_base->container_base()->index_format()) {
case 1: {
IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
case 2: {
IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
case 3: {
IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
case 4: {
IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
case 5: {
IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->HasNext();
}
default:
break;
}
}
return false;
}
CALLER_ATTACH
BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next(
BitmapGlyphInfoIter* iterator_base) {
if (iterator_base) {
switch (iterator_base->container_base()->index_format()) {
case 1: {
IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
case 2: {
IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
case 3: {
IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
case 4: {
IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
case 5: {
IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it =
down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>(
iterator_base);
return it->Next();
}
default:
break;
}
}
return NULL;
}
} // namespace sfntly