summaryrefslogtreecommitdiff
path: root/sfntly/table/truetype/glyph_table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sfntly/table/truetype/glyph_table.cc')
-rw-r--r--sfntly/table/truetype/glyph_table.cc667
1 files changed, 667 insertions, 0 deletions
diff --git a/sfntly/table/truetype/glyph_table.cc b/sfntly/table/truetype/glyph_table.cc
new file mode 100644
index 0000000..ff289f3
--- /dev/null
+++ b/sfntly/table/truetype/glyph_table.cc
@@ -0,0 +1,667 @@
+/*
+ * 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(data_, offset, length);
+}
+
+GlyphTable::GlyphTable(Header* header, ReadableFontData* data)
+ : Table(header, data) {
+}
+
+/******************************************************************************
+ * GlyphTable::Builder class
+ ******************************************************************************/
+GlyphTable::Builder::Builder(FontDataTableBuilderContainer* font_builder,
+ Header* header,
+ WritableFontData* data)
+ : Table::ArrayElementTableBuilder(font_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->resize(glyph_builders->size());
+ 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;
+ }
+ }
+}
+
+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()) {
+#if defined (SFNTLY_NO_EXCEPTION)
+ return;
+#else
+ throw IllegalStateException(
+ "Loca values not set - unable to parse glyph data.");
+#endif
+ }
+ 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()) {
+ 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(ReadableFontData* data,
+ int32_t offset,
+ int32_t length) {
+ 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::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);
+}
+
+int32_t GlyphTable::Glyph::Padding() {
+ return padding_;
+}
+
+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(FontDataTableBuilderContainer* font_builder,
+ WritableFontData* data)
+ : SubTable::Builder(font_builder, data) {
+}
+
+GlyphTable::Glyph::Builder::Builder(FontDataTableBuilderContainer* font_builder,
+ ReadableFontData* data)
+ : SubTable::Builder(font_builder, data) {
+}
+
+CALLER_ATTACH GlyphTable::Glyph::Builder*
+ GlyphTable::Glyph::Builder::GetBuilder(
+ FontDataTableBuilderContainer* table_builder,
+ ReadableFontData* data) {
+ return GetBuilder(table_builder, data, 0, data->Length());
+}
+
+CALLER_ATTACH GlyphTable::Glyph::Builder*
+ GlyphTable::Glyph::Builder::GetBuilder(
+ FontDataTableBuilderContainer* table_builder,
+ ReadableFontData* data,
+ int32_t offset,
+ int32_t length) {
+ 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(table_builder, sliced_data);
+ } else {
+ builder = new CompositeGlyph::CompositeGlyphBuilder(table_builder,
+ 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) {
+}
+
+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() {
+ 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);
+ padding_ = Length() - 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(
+ FontDataTableBuilderContainer* table_builder,
+ WritableFontData* data)
+ : Glyph::Builder(table_builder, data) {
+}
+
+GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder(
+ FontDataTableBuilderContainer* table_builder,
+ ReadableFontData* data)
+ : Glyph::Builder(table_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) {
+ ParseData();
+}
+
+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::ParseData() {
+ 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);
+ }
+ padding_ = Length() - non_padded_data_length;
+ }
+}
+
+/******************************************************************************
+ * GlyphTable::CompositeGlyph::Builder
+ ******************************************************************************/
+GlyphTable::CompositeGlyph::CompositeGlyphBuilder::~CompositeGlyphBuilder() {
+}
+
+GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder(
+ FontDataTableBuilderContainer* table_builder,
+ WritableFontData* data)
+ : Glyph::Builder(table_builder, data) {
+}
+
+GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder(
+ FontDataTableBuilderContainer* table_builder,
+ ReadableFontData* data)
+ : Glyph::Builder(table_builder, data) {
+}
+
+CALLER_ATTACH FontDataTable*
+ GlyphTable::CompositeGlyph::CompositeGlyphBuilder::SubBuildTable(
+ ReadableFontData* data) {
+ FontDataTablePtr table = new CompositeGlyph(data);
+ return table.Detach();
+}
+
+} // namespace sfntly