1<?php 2/** 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 $ 8 */ 9 10namespace FontLib\Glyph; 11 12/** 13 * Composite glyph outline 14 * 15 * @package php-font-lib 16 */ 17class 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; 28 29 /** 30 * @var OutlineComponent[] 31 */ 32 public $components = array(); 33 34 function getGlyphIDs() { 35 if (empty($this->components)) { 36 $this->parseData(); 37 } 38 39 $glyphIDs = array(); 40 foreach ($this->components as $_component) { 41 $glyphIDs[] = $_component->glyphIndex; 42 43 $_glyph = $this->table->data[$_component->glyphIndex]; 44 45 if ($_glyph !== $this) { 46 $glyphIDs = array_merge($glyphIDs, $_glyph->getGlyphIDs()); 47 } 48 } 49 50 return $glyphIDs; 51 } 52 53 /*function parse() { 54 //$this->parseData(); 55 }*/ 56 57 function parseData() { 58 parent::parseData(); 59 60 $font = $this->getFont(); 61 62 do { 63 $flags = $font->readUInt16(); 64 $glyphIndex = $font->readUInt16(); 65 66 $a = 1.0; 67 $b = 0.0; 68 $c = 0.0; 69 $d = 1.0; 70 $e = 0.0; 71 $f = 0.0; 72 73 $point_compound = null; 74 $point_component = null; 75 76 $instructions = null; 77 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(); 82 } 83 else { 84 $point_compound = $font->readUInt16(); 85 $point_component = $font->readUInt16(); 86 } 87 } 88 else { 89 if ($flags & self::ARGS_ARE_XY_VALUES) { 90 $e = $font->readInt8(); 91 $f = $font->readInt8(); 92 } 93 else { 94 $point_compound = $font->readUInt8(); 95 $point_component = $font->readUInt8(); 96 } 97 } 98 99 if ($flags & self::WE_HAVE_A_SCALE) { 100 $a = $d = $font->readInt16(); 101 } 102 elseif ($flags & self::WE_HAVE_AN_X_AND_Y_SCALE) { 103 $a = $font->readInt16(); 104 $d = $font->readInt16(); 105 } 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(); 111 } 112 113 //if ($flags & self::WE_HAVE_INSTRUCTIONS) { 114 // 115 //} 116 117 $component = new OutlineComponent(); 118 $component->flags = $flags; 119 $component->glyphIndex = $glyphIndex; 120 $component->a = $a; 121 $component->b = $b; 122 $component->c = $c; 123 $component->d = $d; 124 $component->e = $e; 125 $component->f = $f; 126 $component->point_compound = $point_compound; 127 $component->point_component = $point_component; 128 $component->instructions = $instructions; 129 130 $this->components[] = $component; 131 } while ($flags & self::MORE_COMPONENTS); 132 } 133 134 function encode() { 135 $font = $this->getFont(); 136 137 $gids = $font->getSubset(); 138 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); 144 145 foreach ($this->components as $_i => $_component) { 146 $flags = 0; 147 if ($_component->point_component === null && $_component->point_compound === null) { 148 $flags |= self::ARGS_ARE_XY_VALUES; 149 150 if (abs($_component->e) > 0x7F || abs($_component->f) > 0x7F) { 151 $flags |= self::ARG_1_AND_2_ARE_WORDS; 152 } 153 } 154 elseif ($_component->point_component > 0xFF || $_component->point_compound > 0xFF) { 155 $flags |= self::ARG_1_AND_2_ARE_WORDS; 156 } 157 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; 162 } 163 } 164 else { 165 $flags |= self::WE_HAVE_AN_X_AND_Y_SCALE; 166 } 167 } 168 else { 169 $flags |= self::WE_HAVE_A_TWO_BY_TWO; 170 } 171 172 if ($_i < count($this->components) - 1) { 173 $flags |= self::MORE_COMPONENTS; 174 } 175 176 $size += $font->writeUInt16($flags); 177 178 $new_gid = array_search($_component->glyphIndex, $gids); 179 $size += $font->writeUInt16($new_gid); 180 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); 185 } 186 else { 187 $size += $font->writeUInt16($_component->point_compound); 188 $size += $font->writeUInt16($_component->point_component); 189 } 190 } 191 else { 192 if ($flags & self::ARGS_ARE_XY_VALUES) { 193 $size += $font->writeInt8($_component->e); 194 $size += $font->writeInt8($_component->f); 195 } 196 else { 197 $size += $font->writeUInt8($_component->point_compound); 198 $size += $font->writeUInt8($_component->point_component); 199 } 200 } 201 202 if ($flags & self::WE_HAVE_A_SCALE) { 203 $size += $font->writeInt16($_component->a); 204 } 205 elseif ($flags & self::WE_HAVE_AN_X_AND_Y_SCALE) { 206 $size += $font->writeInt16($_component->a); 207 $size += $font->writeInt16($_component->d); 208 } 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); 214 } 215 } 216 217 return $size; 218 } 219 220 public function getSVGContours() { 221 $contours = array(); 222 223 /** @var \FontLib\Table\Type\glyf $glyph_data */ 224 $glyph_data = $this->getFont()->getTableObject("glyf"); 225 226 /** @var Outline[] $glyphs */ 227 $glyphs = $glyph_data->data; 228 229 foreach ($this->components as $component) { 230 $_glyph = $glyphs[$component->glyphIndex]; 231 232 if ($_glyph !== $this) { 233 $contours[] = array( 234 "contours" => $_glyph->getSVGContours(), 235 "transform" => $component->getMatrix(), 236 ); 237 } 238 } 239 240 return $contours; 241 } 242}