Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1051 | chris | 1 | package com.gebauz.bauzoid.graphics; |
| 2 | |||
| 3 | import java.io.IOException; |
||
| 4 | import java.util.Vector; |
||
| 5 | |||
| 6 | import com.badlogic.gdx.Gdx; |
||
| 7 | import com.badlogic.gdx.files.FileHandle; |
||
| 8 | import com.gebauz.bauzoid.app.Consts; |
||
| 9 | import com.gebauz.bauzoid.file.File; |
||
| 10 | import com.gebauz.bauzoid.file.FileUtil; |
||
| 11 | import com.gebauz.bauzoid.graphics.sprite.Sprite; |
||
| 12 | import com.gebauz.bauzoid.graphics.sprite.SpriteRegion; |
||
| 13 | import com.gebauz.bauzoid.parser.ScanException; |
||
| 14 | import com.gebauz.bauzoid.parser.Tokenizer; |
||
| 15 | |||
| 16 | public class FontUtil |
||
| 17 | { |
||
| 18 | public static final String LOG_TAG = Consts.LOG_TAG + ":FontUtil"; |
||
| 19 | public static boolean verbose = true; |
||
| 20 | |||
| 21 | private static class CharacterRect |
||
| 22 | { |
||
| 23 | public float x; |
||
| 24 | public float y; |
||
| 25 | public float w; |
||
| 26 | public float h; |
||
| 27 | |||
| 28 | public CharacterRect(float _x, float _y, float _w, float _h) |
||
| 29 | { |
||
| 30 | x = _x; |
||
| 31 | y = _y; |
||
| 32 | w = _w; |
||
| 33 | h = _h; |
||
| 34 | } |
||
| 35 | } |
||
| 36 | |||
| 37 | private static class CharacterOffset |
||
| 38 | { |
||
| 39 | public float x; |
||
| 40 | public float y; |
||
| 41 | |||
| 42 | public CharacterOffset(float _x, float _y) |
||
| 43 | { |
||
| 44 | x = _x; |
||
| 45 | y = _y; |
||
| 46 | } |
||
| 47 | } |
||
| 48 | |||
| 49 | private static class KerningPair |
||
| 50 | { |
||
| 51 | public char first; |
||
| 52 | public char second; |
||
| 53 | public int value; |
||
| 54 | |||
| 55 | public KerningPair(char a, char b, int n) |
||
| 56 | { |
||
| 57 | first = a; |
||
| 58 | second = b; |
||
| 59 | value = n; |
||
| 60 | } |
||
| 61 | } |
||
| 62 | |||
| 63 | |||
| 64 | private FontUtil() {} |
||
| 65 | |||
| 66 | public static void log(String tag, String msg) |
||
| 67 | { |
||
| 68 | if (verbose) |
||
| 69 | Gdx.app.log(tag, msg); |
||
| 70 | } |
||
| 71 | |||
| 72 | public static Font createFontFromBinaryFile(Graphics graphics, FileHandle file) |
||
| 73 | { |
||
| 74 | Vector<Character> charList = new Vector<Character>(); |
||
| 75 | Vector<Float> widthList = new Vector<Float>(); |
||
| 76 | Vector<CharacterRect> rectList = new Vector<CharacterRect>(); |
||
| 77 | Vector<CharacterOffset> offsetList = new Vector<CharacterOffset>(); |
||
| 78 | Vector<KerningPair> kerningPairs = new Vector<KerningPair>(); |
||
| 79 | |||
| 80 | //Font font = new Font(graphics); |
||
| 81 | //Texture texture = null; |
||
| 82 | String textureFileFull = null; |
||
| 83 | |||
| 84 | float multiplier = 1.0f; |
||
| 85 | float ascent = 10.0f; |
||
| 86 | |||
| 87 | try |
||
| 88 | { |
||
| 89 | File f = new File(file.read()); |
||
| 90 | |||
| 91 | int version = f.readInt(); |
||
| 92 | if (version != 100) |
||
| 93 | { |
||
| 94 | Gdx.app.log(LOG_TAG, "Version mismatch: 100 != " + version); |
||
| 95 | return null; |
||
| 96 | } |
||
| 97 | |||
| 98 | String textureFile = f.readString(); |
||
| 99 | textureFileFull = FileUtil.extractPath(file.path()) + "/" + textureFile; |
||
| 100 | //texture = new Texture(Gdx.files.internal(filename)); |
||
| 101 | |||
| 102 | ascent = f.readFloat(); |
||
| 103 | multiplier = f.readFloat(); |
||
| 104 | |||
| 105 | // Read character list (char * num) |
||
| 106 | int numChars = f.readInt(); // number of characters |
||
| 107 | for (int i = 0; i < numChars; i++) |
||
| 108 | { |
||
| 109 | Character c = f.readChar(); |
||
| 110 | charList.add(c); |
||
| 111 | } |
||
| 112 | |||
| 113 | // Read width list (float * num) |
||
| 114 | int numWidths = f.readInt(); // number of widths |
||
| 115 | for (int i = 0; i < numWidths; i++) |
||
| 116 | { |
||
| 117 | Float width = f.readFloat(); |
||
| 118 | widthList.add(width); |
||
| 119 | } |
||
| 120 | |||
| 121 | // Read rect list (CharRect * num) |
||
| 122 | int numRects = f.readInt(); // number of rects |
||
| 123 | for (int i = 0; i < numRects; i++) |
||
| 124 | { |
||
| 125 | float x = f.readFloat(); |
||
| 126 | float y = f.readFloat(); |
||
| 127 | float w = f.readFloat(); |
||
| 128 | float h = f.readFloat(); |
||
| 129 | |||
| 130 | rectList.add(new CharacterRect(x, y, w, h)); |
||
| 131 | } |
||
| 132 | |||
| 133 | // Read offset list (CharOffset * num) |
||
| 134 | int numOffsets = f.readInt(); // number of offsets |
||
| 135 | for (int i = 0; i < numOffsets; i++) |
||
| 136 | { |
||
| 137 | float x = f.readFloat(); |
||
| 138 | float y = f.readFloat(); |
||
| 139 | |||
| 140 | offsetList.add(new CharacterOffset(x, y)); |
||
| 141 | } |
||
| 142 | |||
| 143 | // number of kerning pairs |
||
| 144 | int numKerning = f.readInt(); |
||
| 145 | |||
| 146 | // Read kerning pairs + values |
||
| 147 | for (int i = 0; i < numKerning; i++) |
||
| 148 | { |
||
| 149 | char a = f.readChar(); |
||
| 150 | char b = f.readChar(); |
||
| 151 | int v = f.readInt(); |
||
| 152 | |||
| 153 | kerningPairs.add(new KerningPair(a, b, v)); |
||
| 154 | } |
||
| 155 | |||
| 156 | f.close(); |
||
| 157 | } |
||
| 158 | catch (IOException e) |
||
| 159 | { |
||
| 160 | Gdx.app.log(LOG_TAG, "Could not read font!"); |
||
| 161 | } |
||
| 162 | |||
| 163 | return buildFont(graphics, charList, widthList, rectList, offsetList, textureFileFull, multiplier, ascent, kerningPairs); |
||
| 164 | } |
||
| 165 | |||
| 166 | public static Font createFontFromFile(Graphics graphics, FileHandle file) |
||
| 167 | { |
||
| 168 | String fileContents = file.readString(); |
||
| 169 | |||
| 170 | Vector<Character> charList = null; |
||
| 171 | Vector<Float> widthList = null; |
||
| 172 | Vector<CharacterRect> rectList = null; |
||
| 173 | Vector<CharacterOffset> offsetList = null; |
||
| 174 | Vector<KerningPair> kerningPairs = null; |
||
| 175 | Vector<Integer> kerningValues = null; |
||
| 176 | |||
| 177 | //Texture texture = null; |
||
| 178 | String textureFile = null; |
||
| 179 | |||
| 180 | float ascent = 10.0f; |
||
| 181 | float multiplier = 1.0f; |
||
| 182 | |||
| 183 | try |
||
| 184 | { |
||
| 185 | Tokenizer tokenizer = new Tokenizer(fileContents); |
||
| 186 | tokenizer.setStringDelimiter(new char[] {'\'', '"'} ); |
||
| 187 | |||
| 188 | while (!tokenizer.checkNoMoreTokens()) |
||
| 189 | { |
||
| 190 | String identifier = tokenizer.readIdentifier(); |
||
| 191 | |||
| 192 | if (identifier.equalsIgnoreCase("Define")) |
||
| 193 | { |
||
| 194 | // Define |
||
| 195 | String define = tokenizer.readIdentifier(); |
||
| 196 | |||
| 197 | if (define.equalsIgnoreCase("CharList")) |
||
| 198 | { |
||
| 199 | charList = parseCharList(tokenizer); |
||
| 200 | } |
||
| 201 | else if (define.equalsIgnoreCase("WidthList")) |
||
| 202 | { |
||
| 203 | widthList = parseWidthList(tokenizer); |
||
| 204 | } |
||
| 205 | else if (define.equalsIgnoreCase("RectList")) |
||
| 206 | { |
||
| 207 | rectList = parseRectList(tokenizer); |
||
| 208 | } |
||
| 209 | else if (define.equalsIgnoreCase("OffsetList")) |
||
| 210 | { |
||
| 211 | offsetList = parseOffsetList(tokenizer); |
||
| 212 | } |
||
| 213 | else if (define.equalsIgnoreCase("KerningPairs")) |
||
| 214 | { |
||
| 215 | kerningPairs = parseKerningPairs(tokenizer); |
||
| 216 | } |
||
| 217 | else if (define.equalsIgnoreCase("KerningValues")) |
||
| 218 | { |
||
| 219 | kerningValues = parseKerningValues(tokenizer); |
||
| 220 | } |
||
| 221 | tokenizer.readToken(";"); |
||
| 222 | } |
||
| 223 | else if (identifier.equalsIgnoreCase("CreateLayer")) |
||
| 224 | { |
||
| 225 | tokenizer.readIdentifier(); |
||
| 226 | tokenizer.readToken(";"); |
||
| 227 | } |
||
| 228 | else if (identifier.equalsIgnoreCase("LayerSetImage")) |
||
| 229 | { |
||
| 230 | tokenizer.readIdentifier(); |
||
| 231 | //String filename = FileUtil.extractPath(file.path()) + "/" + tokenizer.readString() + ".png"; |
||
| 232 | textureFile = FileUtil.extractPath(file.path()) + "/" + tokenizer.readString() + ".png"; |
||
| 233 | |||
| 234 | //texture = new Texture(Gdx.files.internal(filename)); |
||
| 235 | |||
| 236 | tokenizer.readToken(";"); |
||
| 237 | } |
||
| 238 | else if (identifier.equalsIgnoreCase("LayerRegionMultiplier")) |
||
| 239 | { |
||
| 240 | tokenizer.readIdentifier(); |
||
| 241 | |||
| 242 | multiplier = tokenizer.readNumber(); |
||
| 243 | tokenizer.readToken(";"); |
||
| 244 | } |
||
| 245 | else if (identifier.equalsIgnoreCase("LayerSetAscent")) |
||
| 246 | { |
||
| 247 | tokenizer.readIdentifier(); |
||
| 248 | ascent = tokenizer.readNumber(); |
||
| 249 | tokenizer.readToken(";"); |
||
| 250 | } |
||
| 251 | else if (identifier.equalsIgnoreCase("LayerSetCharWidths")) |
||
| 252 | { |
||
| 253 | tokenizer.readIdentifier(); |
||
| 254 | if (tokenizer.checkIdentifier()) |
||
| 255 | { |
||
| 256 | tokenizer.readIdentifier(); |
||
| 257 | tokenizer.readIdentifier(); |
||
| 258 | } |
||
| 259 | else if (tokenizer.checkToken("(")) |
||
| 260 | { |
||
| 261 | Vector<Character> charListExtra = parseCharList(tokenizer); |
||
| 262 | Vector<Float> widthListExtra = parseWidthList(tokenizer); |
||
| 263 | |||
| 264 | charList.addAll(charListExtra); |
||
| 265 | widthList.addAll(widthListExtra); |
||
| 266 | } |
||
| 267 | tokenizer.readToken(";"); |
||
| 268 | } |
||
| 269 | else if (identifier.equalsIgnoreCase("LayerSetImageMap")) |
||
| 270 | { |
||
| 271 | tokenizer.readIdentifier(); |
||
| 272 | tokenizer.readIdentifier(); |
||
| 273 | tokenizer.readIdentifier(); |
||
| 274 | tokenizer.readToken(";"); |
||
| 275 | } |
||
| 276 | else if (identifier.equalsIgnoreCase("LayerSetCharOffsets")) |
||
| 277 | { |
||
| 278 | tokenizer.readIdentifier(); |
||
| 279 | tokenizer.readIdentifier(); |
||
| 280 | tokenizer.readIdentifier(); |
||
| 281 | tokenizer.readToken(";"); |
||
| 282 | } |
||
| 283 | else if (identifier.equalsIgnoreCase("LayerSetAscentPadding")) |
||
| 284 | { |
||
| 285 | tokenizer.readIdentifier(); |
||
| 286 | tokenizer.readNumber(); |
||
| 287 | tokenizer.readToken(";"); |
||
| 288 | } |
||
| 289 | else if (identifier.equalsIgnoreCase("LayerSetLineSpacingOffset")) |
||
| 290 | { |
||
| 291 | tokenizer.readIdentifier(); |
||
| 292 | tokenizer.readNumber(); |
||
| 293 | tokenizer.readToken(";"); |
||
| 294 | } |
||
| 295 | else if (identifier.equalsIgnoreCase("LayerSetPointSize")) |
||
| 296 | { |
||
| 297 | tokenizer.readIdentifier(); |
||
| 298 | tokenizer.readNumber(); |
||
| 299 | tokenizer.readToken(";"); |
||
| 300 | } |
||
| 301 | else if (identifier.equalsIgnoreCase("SetDefaultPointSize")) |
||
| 302 | { |
||
| 303 | tokenizer.readNumber(); |
||
| 304 | tokenizer.readToken(";"); |
||
| 305 | } |
||
| 306 | else if (identifier.equalsIgnoreCase("LayerSetKerningPairs")) |
||
| 307 | { |
||
| 308 | tokenizer.readIdentifier(); |
||
| 309 | tokenizer.readIdentifier(); |
||
| 310 | tokenizer.readIdentifier(); |
||
| 311 | tokenizer.readToken(";"); |
||
| 312 | |||
| 313 | // set kerning values |
||
| 314 | for (int i = 0; i < kerningPairs.size(); i++) |
||
| 315 | { |
||
| 316 | kerningPairs.elementAt(i).value = kerningValues.elementAt(i); |
||
| 317 | } |
||
| 318 | } |
||
| 319 | else if (identifier.equalsIgnoreCase("ConvertGreyScaleToAlpha")) |
||
| 320 | { |
||
| 321 | tokenizer.readNumber(); |
||
| 322 | tokenizer.readToken(";"); |
||
| 323 | } |
||
| 324 | } |
||
| 325 | |||
| 326 | } |
||
| 327 | catch (ScanException ex) |
||
| 328 | { |
||
| 329 | ex.log(LOG_TAG); |
||
| 330 | } |
||
| 331 | |||
| 332 | return buildFont(graphics, charList, widthList, rectList, offsetList, textureFile, multiplier, ascent, kerningPairs); |
||
| 333 | } |
||
| 334 | |||
| 335 | private static Font buildFont(Graphics graphics, Vector<Character> charList, Vector<Float> widthList, Vector<CharacterRect> rectList, Vector<CharacterOffset> offsetList, |
||
| 336 | String textureFile, float multiplier, float ascent, Vector<KerningPair> kerningPairs) |
||
| 337 | { |
||
| 338 | // Build font |
||
| 339 | if (textureFile == null) |
||
| 340 | { |
||
| 341 | Gdx.app.log(LOG_TAG, "No font file specified!"); |
||
| 342 | return null; |
||
| 343 | } |
||
| 344 | |||
| 345 | Font font = new Font(graphics); |
||
| 346 | |||
| 347 | Font.CharacterInfo[] characters = new Font.CharacterInfo[charList.size()]; |
||
| 348 | SpriteRegion[] regions = new SpriteRegion[rectList.size()]; |
||
| 349 | |||
| 350 | Sprite sprite = new Sprite(graphics, textureFile); |
||
| 351 | sprite.init(); |
||
| 352 | |||
| 353 | for (int i = 0; i < characters.length; i++) |
||
| 354 | { |
||
| 355 | characters[i] = new Font.CharacterInfo(charList.elementAt(i)); |
||
| 356 | |||
| 357 | characters[i].width = widthList.elementAt(i); |
||
| 358 | |||
| 359 | if (i < offsetList.size()) |
||
| 360 | { |
||
| 361 | characters[i].offsetX = offsetList.elementAt(i).x; |
||
| 362 | characters[i].offsetY = offsetList.elementAt(i).y; |
||
| 363 | } |
||
| 364 | |||
| 365 | if (i < rectList.size()) |
||
| 366 | { |
||
| 367 | CharacterRect rect = rectList.elementAt(i); |
||
| 368 | |||
| 369 | /*characters[i].texX = rectList.elementAt(i).x; |
||
| 370 | characters[i].texY = rectList.elementAt(i).y; |
||
| 371 | characters[i].texW = rectList.elementAt(i).w; |
||
| 372 | characters[i].texH = rectList.elementAt(i).h;*/ |
||
| 373 | regions[i] = new SpriteRegion(sprite, i, rect.x / multiplier, rect.y / multiplier, rect.w / multiplier, rect.h / multiplier, true); |
||
| 374 | } |
||
| 375 | } |
||
| 376 | sprite.setRegions(regions); |
||
| 377 | |||
| 378 | //AtlasSprite sprite = new AtlasSprite(graphics, texture, regions); |
||
| 379 | |||
| 380 | for (int i = 0; i < regions.length; i++) |
||
| 381 | { |
||
| 382 | characters[i].setSpriteInstance(sprite.createSpriteInstance(i)); |
||
| 383 | } |
||
| 384 | |||
| 385 | font.setCharacters(characters); |
||
| 386 | font.setSprite(sprite); |
||
| 387 | font.setAscent(ascent); |
||
| 388 | font.setGlobalMultiplier(multiplier); |
||
| 389 | |||
| 390 | for (int i = 0; i < kerningPairs.size(); i++) |
||
| 391 | { |
||
| 392 | KerningPair pair = kerningPairs.elementAt(i); |
||
| 393 | font.setKerning(pair.first, pair.second, pair.value); |
||
| 394 | } |
||
| 395 | |||
| 396 | return font; |
||
| 397 | } |
||
| 398 | |||
| 399 | private static Vector<Character> parseCharList(Tokenizer t) throws ScanException |
||
| 400 | { |
||
| 401 | Vector<Character> charList = new Vector<Character>(); |
||
| 402 | |||
| 403 | t.readToken("("); |
||
| 404 | |||
| 405 | while (!t.checkToken(")")) |
||
| 406 | { |
||
| 407 | String character = t.readString(); |
||
| 408 | |||
| 409 | if (character.length() > 1) |
||
| 410 | throw new ScanException("Character can only have length 1!", t.getSurroundings()); |
||
| 411 | |||
| 412 | charList.add(character.charAt(0)); |
||
| 413 | |||
| 414 | if (t.checkToken(")")) |
||
| 415 | break; |
||
| 416 | |||
| 417 | t.readToken(","); |
||
| 418 | } |
||
| 419 | |||
| 420 | t.readToken(")"); |
||
| 421 | |||
| 422 | return charList; |
||
| 423 | } |
||
| 424 | |||
| 425 | private static Vector<Float> parseWidthList(Tokenizer t) throws ScanException |
||
| 426 | { |
||
| 427 | Vector<Float> widthList = new Vector<Float>(); |
||
| 428 | |||
| 429 | t.readToken("("); |
||
| 430 | |||
| 431 | while (!t.checkToken(")")) |
||
| 432 | { |
||
| 433 | float width = t.readNumber(); |
||
| 434 | |||
| 435 | widthList.add(width); |
||
| 436 | |||
| 437 | if (t.checkToken(")")) |
||
| 438 | break; |
||
| 439 | |||
| 440 | //Gdx.app.log(LOG_TAG, "[" + width + "]"); |
||
| 441 | |||
| 442 | t.readToken(","); |
||
| 443 | } |
||
| 444 | |||
| 445 | t.readToken(")"); |
||
| 446 | |||
| 447 | return widthList; |
||
| 448 | } |
||
| 449 | |||
| 450 | private static Vector<CharacterRect> parseRectList(Tokenizer t) throws ScanException |
||
| 451 | { |
||
| 452 | Vector<CharacterRect> rectList = new Vector<CharacterRect>(); |
||
| 453 | |||
| 454 | t.readToken("("); |
||
| 455 | |||
| 456 | while (t.checkToken("(")) |
||
| 457 | { |
||
| 458 | t.readToken("("); |
||
| 459 | |||
| 460 | float x = t.readNumber(); |
||
| 461 | t.readToken(","); |
||
| 462 | float y = t.readNumber(); |
||
| 463 | t.readToken(","); |
||
| 464 | float w = t.readNumber(); |
||
| 465 | t.readToken(","); |
||
| 466 | float h = t.readNumber(); |
||
| 467 | |||
| 468 | rectList.add(new CharacterRect(x, y, w, h)); |
||
| 469 | |||
| 470 | t.readToken(")"); |
||
| 471 | |||
| 472 | if (!t.checkToken(",")) |
||
| 473 | break; |
||
| 474 | |||
| 475 | t.readToken(","); |
||
| 476 | } |
||
| 477 | |||
| 478 | if (!t.checkToken(")")) |
||
| 479 | throw new ScanException("Syntax error in RectList!", t.getSurroundings()); |
||
| 480 | |||
| 481 | t.readToken(")"); |
||
| 482 | |||
| 483 | return rectList; |
||
| 484 | } |
||
| 485 | |||
| 486 | private static Vector<CharacterOffset> parseOffsetList(Tokenizer t) throws ScanException |
||
| 487 | { |
||
| 488 | Vector<CharacterOffset> offsetList = new Vector<CharacterOffset>(); |
||
| 489 | |||
| 490 | t.readToken("("); |
||
| 491 | |||
| 492 | while (t.checkToken("(")) |
||
| 493 | { |
||
| 494 | t.readToken("("); |
||
| 495 | |||
| 496 | float x = t.readNumber(); |
||
| 497 | t.readToken(","); |
||
| 498 | float y = t.readNumber(); |
||
| 499 | |||
| 500 | offsetList.add(new CharacterOffset(x, y)); |
||
| 501 | |||
| 502 | t.readToken(")"); |
||
| 503 | |||
| 504 | if (!t.checkToken(",")) |
||
| 505 | break; |
||
| 506 | |||
| 507 | t.readToken(","); |
||
| 508 | } |
||
| 509 | |||
| 510 | if (!t.checkToken(")")) |
||
| 511 | throw new ScanException("Syntax error in OffsetList!", t.getSurroundings()); |
||
| 512 | |||
| 513 | t.readToken(")"); |
||
| 514 | |||
| 515 | return offsetList; |
||
| 516 | } |
||
| 517 | |||
| 518 | private static Vector<KerningPair> parseKerningPairs(Tokenizer t) throws ScanException |
||
| 519 | { |
||
| 520 | Vector<KerningPair> kerningPairs = new Vector<KerningPair>(); |
||
| 521 | |||
| 522 | t.readToken("("); |
||
| 523 | |||
| 524 | while (!t.checkToken(")")) |
||
| 525 | { |
||
| 526 | String pair = t.readString(); |
||
| 527 | |||
| 528 | kerningPairs.add(new KerningPair(pair.charAt(0), pair.charAt(1), 0)); |
||
| 529 | |||
| 530 | if (t.checkToken(")")) |
||
| 531 | break; |
||
| 532 | |||
| 533 | //Gdx.app.log(LOG_TAG, "[" + width + "]"); |
||
| 534 | |||
| 535 | t.readToken(","); |
||
| 536 | } |
||
| 537 | |||
| 538 | t.readToken(")"); |
||
| 539 | |||
| 540 | return kerningPairs; |
||
| 541 | } |
||
| 542 | |||
| 543 | private static Vector<Integer> parseKerningValues(Tokenizer t) throws ScanException |
||
| 544 | { |
||
| 545 | Vector<Integer> kerningValues = new Vector<Integer>(); |
||
| 546 | |||
| 547 | t.readToken("("); |
||
| 548 | |||
| 549 | while (!t.checkToken(")")) |
||
| 550 | { |
||
| 551 | int value = (int)t.readNumber(); |
||
| 552 | |||
| 553 | kerningValues.add(value); |
||
| 554 | |||
| 555 | if (t.checkToken(")")) |
||
| 556 | break; |
||
| 557 | |||
| 558 | //Gdx.app.log(LOG_TAG, "[" + width + "]"); |
||
| 559 | |||
| 560 | t.readToken(","); |
||
| 561 | } |
||
| 562 | |||
| 563 | t.readToken(")"); |
||
| 564 | |||
| 565 | return kerningValues; |
||
| 566 | } |
||
| 567 | } |