• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "sfntly/table/truetype/glyph_table.h"
18 
19 #include <stdlib.h>
20 
21 #include "sfntly/port/exception_type.h"
22 
23 namespace sfntly {
24 /******************************************************************************
25  * Constants
26  ******************************************************************************/
27 const int32_t GlyphTable::SimpleGlyph::kFLAG_ONCURVE = 1;
28 const int32_t GlyphTable::SimpleGlyph::kFLAG_XSHORT = 1 << 1;
29 const int32_t GlyphTable::SimpleGlyph::kFLAG_YSHORT = 1 << 2;
30 const int32_t GlyphTable::SimpleGlyph::kFLAG_REPEAT = 1 << 3;
31 const int32_t GlyphTable::SimpleGlyph::kFLAG_XREPEATSIGN = 1 << 4;
32 const int32_t GlyphTable::SimpleGlyph::kFLAG_YREPEATSIGN = 1 << 5;
33 
34 const int32_t GlyphTable::CompositeGlyph::kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
35 const int32_t GlyphTable::CompositeGlyph::kFLAG_ARGS_ARE_XY_VALUES = 1 << 1;
36 const int32_t GlyphTable::CompositeGlyph::kFLAG_ROUND_XY_TO_GRID = 1 << 2;
37 const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_SCALE = 1 << 3;
38 const int32_t GlyphTable::CompositeGlyph::kFLAG_RESERVED = 1 << 4;
39 const int32_t GlyphTable::CompositeGlyph::kFLAG_MORE_COMPONENTS = 1 << 5;
40 const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
41 const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
42 const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
43 const int32_t GlyphTable::CompositeGlyph::kFLAG_USE_MY_METRICS = 1 << 9;
44 const int32_t GlyphTable::CompositeGlyph::kFLAG_OVERLAP_COMPOUND = 1 << 10;
45 const int32_t GlyphTable::CompositeGlyph::kFLAG_SCALED_COMPONENT_OFFSET = 1 << 11;
46 const int32_t GlyphTable::CompositeGlyph::kFLAG_UNSCALED_COMPONENT_OFFSET = 1 << 12;
47 
48 /******************************************************************************
49  * GlyphTable class
50  ******************************************************************************/
~GlyphTable()51 GlyphTable::~GlyphTable() {
52 }
53 
GetGlyph(int32_t offset,int32_t length)54 GlyphTable::Glyph* GlyphTable::GetGlyph(int32_t offset, int32_t length) {
55   return GlyphTable::Glyph::GetGlyph(this, this->data_, offset, length);
56 }
57 
GlyphTable(Header * header,ReadableFontData * data)58 GlyphTable::GlyphTable(Header* header, ReadableFontData* data)
59     : SubTableContainerTable(header, data) {
60 }
61 
62 /******************************************************************************
63  * GlyphTable::Builder class
64  ******************************************************************************/
Builder(Header * header,ReadableFontData * data)65 GlyphTable::Builder::Builder(Header* header, ReadableFontData* data)
66     : SubTableContainerTable::Builder(header, data) {
67 }
68 
~Builder()69 GlyphTable::Builder::~Builder() {
70 }
71 
SetLoca(const IntegerList & loca)72 void GlyphTable::Builder::SetLoca(const IntegerList& loca) {
73   loca_ = loca;
74   set_model_changed(false);
75   glyph_builders_.clear();
76 }
77 
GenerateLocaList(IntegerList * locas)78 void GlyphTable::Builder::GenerateLocaList(IntegerList* locas) {
79   assert(locas);
80   GlyphBuilderList* glyph_builders = GetGlyphBuilders();
81   locas->push_back(0);
82   if (glyph_builders->size() == 0) {
83     locas->push_back(0);
84   } else {
85     int32_t total = 0;
86     for (GlyphBuilderList::iterator b = glyph_builders->begin(),
87                                     b_end = glyph_builders->end();
88                                     b != b_end; ++b) {
89       int32_t size = (*b)->SubDataSizeToSerialize();
90       locas->push_back(total + size);
91       total += size;
92     }
93   }
94 }
95 
96 CALLER_ATTACH GlyphTable::Builder*
CreateBuilder(Header * header,WritableFontData * data)97     GlyphTable::Builder::CreateBuilder(Header* header, WritableFontData* data) {
98   Ptr<GlyphTable::Builder> builder;
99   builder = new GlyphTable::Builder(header, data);
100   return builder.Detach();
101 }
102 
GlyphBuilders()103 GlyphTable::GlyphBuilderList* GlyphTable::Builder::GlyphBuilders() {
104   return GetGlyphBuilders();
105 }
106 
SetGlyphBuilders(GlyphBuilderList * glyph_builders)107 void GlyphTable::Builder::SetGlyphBuilders(GlyphBuilderList* glyph_builders) {
108   glyph_builders_ = *glyph_builders;
109   set_model_changed();
110 }
111 
112 CALLER_ATTACH GlyphTable::Glyph::Builder*
GlyphBuilder(ReadableFontData * data)113     GlyphTable::Builder::GlyphBuilder(ReadableFontData* data) {
114   return Glyph::Builder::GetBuilder(this, data);
115 }
116 
117 CALLER_ATTACH FontDataTable*
SubBuildTable(ReadableFontData * data)118     GlyphTable::Builder::SubBuildTable(ReadableFontData* data) {
119   FontDataTablePtr table = new GlyphTable(header(), data);
120   return table.Detach();
121 }
122 
SubDataSet()123 void GlyphTable::Builder::SubDataSet() {
124   glyph_builders_.clear();
125   set_model_changed(false);
126 }
127 
SubDataSizeToSerialize()128 int32_t GlyphTable::Builder::SubDataSizeToSerialize() {
129   if (glyph_builders_.empty())
130     return 0;
131 
132   bool variable = false;
133   int32_t size = 0;
134 
135   // Calculate size of each table.
136   for (GlyphBuilderList::iterator b = glyph_builders_.begin(),
137                                   end = glyph_builders_.end(); b != end; ++b) {
138       int32_t glyph_size = (*b)->SubDataSizeToSerialize();
139       size += abs(glyph_size);
140       variable |= glyph_size <= 0;
141   }
142   return variable ? -size : size;
143 }
144 
SubReadyToSerialize()145 bool GlyphTable::Builder::SubReadyToSerialize() {
146   return !glyph_builders_.empty();
147 }
148 
SubSerialize(WritableFontData * new_data)149 int32_t GlyphTable::Builder::SubSerialize(WritableFontData* new_data) {
150   int32_t size = 0;
151   for (GlyphBuilderList::iterator b = glyph_builders_.begin(),
152                                   end = glyph_builders_.end(); b != end; ++b) {
153     FontDataPtr data;
154     data.Attach(new_data->Slice(size));
155     size += (*b)->SubSerialize(down_cast<WritableFontData*>(data.p_));
156   }
157   return size;
158 }
159 
Initialize(ReadableFontData * data,const IntegerList & loca)160 void GlyphTable::Builder::Initialize(ReadableFontData* data,
161                                      const IntegerList& loca) {
162   if (data != NULL) {
163     if (loca_.empty()) {
164       return;
165     }
166     int32_t loca_value;
167     int32_t last_loca_value = loca[0];
168     for (size_t i = 1; i < loca.size(); ++i) {
169       loca_value = loca[i];
170       GlyphBuilderPtr builder;
171       builder.Attach(
172         Glyph::Builder::GetBuilder(this,
173                                    data,
174                                    last_loca_value /*offset*/,
175                                    loca_value - last_loca_value /*length*/));
176       glyph_builders_.push_back(builder);
177       last_loca_value = loca_value;
178     }
179   }
180 }
181 
GetGlyphBuilders()182 GlyphTable::GlyphBuilderList* GlyphTable::Builder::GetGlyphBuilders() {
183   if (glyph_builders_.empty()) {
184     if (InternalReadData() && !loca_.empty()) {
185 #if !defined (SFNTLY_NO_EXCEPTION)
186       throw IllegalStateException(
187           "Loca values not set - unable to parse glyph data.");
188 #endif
189       return NULL;
190     }
191     Initialize(InternalReadData(), loca_);
192     set_model_changed();
193   }
194   return &glyph_builders_;
195 }
196 
Revert()197 void GlyphTable::Builder::Revert() {
198   glyph_builders_.clear();
199   set_model_changed(false);
200 }
201 
202 /******************************************************************************
203  * GlyphTable::Glyph class
204  ******************************************************************************/
~Glyph()205 GlyphTable::Glyph::~Glyph() {}
206 
207 CALLER_ATTACH GlyphTable::Glyph*
GetGlyph(GlyphTable * table,ReadableFontData * data,int32_t offset,int32_t length)208     GlyphTable::Glyph::GetGlyph(GlyphTable* table,
209                                 ReadableFontData* data,
210                                 int32_t offset,
211                                 int32_t length) {
212   UNREFERENCED_PARAMETER(table);
213   int32_t type = GlyphType(data, offset, length);
214   GlyphPtr glyph;
215 
216   ReadableFontDataPtr sliced_data;
217   sliced_data.Attach(down_cast<ReadableFontData*>(data->Slice(offset, length)));
218   if (sliced_data) {
219     if (type == GlyphType::kSimple)
220       glyph = new SimpleGlyph(sliced_data);
221     else
222       glyph = new CompositeGlyph(sliced_data);
223   }
224   return glyph.Detach();
225 }
226 
Padding()227 int32_t GlyphTable::Glyph::Padding() {
228   Initialize();
229   return SubTable::Padding();
230 }
231 
GlyphType()232 int32_t GlyphTable::Glyph::GlyphType() {
233   return glyph_type_;
234 }
235 
NumberOfContours()236 int32_t GlyphTable::Glyph::NumberOfContours() {
237   return number_of_contours_;
238 }
239 
XMin()240 int32_t GlyphTable::Glyph::XMin() {
241   return data_->ReadShort(Offset::kXMin);
242 }
243 
XMax()244 int32_t GlyphTable::Glyph::XMax() {
245   return data_->ReadShort(Offset::kXMax);
246 }
247 
YMin()248 int32_t GlyphTable::Glyph::YMin() {
249   return data_->ReadShort(Offset::kYMin);
250 }
251 
YMax()252 int32_t GlyphTable::Glyph::YMax() {
253   return data_->ReadShort(Offset::kYMax);
254 }
255 
Glyph(ReadableFontData * data,int32_t glyph_type)256 GlyphTable::Glyph::Glyph(ReadableFontData* data, int32_t glyph_type)
257     : SubTable(data),
258       glyph_type_(glyph_type) {
259   if (data_->Length() == 0) {
260     number_of_contours_ = 0;
261   } else {
262     // -1 if composite
263     number_of_contours_ = data_->ReadShort(Offset::kNumberOfContours);
264   }
265 }
266 
GlyphType(ReadableFontData * data,int32_t offset,int32_t length)267 int32_t GlyphTable::Glyph::GlyphType(ReadableFontData* data,
268                                      int32_t offset,
269                                      int32_t length) {
270   if (length == 0) {
271     return GlyphType::kSimple;
272   }
273   int32_t number_of_contours = data->ReadShort(offset);
274   if (number_of_contours >= 0) {
275     return GlyphType::kSimple;
276   }
277   return GlyphType::kComposite;
278 }
279 
280 /******************************************************************************
281  * GlyphTable::Glyph::Builder class
282  ******************************************************************************/
~Builder()283 GlyphTable::Glyph::Builder::~Builder() {
284 }
285 
Builder(WritableFontData * data)286 GlyphTable::Glyph::Builder::Builder(WritableFontData* data)
287     : SubTable::Builder(data) {
288 }
289 
Builder(ReadableFontData * data)290 GlyphTable::Glyph::Builder::Builder(ReadableFontData* data)
291     : SubTable::Builder(data) {
292 }
293 
294 CALLER_ATTACH GlyphTable::Glyph::Builder*
GetBuilder(GlyphTable::Builder * table_builder,ReadableFontData * data)295     GlyphTable::Glyph::Builder::GetBuilder(
296         GlyphTable::Builder* table_builder,
297         ReadableFontData* data) {
298   return GetBuilder(table_builder, data, 0, data->Length());
299 }
300 
301 CALLER_ATTACH GlyphTable::Glyph::Builder*
GetBuilder(GlyphTable::Builder * table_builder,ReadableFontData * data,int32_t offset,int32_t length)302     GlyphTable::Glyph::Builder::GetBuilder(
303         GlyphTable::Builder* table_builder,
304         ReadableFontData* data,
305         int32_t offset,
306         int32_t length) {
307   UNREFERENCED_PARAMETER(table_builder);
308   int32_t type = Glyph::GlyphType(data, offset, length);
309   GlyphBuilderPtr builder;
310   ReadableFontDataPtr sliced_data;
311   sliced_data.Attach(down_cast<ReadableFontData*>(data->Slice(offset, length)));
312   if (type == GlyphType::kSimple) {
313     builder = new SimpleGlyph::SimpleGlyphBuilder(sliced_data);
314   } else {
315     builder = new CompositeGlyph::CompositeGlyphBuilder(sliced_data);
316   }
317   return builder.Detach();
318 }
319 
SubDataSet()320 void GlyphTable::Glyph::Builder::SubDataSet() {
321   // NOP
322 }
323 
SubDataSizeToSerialize()324 int32_t GlyphTable::Glyph::Builder::SubDataSizeToSerialize() {
325   return InternalReadData()->Length();
326 }
327 
SubReadyToSerialize()328 bool GlyphTable::Glyph::Builder::SubReadyToSerialize() {
329   return true;
330 }
331 
SubSerialize(WritableFontData * new_data)332 int32_t GlyphTable::Glyph::Builder::SubSerialize(WritableFontData* new_data) {
333   return InternalReadData()->CopyTo(new_data);
334 }
335 
336 /******************************************************************************
337  * GlyphTable::SimpleGlyph
338  ******************************************************************************/
SimpleGlyph(ReadableFontData * data)339 GlyphTable::SimpleGlyph::SimpleGlyph(ReadableFontData* data)
340     : GlyphTable::Glyph(data, GlyphType::kSimple), initialized_(false) {
341 }
342 
~SimpleGlyph()343 GlyphTable::SimpleGlyph::~SimpleGlyph() {
344 }
345 
InstructionSize()346 int32_t GlyphTable::SimpleGlyph::InstructionSize() {
347   Initialize();
348   return instruction_size_;
349 }
350 
Instructions()351 CALLER_ATTACH ReadableFontData* GlyphTable::SimpleGlyph::Instructions() {
352   Initialize();
353   return down_cast<ReadableFontData*>(
354              data_->Slice(instructions_offset_, InstructionSize()));
355 }
356 
NumberOfPoints(int32_t contour)357 int32_t GlyphTable::SimpleGlyph::NumberOfPoints(int32_t contour) {
358   Initialize();
359   if (contour >= NumberOfContours()) {
360     return 0;
361   }
362   return contour_index_[contour + 1] - contour_index_[contour];
363 }
364 
XCoordinate(int32_t contour,int32_t point)365 int32_t GlyphTable::SimpleGlyph::XCoordinate(int32_t contour, int32_t point) {
366   Initialize();
367   return x_coordinates_[contour_index_[contour] + point];
368 }
369 
YCoordinate(int32_t contour,int32_t point)370 int32_t GlyphTable::SimpleGlyph::YCoordinate(int32_t contour, int32_t point) {
371   Initialize();
372   return y_coordinates_[contour_index_[contour] + point];
373 }
374 
OnCurve(int32_t contour,int32_t point)375 bool GlyphTable::SimpleGlyph::OnCurve(int32_t contour, int32_t point) {
376   Initialize();
377   return on_curve_[contour_index_[contour] + point];
378 }
379 
Initialize()380 void GlyphTable::SimpleGlyph::Initialize() {
381   AutoLock lock(initialization_lock_);
382   if (initialized_) {
383     return;
384   }
385 
386   if (ReadFontData()->Length() == 0) {
387     instruction_size_ = 0;
388     number_of_points_ = 0;
389     instructions_offset_ = 0;
390     flags_offset_ = 0;
391     x_coordinates_offset_ = 0;
392     y_coordinates_offset_ = 0;
393     return;
394   }
395 
396   instruction_size_ = data_->ReadUShort(Offset::kSimpleEndPtsOfCountours +
397       NumberOfContours() * DataSize::kUSHORT);
398   instructions_offset_ = Offset::kSimpleEndPtsOfCountours +
399       (NumberOfContours() + 1) * DataSize::kUSHORT;
400   flags_offset_ = instructions_offset_ + instruction_size_ * DataSize::kBYTE;
401   number_of_points_ = ContourEndPoint(NumberOfContours() - 1) + 1;
402   x_coordinates_.resize(number_of_points_);
403   y_coordinates_.resize(number_of_points_);
404   on_curve_.resize(number_of_points_);
405   ParseData(false);
406   x_coordinates_offset_ = flags_offset_ + flag_byte_count_ * DataSize::kBYTE;
407   y_coordinates_offset_ = x_coordinates_offset_ + x_byte_count_ *
408       DataSize::kBYTE;
409   contour_index_.resize(NumberOfContours() + 1);
410   contour_index_[0] = 0;
411   for (uint32_t contour = 0; contour < contour_index_.size() - 1; ++contour) {
412     contour_index_[contour + 1] = ContourEndPoint(contour) + 1;
413   }
414   ParseData(true);
415   int32_t non_padded_data_length =
416     5 * DataSize::kSHORT +
417     (NumberOfContours() * DataSize::kUSHORT) +
418     DataSize::kUSHORT +
419     (instruction_size_ * DataSize::kBYTE) +
420     (flag_byte_count_ * DataSize::kBYTE) +
421     (x_byte_count_ * DataSize::kBYTE) +
422     (y_byte_count_ * DataSize::kBYTE);
423   set_padding(DataLength() - non_padded_data_length);
424   initialized_ = true;
425 }
426 
ParseData(bool fill_arrays)427 void GlyphTable::SimpleGlyph::ParseData(bool fill_arrays) {
428   int32_t flag = 0;
429   int32_t flag_repeat = 0;
430   int32_t flag_index = 0;
431   int32_t x_byte_index = 0;
432   int32_t y_byte_index = 0;
433 
434   for (int32_t point_index = 0; point_index < number_of_points_;
435        ++point_index) {
436     // get the flag for the current point
437     if (flag_repeat == 0) {
438       flag = FlagAsInt(flag_index++);
439       if ((flag & kFLAG_REPEAT) == kFLAG_REPEAT) {
440         flag_repeat = FlagAsInt(flag_index++);
441       }
442     } else {
443       flag_repeat--;
444     }
445 
446     // on the curve?
447     if (fill_arrays) {
448       on_curve_[point_index] = ((flag & kFLAG_ONCURVE) == kFLAG_ONCURVE);
449     }
450     // get the x coordinate
451     if ((flag & kFLAG_XSHORT) == kFLAG_XSHORT) {
452       // single byte x coord value
453       if (fill_arrays) {
454         x_coordinates_[point_index] =
455             data_->ReadUByte(x_coordinates_offset_ + x_byte_index);
456         x_coordinates_[point_index] *=
457             ((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN) ? 1 : -1;
458       }
459       x_byte_index++;
460     } else {
461       // double byte coord value
462       if (!((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN)) {
463         if (fill_arrays) {
464           x_coordinates_[point_index] =
465             data_->ReadShort(x_coordinates_offset_ + x_byte_index);
466         }
467         x_byte_index += 2;
468       }
469     }
470     if (fill_arrays && point_index > 0) {
471       x_coordinates_[point_index] += x_coordinates_[point_index - 1];
472     }
473 
474     // get the y coordinate
475     if ((flag & kFLAG_YSHORT) == kFLAG_YSHORT) {
476       if (fill_arrays) {
477         y_coordinates_[point_index] =
478           data_->ReadUByte(y_coordinates_offset_ + y_byte_index);
479         y_coordinates_[point_index] *=
480           ((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN) ? 1 : -1;
481       }
482       y_byte_index++;
483     } else {
484       if (!((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN)) {
485         if (fill_arrays) {
486           y_coordinates_[point_index] =
487             data_->ReadShort(y_coordinates_offset_ + y_byte_index);
488         }
489         y_byte_index += 2;
490       }
491     }
492     if (fill_arrays && point_index > 0) {
493       y_coordinates_[point_index] += y_coordinates_[point_index - 1];
494     }
495   }
496   flag_byte_count_ = flag_index;
497   x_byte_count_ = x_byte_index;
498   y_byte_count_ = y_byte_index;
499 }
500 
FlagAsInt(int32_t index)501 int32_t GlyphTable::SimpleGlyph::FlagAsInt(int32_t index) {
502   return data_->ReadUByte(flags_offset_ + index * DataSize::kBYTE);
503 }
504 
ContourEndPoint(int32_t contour)505 int32_t GlyphTable::SimpleGlyph::ContourEndPoint(int32_t contour) {
506   return data_->ReadUShort(contour * DataSize::kUSHORT +
507                            Offset::kSimpleEndPtsOfCountours);
508 }
509 
510 /******************************************************************************
511  * GlyphTable::SimpleGlyph::Builder
512  ******************************************************************************/
~SimpleGlyphBuilder()513 GlyphTable::SimpleGlyph::SimpleGlyphBuilder::~SimpleGlyphBuilder() {
514 }
515 
SimpleGlyphBuilder(WritableFontData * data)516 GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder(
517     WritableFontData* data)
518     : Glyph::Builder(data) {
519 }
520 
SimpleGlyphBuilder(ReadableFontData * data)521 GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder(
522     ReadableFontData* data)
523     : Glyph::Builder(data) {
524 }
525 
526 CALLER_ATTACH FontDataTable*
SubBuildTable(ReadableFontData * data)527     GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SubBuildTable(
528         ReadableFontData* data) {
529   FontDataTablePtr table = new SimpleGlyph(data);
530   return table.Detach();
531 }
532 
533 /******************************************************************************
534  * GlyphTable::CompositeGlyph
535  ******************************************************************************/
CompositeGlyph(ReadableFontData * data)536 GlyphTable::CompositeGlyph::CompositeGlyph(ReadableFontData* data)
537     : GlyphTable::Glyph(data, GlyphType::kComposite),
538       instruction_size_(0),
539       instructions_offset_(0),
540       initialized_(false) {
541   Initialize();
542 }
543 
~CompositeGlyph()544 GlyphTable::CompositeGlyph::~CompositeGlyph() {
545 }
546 
Flags(int32_t contour)547 int32_t GlyphTable::CompositeGlyph::Flags(int32_t contour) {
548   return data_->ReadUShort(contour_index_[contour]);
549 }
550 
NumGlyphs()551 int32_t GlyphTable::CompositeGlyph::NumGlyphs() {
552   return contour_index_.size();
553 }
554 
GlyphIndex(int32_t contour)555 int32_t GlyphTable::CompositeGlyph::GlyphIndex(int32_t contour) {
556   return data_->ReadUShort(DataSize::kUSHORT + contour_index_[contour]);
557 }
558 
Argument1(int32_t contour)559 int32_t GlyphTable::CompositeGlyph::Argument1(int32_t contour) {
560   int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour];
561   int32_t contour_flags = Flags(contour);
562   if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) ==
563                        kFLAG_ARG_1_AND_2_ARE_WORDS) {
564     return data_->ReadUShort(index);
565   }
566   return data_->ReadByte(index);
567 }
568 
Argument2(int32_t contour)569 int32_t GlyphTable::CompositeGlyph::Argument2(int32_t contour) {
570   int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour];
571   int32_t contour_flags = Flags(contour);
572   if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) ==
573                        kFLAG_ARG_1_AND_2_ARE_WORDS) {
574     return data_->ReadUShort(index + DataSize::kUSHORT);
575   }
576   return data_->ReadByte(index + DataSize::kUSHORT);
577 }
578 
TransformationSize(int32_t contour)579 int32_t GlyphTable::CompositeGlyph::TransformationSize(int32_t contour) {
580   int32_t contour_flags = Flags(contour);
581   if ((contour_flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) {
582       return DataSize::kF2DOT14;
583     } else if ((contour_flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) ==
584                                 kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
585       return 2 * DataSize::kF2DOT14;
586     } else if ((contour_flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) ==
587                                 kFLAG_WE_HAVE_A_TWO_BY_TWO) {
588       return 4 * DataSize::kF2DOT14;
589     }
590     return 0;
591 }
592 
Transformation(int32_t contour,ByteVector * transformation)593 void GlyphTable::CompositeGlyph::Transformation(int32_t contour,
594                                                 ByteVector* transformation) {
595   int32_t contour_flags = Flags(contour);
596   int32_t index = contour_index_[contour] + 2 * DataSize::kUSHORT;
597   if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) ==
598                        kFLAG_ARG_1_AND_2_ARE_WORDS) {
599     index += 2 * DataSize::kSHORT;
600   } else {
601     index += 2 * DataSize::kBYTE;
602   }
603   int32_t tsize = TransformationSize(contour);
604   transformation->resize(tsize);
605   data_->ReadBytes(index, &((*transformation)[0]), 0, tsize);
606 }
607 
InstructionSize()608 int32_t GlyphTable::CompositeGlyph::InstructionSize() {
609   return instruction_size_;
610 }
611 
Instructions()612 CALLER_ATTACH ReadableFontData* GlyphTable::CompositeGlyph::Instructions() {
613   return down_cast<ReadableFontData*>(
614              data_->Slice(instructions_offset_, InstructionSize()));
615 }
616 
Initialize()617 void GlyphTable::CompositeGlyph::Initialize() {
618   AutoLock lock(initialization_lock_);
619   if (initialized_) {
620     return;
621   }
622 
623   int32_t index = 5 * DataSize::kUSHORT;
624   int32_t flags = kFLAG_MORE_COMPONENTS;
625 
626   while ((flags & kFLAG_MORE_COMPONENTS) == kFLAG_MORE_COMPONENTS) {
627     contour_index_.push_back(index);
628     flags = data_->ReadUShort(index);
629     index += 2 * DataSize::kUSHORT;  // flags and glyphIndex
630     if ((flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == kFLAG_ARG_1_AND_2_ARE_WORDS) {
631       index += 2 * DataSize::kSHORT;
632     } else {
633       index += 2 * DataSize::kBYTE;
634     }
635     if ((flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) {
636       index += DataSize::kF2DOT14;
637     } else if ((flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) ==
638                         kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
639       index += 2 * DataSize::kF2DOT14;
640     } else if ((flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) ==
641                         kFLAG_WE_HAVE_A_TWO_BY_TWO) {
642       index += 4 * DataSize::kF2DOT14;
643     }
644     int32_t non_padded_data_length = index;
645     if ((flags & kFLAG_WE_HAVE_INSTRUCTIONS) == kFLAG_WE_HAVE_INSTRUCTIONS) {
646       instruction_size_ = data_->ReadUShort(index);
647       index += DataSize::kUSHORT;
648       instructions_offset_ = index;
649       non_padded_data_length = index + (instruction_size_ * DataSize::kBYTE);
650     }
651     set_padding(DataLength() - non_padded_data_length);
652   }
653 
654   initialized_ = true;
655 }
656 
657 /******************************************************************************
658  * GlyphTable::CompositeGlyph::Builder
659  ******************************************************************************/
~CompositeGlyphBuilder()660 GlyphTable::CompositeGlyph::CompositeGlyphBuilder::~CompositeGlyphBuilder() {
661 }
662 
CompositeGlyphBuilder(WritableFontData * data)663 GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder(
664     WritableFontData* data)
665     : Glyph::Builder(data) {
666 }
667 
CompositeGlyphBuilder(ReadableFontData * data)668 GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder(
669     ReadableFontData* data)
670     : Glyph::Builder(data) {
671 }
672 
673 CALLER_ATTACH FontDataTable*
SubBuildTable(ReadableFontData * data)674     GlyphTable::CompositeGlyph::CompositeGlyphBuilder::SubBuildTable(
675         ReadableFontData* data) {
676   FontDataTablePtr table = new CompositeGlyph(data);
677   return table.Detach();
678 }
679 
680 }  // namespace sfntly
681