| /* |
| * 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/truetype/glyph_table.h" |
| |
| #include <stdlib.h> |
| |
| #include "sfntly/port/exception_type.h" |
| |
| namespace sfntly { |
| /****************************************************************************** |
| * Constants |
| ******************************************************************************/ |
| const int32_t GlyphTable::SimpleGlyph::kFLAG_ONCURVE = 1; |
| const int32_t GlyphTable::SimpleGlyph::kFLAG_XSHORT = 1 << 1; |
| const int32_t GlyphTable::SimpleGlyph::kFLAG_YSHORT = 1 << 2; |
| const int32_t GlyphTable::SimpleGlyph::kFLAG_REPEAT = 1 << 3; |
| const int32_t GlyphTable::SimpleGlyph::kFLAG_XREPEATSIGN = 1 << 4; |
| const int32_t GlyphTable::SimpleGlyph::kFLAG_YREPEATSIGN = 1 << 5; |
| |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_ARGS_ARE_XY_VALUES = 1 << 1; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_ROUND_XY_TO_GRID = 1 << 2; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_SCALE = 1 << 3; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_RESERVED = 1 << 4; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_MORE_COMPONENTS = 1 << 5; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_USE_MY_METRICS = 1 << 9; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_OVERLAP_COMPOUND = 1 << 10; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_SCALED_COMPONENT_OFFSET = 1 << 11; |
| const int32_t GlyphTable::CompositeGlyph::kFLAG_UNSCALED_COMPONENT_OFFSET = 1 << 12; |
| |
| /****************************************************************************** |
| * GlyphTable class |
| ******************************************************************************/ |
| GlyphTable::~GlyphTable() { |
| } |
| |
| GlyphTable::Glyph* GlyphTable::GetGlyph(int32_t offset, int32_t length) { |
| return GlyphTable::Glyph::GetGlyph(this, this->data_, offset, length); |
| } |
| |
| GlyphTable::GlyphTable(Header* header, ReadableFontData* data) |
| : SubTableContainerTable(header, data) { |
| } |
| |
| /****************************************************************************** |
| * GlyphTable::Builder class |
| ******************************************************************************/ |
| GlyphTable::Builder::Builder(Header* header, ReadableFontData* data) |
| : SubTableContainerTable::Builder(header, data) { |
| } |
| |
| GlyphTable::Builder::~Builder() { |
| } |
| |
| void GlyphTable::Builder::SetLoca(const IntegerList& loca) { |
| loca_ = loca; |
| set_model_changed(false); |
| glyph_builders_.clear(); |
| } |
| |
| void GlyphTable::Builder::GenerateLocaList(IntegerList* locas) { |
| assert(locas); |
| GlyphBuilderList* glyph_builders = GetGlyphBuilders(); |
| locas->push_back(0); |
| if (glyph_builders->size() == 0) { |
| locas->push_back(0); |
| } else { |
| int32_t total = 0; |
| for (GlyphBuilderList::iterator b = glyph_builders->begin(), |
| b_end = glyph_builders->end(); |
| b != b_end; ++b) { |
| int32_t size = (*b)->SubDataSizeToSerialize(); |
| locas->push_back(total + size); |
| total += size; |
| } |
| } |
| } |
| |
| CALLER_ATTACH GlyphTable::Builder* |
| GlyphTable::Builder::CreateBuilder(Header* header, WritableFontData* data) { |
| Ptr<GlyphTable::Builder> builder; |
| builder = new GlyphTable::Builder(header, data); |
| return builder.Detach(); |
| } |
| |
| GlyphTable::GlyphBuilderList* GlyphTable::Builder::GlyphBuilders() { |
| return GetGlyphBuilders(); |
| } |
| |
| void GlyphTable::Builder::SetGlyphBuilders(GlyphBuilderList* glyph_builders) { |
| glyph_builders_ = *glyph_builders; |
| set_model_changed(); |
| } |
| |
| CALLER_ATTACH GlyphTable::Glyph::Builder* |
| GlyphTable::Builder::GlyphBuilder(ReadableFontData* data) { |
| return Glyph::Builder::GetBuilder(this, data); |
| } |
| |
| CALLER_ATTACH FontDataTable* |
| GlyphTable::Builder::SubBuildTable(ReadableFontData* data) { |
| FontDataTablePtr table = new GlyphTable(header(), data); |
| return table.Detach(); |
| } |
| |
| void GlyphTable::Builder::SubDataSet() { |
| glyph_builders_.clear(); |
| set_model_changed(false); |
| } |
| |
| int32_t GlyphTable::Builder::SubDataSizeToSerialize() { |
| if (glyph_builders_.empty()) |
| return 0; |
| |
| bool variable = false; |
| int32_t size = 0; |
| |
| // Calculate size of each table. |
| for (GlyphBuilderList::iterator b = glyph_builders_.begin(), |
| end = glyph_builders_.end(); b != end; ++b) { |
| int32_t glyph_size = (*b)->SubDataSizeToSerialize(); |
| size += abs(glyph_size); |
| variable |= glyph_size <= 0; |
| } |
| return variable ? -size : size; |
| } |
| |
| bool GlyphTable::Builder::SubReadyToSerialize() { |
| return !glyph_builders_.empty(); |
| } |
| |
| int32_t GlyphTable::Builder::SubSerialize(WritableFontData* new_data) { |
| int32_t size = 0; |
| for (GlyphBuilderList::iterator b = glyph_builders_.begin(), |
| end = glyph_builders_.end(); b != end; ++b) { |
| FontDataPtr data; |
| data.Attach(new_data->Slice(size)); |
| size += (*b)->SubSerialize(down_cast<WritableFontData*>(data.p_)); |
| } |
| return size; |
| } |
| |
| void GlyphTable::Builder::Initialize(ReadableFontData* data, |
| const IntegerList& loca) { |
| if (data != NULL) { |
| if (loca_.empty()) { |
| return; |
| } |
| int32_t loca_value; |
| int32_t last_loca_value = loca[0]; |
| for (size_t i = 1; i < loca.size(); ++i) { |
| loca_value = loca[i]; |
| GlyphBuilderPtr builder; |
| builder.Attach( |
| Glyph::Builder::GetBuilder(this, |
| data, |
| last_loca_value /*offset*/, |
| loca_value - last_loca_value /*length*/)); |
| glyph_builders_.push_back(builder); |
| last_loca_value = loca_value; |
| } |
| } |
| } |
| |
| GlyphTable::GlyphBuilderList* GlyphTable::Builder::GetGlyphBuilders() { |
| if (glyph_builders_.empty()) { |
| if (InternalReadData() && !loca_.empty()) { |
| #if !defined (SFNTLY_NO_EXCEPTION) |
| throw IllegalStateException( |
| "Loca values not set - unable to parse glyph data."); |
| #endif |
| return NULL; |
| } |
| Initialize(InternalReadData(), loca_); |
| set_model_changed(); |
| } |
| return &glyph_builders_; |
| } |
| |
| void GlyphTable::Builder::Revert() { |
| glyph_builders_.clear(); |
| set_model_changed(false); |
| } |
| |
| /****************************************************************************** |
| * GlyphTable::Glyph class |
| ******************************************************************************/ |
| GlyphTable::Glyph::~Glyph() {} |
| |
| CALLER_ATTACH GlyphTable::Glyph* |
| GlyphTable::Glyph::GetGlyph(GlyphTable* table, |
| ReadableFontData* data, |
| int32_t offset, |
| int32_t length) { |
| UNREFERENCED_PARAMETER(table); |
| int32_t type = GlyphType(data, offset, length); |
| GlyphPtr glyph; |
| |
| ReadableFontDataPtr sliced_data; |
| sliced_data.Attach(down_cast<ReadableFontData*>(data->Slice(offset, length))); |
| if (type == GlyphType::kSimple) { |
| glyph = new SimpleGlyph(sliced_data); |
| } else { |
| glyph = new CompositeGlyph(sliced_data); |
| } |
| return glyph.Detach(); |
| } |
| |
| int32_t GlyphTable::Glyph::Padding() { |
| Initialize(); |
| return SubTable::Padding(); |
| } |
| |
| int32_t GlyphTable::Glyph::GlyphType() { |
| return glyph_type_; |
| } |
| |
| int32_t GlyphTable::Glyph::NumberOfContours() { |
| return number_of_contours_; |
| } |
| |
| int32_t GlyphTable::Glyph::XMin() { |
| return data_->ReadShort(Offset::kXMin); |
| } |
| |
| int32_t GlyphTable::Glyph::XMax() { |
| return data_->ReadShort(Offset::kXMax); |
| } |
| |
| int32_t GlyphTable::Glyph::YMin() { |
| return data_->ReadShort(Offset::kYMin); |
| } |
| |
| int32_t GlyphTable::Glyph::YMax() { |
| return data_->ReadShort(Offset::kYMax); |
| } |
| |
| GlyphTable::Glyph::Glyph(ReadableFontData* data, int32_t glyph_type) |
| : SubTable(data), |
| glyph_type_(glyph_type) { |
| if (data_->Length() == 0) { |
| number_of_contours_ = 0; |
| } else { |
| // -1 if composite |
| number_of_contours_ = data_->ReadShort(Offset::kNumberOfContours); |
| } |
| } |
| |
| int32_t GlyphTable::Glyph::GlyphType(ReadableFontData* data, |
| int32_t offset, |
| int32_t length) { |
| if (length == 0) { |
| return GlyphType::kSimple; |
| } |
| int32_t number_of_contours = data->ReadShort(offset); |
| if (number_of_contours >= 0) { |
| return GlyphType::kSimple; |
| } |
| return GlyphType::kComposite; |
| } |
| |
| /****************************************************************************** |
| * GlyphTable::Glyph::Builder class |
| ******************************************************************************/ |
| GlyphTable::Glyph::Builder::~Builder() { |
| } |
| |
| GlyphTable::Glyph::Builder::Builder(WritableFontData* data) |
| : SubTable::Builder(data) { |
| } |
| |
| GlyphTable::Glyph::Builder::Builder(ReadableFontData* data) |
| : SubTable::Builder(data) { |
| } |
| |
| CALLER_ATTACH GlyphTable::Glyph::Builder* |
| GlyphTable::Glyph::Builder::GetBuilder( |
| GlyphTable::Builder* table_builder, |
| ReadableFontData* data) { |
| return GetBuilder(table_builder, data, 0, data->Length()); |
| } |
| |
| CALLER_ATTACH GlyphTable::Glyph::Builder* |
| GlyphTable::Glyph::Builder::GetBuilder( |
| GlyphTable::Builder* table_builder, |
| ReadableFontData* data, |
| int32_t offset, |
| int32_t length) { |
| UNREFERENCED_PARAMETER(table_builder); |
| int32_t type = Glyph::GlyphType(data, offset, length); |
| GlyphBuilderPtr builder; |
| ReadableFontDataPtr sliced_data; |
| sliced_data.Attach(down_cast<ReadableFontData*>(data->Slice(offset, length))); |
| if (type == GlyphType::kSimple) { |
| builder = new SimpleGlyph::SimpleGlyphBuilder(sliced_data); |
| } else { |
| builder = new CompositeGlyph::CompositeGlyphBuilder(sliced_data); |
| } |
| return builder.Detach(); |
| } |
| |
| void GlyphTable::Glyph::Builder::SubDataSet() { |
| // NOP |
| } |
| |
| int32_t GlyphTable::Glyph::Builder::SubDataSizeToSerialize() { |
| return InternalReadData()->Length(); |
| } |
| |
| bool GlyphTable::Glyph::Builder::SubReadyToSerialize() { |
| return true; |
| } |
| |
| int32_t GlyphTable::Glyph::Builder::SubSerialize(WritableFontData* new_data) { |
| return InternalReadData()->CopyTo(new_data); |
| } |
| |
| /****************************************************************************** |
| * GlyphTable::SimpleGlyph |
| ******************************************************************************/ |
| GlyphTable::SimpleGlyph::SimpleGlyph(ReadableFontData* data) |
| : GlyphTable::Glyph(data, GlyphType::kSimple), initialized_(false) { |
| } |
| |
| GlyphTable::SimpleGlyph::~SimpleGlyph() { |
| } |
| |
| int32_t GlyphTable::SimpleGlyph::InstructionSize() { |
| Initialize(); |
| return instruction_size_; |
| } |
| |
| CALLER_ATTACH ReadableFontData* GlyphTable::SimpleGlyph::Instructions() { |
| Initialize(); |
| return down_cast<ReadableFontData*>( |
| data_->Slice(instructions_offset_, InstructionSize())); |
| } |
| |
| int32_t GlyphTable::SimpleGlyph::NumberOfPoints(int32_t contour) { |
| Initialize(); |
| if (contour >= NumberOfContours()) { |
| return 0; |
| } |
| return contour_index_[contour + 1] - contour_index_[contour]; |
| } |
| |
| int32_t GlyphTable::SimpleGlyph::XCoordinate(int32_t contour, int32_t point) { |
| Initialize(); |
| return x_coordinates_[contour_index_[contour] + point]; |
| } |
| |
| int32_t GlyphTable::SimpleGlyph::YCoordinate(int32_t contour, int32_t point) { |
| Initialize(); |
| return y_coordinates_[contour_index_[contour] + point]; |
| } |
| |
| bool GlyphTable::SimpleGlyph::OnCurve(int32_t contour, int32_t point) { |
| Initialize(); |
| return on_curve_[contour_index_[contour] + point]; |
| } |
| |
| void GlyphTable::SimpleGlyph::Initialize() { |
| AutoLock lock(initialization_lock_); |
| if (initialized_) { |
| return; |
| } |
| |
| if (ReadFontData()->Length() == 0) { |
| instruction_size_ = 0; |
| number_of_points_ = 0; |
| instructions_offset_ = 0; |
| flags_offset_ = 0; |
| x_coordinates_offset_ = 0; |
| y_coordinates_offset_ = 0; |
| return; |
| } |
| |
| instruction_size_ = data_->ReadUShort(Offset::kSimpleEndPtsOfCountours + |
| NumberOfContours() * DataSize::kUSHORT); |
| instructions_offset_ = Offset::kSimpleEndPtsOfCountours + |
| (NumberOfContours() + 1) * DataSize::kUSHORT; |
| flags_offset_ = instructions_offset_ + instruction_size_ * DataSize::kBYTE; |
| number_of_points_ = ContourEndPoint(NumberOfContours() - 1) + 1; |
| x_coordinates_.resize(number_of_points_); |
| y_coordinates_.resize(number_of_points_); |
| on_curve_.resize(number_of_points_); |
| ParseData(false); |
| x_coordinates_offset_ = flags_offset_ + flag_byte_count_ * DataSize::kBYTE; |
| y_coordinates_offset_ = x_coordinates_offset_ + x_byte_count_ * |
| DataSize::kBYTE; |
| contour_index_.resize(NumberOfContours() + 1); |
| contour_index_[0] = 0; |
| for (uint32_t contour = 0; contour < contour_index_.size() - 1; ++contour) { |
| contour_index_[contour + 1] = ContourEndPoint(contour) + 1; |
| } |
| ParseData(true); |
| int32_t non_padded_data_length = |
| 5 * DataSize::kSHORT + |
| (NumberOfContours() * DataSize::kUSHORT) + |
| DataSize::kUSHORT + |
| (instruction_size_ * DataSize::kBYTE) + |
| (flag_byte_count_ * DataSize::kBYTE) + |
| (x_byte_count_ * DataSize::kBYTE) + |
| (y_byte_count_ * DataSize::kBYTE); |
| set_padding(DataLength() - non_padded_data_length); |
| initialized_ = true; |
| } |
| |
| void GlyphTable::SimpleGlyph::ParseData(bool fill_arrays) { |
| int32_t flag = 0; |
| int32_t flag_repeat = 0; |
| int32_t flag_index = 0; |
| int32_t x_byte_index = 0; |
| int32_t y_byte_index = 0; |
| |
| for (int32_t point_index = 0; point_index < number_of_points_; |
| ++point_index) { |
| // get the flag for the current point |
| if (flag_repeat == 0) { |
| flag = FlagAsInt(flag_index++); |
| if ((flag & kFLAG_REPEAT) == kFLAG_REPEAT) { |
| flag_repeat = FlagAsInt(flag_index++); |
| } |
| } else { |
| flag_repeat--; |
| } |
| |
| // on the curve? |
| if (fill_arrays) { |
| on_curve_[point_index] = ((flag & kFLAG_ONCURVE) == kFLAG_ONCURVE); |
| } |
| // get the x coordinate |
| if ((flag & kFLAG_XSHORT) == kFLAG_XSHORT) { |
| // single byte x coord value |
| if (fill_arrays) { |
| x_coordinates_[point_index] = |
| data_->ReadUByte(x_coordinates_offset_ + x_byte_index); |
| x_coordinates_[point_index] *= |
| ((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN) ? 1 : -1; |
| } |
| x_byte_index++; |
| } else { |
| // double byte coord value |
| if (!((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN)) { |
| if (fill_arrays) { |
| x_coordinates_[point_index] = |
| data_->ReadShort(x_coordinates_offset_ + x_byte_index); |
| } |
| x_byte_index += 2; |
| } |
| } |
| if (fill_arrays && point_index > 0) { |
| x_coordinates_[point_index] += x_coordinates_[point_index - 1]; |
| } |
| |
| // get the y coordinate |
| if ((flag & kFLAG_YSHORT) == kFLAG_YSHORT) { |
| if (fill_arrays) { |
| y_coordinates_[point_index] = |
| data_->ReadUByte(y_coordinates_offset_ + y_byte_index); |
| y_coordinates_[point_index] *= |
| ((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN) ? 1 : -1; |
| } |
| y_byte_index++; |
| } else { |
| if (!((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN)) { |
| if (fill_arrays) { |
| y_coordinates_[point_index] = |
| data_->ReadShort(y_coordinates_offset_ + y_byte_index); |
| } |
| y_byte_index += 2; |
| } |
| } |
| if (fill_arrays && point_index > 0) { |
| y_coordinates_[point_index] += y_coordinates_[point_index - 1]; |
| } |
| } |
| flag_byte_count_ = flag_index; |
| x_byte_count_ = x_byte_index; |
| y_byte_count_ = y_byte_index; |
| } |
| |
| int32_t GlyphTable::SimpleGlyph::FlagAsInt(int32_t index) { |
| return data_->ReadUByte(flags_offset_ + index * DataSize::kBYTE); |
| } |
| |
| int32_t GlyphTable::SimpleGlyph::ContourEndPoint(int32_t contour) { |
| return data_->ReadUShort(contour * DataSize::kUSHORT + |
| Offset::kSimpleEndPtsOfCountours); |
| } |
| |
| /****************************************************************************** |
| * GlyphTable::SimpleGlyph::Builder |
| ******************************************************************************/ |
| GlyphTable::SimpleGlyph::SimpleGlyphBuilder::~SimpleGlyphBuilder() { |
| } |
| |
| GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder( |
| WritableFontData* data) |
| : Glyph::Builder(data) { |
| } |
| |
| GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder( |
| ReadableFontData* data) |
| : Glyph::Builder(data) { |
| } |
| |
| CALLER_ATTACH FontDataTable* |
| GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SubBuildTable( |
| ReadableFontData* data) { |
| FontDataTablePtr table = new SimpleGlyph(data); |
| return table.Detach(); |
| } |
| |
| /****************************************************************************** |
| * GlyphTable::CompositeGlyph |
| ******************************************************************************/ |
| GlyphTable::CompositeGlyph::CompositeGlyph(ReadableFontData* data) |
| : GlyphTable::Glyph(data, GlyphType::kComposite), |
| instruction_size_(0), |
| instructions_offset_(0), |
| initialized_(false) { |
| Initialize(); |
| } |
| |
| GlyphTable::CompositeGlyph::~CompositeGlyph() { |
| } |
| |
| int32_t GlyphTable::CompositeGlyph::Flags(int32_t contour) { |
| return data_->ReadUShort(contour_index_[contour]); |
| } |
| |
| int32_t GlyphTable::CompositeGlyph::NumGlyphs() { |
| return contour_index_.size(); |
| } |
| |
| int32_t GlyphTable::CompositeGlyph::GlyphIndex(int32_t contour) { |
| return data_->ReadUShort(DataSize::kUSHORT + contour_index_[contour]); |
| } |
| |
| int32_t GlyphTable::CompositeGlyph::Argument1(int32_t contour) { |
| int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour]; |
| int32_t contour_flags = Flags(contour); |
| if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == |
| kFLAG_ARG_1_AND_2_ARE_WORDS) { |
| return data_->ReadUShort(index); |
| } |
| return data_->ReadByte(index); |
| } |
| |
| int32_t GlyphTable::CompositeGlyph::Argument2(int32_t contour) { |
| int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour]; |
| int32_t contour_flags = Flags(contour); |
| if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == |
| kFLAG_ARG_1_AND_2_ARE_WORDS) { |
| return data_->ReadUShort(index + DataSize::kUSHORT); |
| } |
| return data_->ReadByte(index + DataSize::kUSHORT); |
| } |
| |
| int32_t GlyphTable::CompositeGlyph::TransformationSize(int32_t contour) { |
| int32_t contour_flags = Flags(contour); |
| if ((contour_flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) { |
| return DataSize::kF2DOT14; |
| } else if ((contour_flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) == |
| kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) { |
| return 2 * DataSize::kF2DOT14; |
| } else if ((contour_flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) == |
| kFLAG_WE_HAVE_A_TWO_BY_TWO) { |
| return 4 * DataSize::kF2DOT14; |
| } |
| return 0; |
| } |
| |
| void GlyphTable::CompositeGlyph::Transformation(int32_t contour, |
| ByteVector* transformation) { |
| int32_t contour_flags = Flags(contour); |
| int32_t index = contour_index_[contour] + 2 * DataSize::kUSHORT; |
| if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == |
| kFLAG_ARG_1_AND_2_ARE_WORDS) { |
| index += 2 * DataSize::kSHORT; |
| } else { |
| index += 2 * DataSize::kBYTE; |
| } |
| int32_t tsize = TransformationSize(contour); |
| transformation->resize(tsize); |
| data_->ReadBytes(index, &((*transformation)[0]), 0, tsize); |
| } |
| |
| int32_t GlyphTable::CompositeGlyph::InstructionSize() { |
| return instruction_size_; |
| } |
| |
| CALLER_ATTACH ReadableFontData* GlyphTable::CompositeGlyph::Instructions() { |
| return down_cast<ReadableFontData*>( |
| data_->Slice(instructions_offset_, InstructionSize())); |
| } |
| |
| void GlyphTable::CompositeGlyph::Initialize() { |
| AutoLock lock(initialization_lock_); |
| if (initialized_) { |
| return; |
| } |
| |
| int32_t index = 5 * DataSize::kUSHORT; |
| int32_t flags = kFLAG_MORE_COMPONENTS; |
| |
| while ((flags & kFLAG_MORE_COMPONENTS) == kFLAG_MORE_COMPONENTS) { |
| contour_index_.push_back(index); |
| flags = data_->ReadUShort(index); |
| index += 2 * DataSize::kUSHORT; // flags and glyphIndex |
| if ((flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == kFLAG_ARG_1_AND_2_ARE_WORDS) { |
| index += 2 * DataSize::kSHORT; |
| } else { |
| index += 2 * DataSize::kBYTE; |
| } |
| if ((flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) { |
| index += DataSize::kF2DOT14; |
| } else if ((flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) == |
| kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) { |
| index += 2 * DataSize::kF2DOT14; |
| } else if ((flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) == |
| kFLAG_WE_HAVE_A_TWO_BY_TWO) { |
| index += 4 * DataSize::kF2DOT14; |
| } |
| int32_t non_padded_data_length = index; |
| if ((flags & kFLAG_WE_HAVE_INSTRUCTIONS) == kFLAG_WE_HAVE_INSTRUCTIONS) { |
| instruction_size_ = data_->ReadUShort(index); |
| index += DataSize::kUSHORT; |
| instructions_offset_ = index; |
| non_padded_data_length = index + (instruction_size_ * DataSize::kBYTE); |
| } |
| set_padding(DataLength() - non_padded_data_length); |
| } |
| |
| initialized_ = true; |
| } |
| |
| /****************************************************************************** |
| * GlyphTable::CompositeGlyph::Builder |
| ******************************************************************************/ |
| GlyphTable::CompositeGlyph::CompositeGlyphBuilder::~CompositeGlyphBuilder() { |
| } |
| |
| GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder( |
| WritableFontData* data) |
| : Glyph::Builder(data) { |
| } |
| |
| GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder( |
| ReadableFontData* data) |
| : Glyph::Builder(data) { |
| } |
| |
| CALLER_ATTACH FontDataTable* |
| GlyphTable::CompositeGlyph::CompositeGlyphBuilder::SubBuildTable( |
| ReadableFontData* data) { |
| FontDataTablePtr table = new CompositeGlyph(data); |
| return table.Detach(); |
| } |
| |
| } // namespace sfntly |