3 * @package php-font-lib
4 * @link https://github.com/PhenX/php-font-lib
5 * @author Fabien Ménager <fabien.menager@gmail.com>
6 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7 * @version $Id: Font_Table_glyf.php 46 2012-04-02 20:22:38Z fabien.menager $
10 namespace FontLib\Glyph;
13 * Composite glyph outline
15 * @package php-font-lib
17 class OutlineComposite extends Outline {
18 const ARG_1_AND_2_ARE_WORDS = 0x0001;
19 const ARGS_ARE_XY_VALUES = 0x0002;
20 const ROUND_XY_TO_GRID = 0x0004;
21 const WE_HAVE_A_SCALE = 0x0008;
22 const MORE_COMPONENTS = 0x0020;
23 const WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
24 const WE_HAVE_A_TWO_BY_TWO = 0x0080;
25 const WE_HAVE_INSTRUCTIONS = 0x0100;
26 const USE_MY_METRICS = 0x0200;
27 const OVERLAP_COMPOUND = 0x0400;
30 * @var OutlineComponent[]
32 public $components = array();
34 function getGlyphIDs() {
35 if (empty($this->components)) {
40 foreach ($this->components as $_component) {
41 $glyphIDs[] = $_component->glyphIndex;
43 $_glyph = $this->table->data[$_component->glyphIndex];
45 if ($_glyph !== $this) {
46 $glyphIDs = array_merge($glyphIDs, $_glyph->getGlyphIDs());
57 function parseData() {
60 $font = $this->getFont();
63 $flags = $font->readUInt16();
64 $glyphIndex = $font->readUInt16();
73 $point_compound = null;
74 $point_component = null;
78 if ($flags & self::ARG_1_AND_2_ARE_WORDS) {
79 if ($flags & self::ARGS_ARE_XY_VALUES) {
80 $e = $font->readInt16();
81 $f = $font->readInt16();
84 $point_compound = $font->readUInt16();
85 $point_component = $font->readUInt16();
89 if ($flags & self::ARGS_ARE_XY_VALUES) {
90 $e = $font->readInt8();
91 $f = $font->readInt8();
94 $point_compound = $font->readUInt8();
95 $point_component = $font->readUInt8();
99 if ($flags & self::WE_HAVE_A_SCALE) {
100 $a = $d = $font->readInt16();
102 elseif ($flags & self::WE_HAVE_AN_X_AND_Y_SCALE) {
103 $a = $font->readInt16();
104 $d = $font->readInt16();
106 elseif ($flags & self::WE_HAVE_A_TWO_BY_TWO) {
107 $a = $font->readInt16();
108 $b = $font->readInt16();
109 $c = $font->readInt16();
110 $d = $font->readInt16();
113 //if ($flags & self::WE_HAVE_INSTRUCTIONS) {
117 $component = new OutlineComponent();
118 $component->flags = $flags;
119 $component->glyphIndex = $glyphIndex;
126 $component->point_compound = $point_compound;
127 $component->point_component = $point_component;
128 $component->instructions = $instructions;
130 $this->components[] = $component;
131 } while ($flags & self::MORE_COMPONENTS);
135 $font = $this->getFont();
137 $gids = $font->getSubset();
139 $size = $font->writeInt16(-1);
140 $size += $font->writeFWord($this->xMin);
141 $size += $font->writeFWord($this->yMin);
142 $size += $font->writeFWord($this->xMax);
143 $size += $font->writeFWord($this->yMax);
145 foreach ($this->components as $_i => $_component) {
147 if ($_component->point_component === null && $_component->point_compound === null) {
148 $flags |= self::ARGS_ARE_XY_VALUES;
150 if (abs($_component->e) > 0x7F || abs($_component->f) > 0x7F) {
151 $flags |= self::ARG_1_AND_2_ARE_WORDS;
154 elseif ($_component->point_component > 0xFF || $_component->point_compound > 0xFF) {
155 $flags |= self::ARG_1_AND_2_ARE_WORDS;
158 if ($_component->b == 0 && $_component->c == 0) {
159 if ($_component->a == $_component->d) {
160 if ($_component->a != 1.0) {
161 $flags |= self::WE_HAVE_A_SCALE;
165 $flags |= self::WE_HAVE_AN_X_AND_Y_SCALE;
169 $flags |= self::WE_HAVE_A_TWO_BY_TWO;
172 if ($_i < count($this->components) - 1) {
173 $flags |= self::MORE_COMPONENTS;
176 $size += $font->writeUInt16($flags);
178 $new_gid = array_search($_component->glyphIndex, $gids);
179 $size += $font->writeUInt16($new_gid);
181 if ($flags & self::ARG_1_AND_2_ARE_WORDS) {
182 if ($flags & self::ARGS_ARE_XY_VALUES) {
183 $size += $font->writeInt16($_component->e);
184 $size += $font->writeInt16($_component->f);
187 $size += $font->writeUInt16($_component->point_compound);
188 $size += $font->writeUInt16($_component->point_component);
192 if ($flags & self::ARGS_ARE_XY_VALUES) {
193 $size += $font->writeInt8($_component->e);
194 $size += $font->writeInt8($_component->f);
197 $size += $font->writeUInt8($_component->point_compound);
198 $size += $font->writeUInt8($_component->point_component);
202 if ($flags & self::WE_HAVE_A_SCALE) {
203 $size += $font->writeInt16($_component->a);
205 elseif ($flags & self::WE_HAVE_AN_X_AND_Y_SCALE) {
206 $size += $font->writeInt16($_component->a);
207 $size += $font->writeInt16($_component->d);
209 elseif ($flags & self::WE_HAVE_A_TWO_BY_TWO) {
210 $size += $font->writeInt16($_component->a);
211 $size += $font->writeInt16($_component->b);
212 $size += $font->writeInt16($_component->c);
213 $size += $font->writeInt16($_component->d);
220 public function getSVGContours() {
223 /** @var \FontLib\Table\Type\glyf $glyph_data */
224 $glyph_data = $this->getFont()->getTableObject("glyf");
226 /** @var Outline[] $glyphs */
227 $glyphs = $glyph_data->data;
229 foreach ($this->components as $component) {
230 $_glyph = $glyphs[$component->glyphIndex];
232 if ($_glyph !== $this) {
234 "contours" => $_glyph->getSVGContours(),
235 "transform" => $component->getMatrix(),