1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 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 package com.badlogic.gdx.graphics.g2d.freetype; 18 19 import java.nio.ByteBuffer; 20 import java.nio.IntBuffer; 21 22 import com.badlogic.gdx.files.FileHandle; 23 import com.badlogic.gdx.graphics.Color; 24 import com.badlogic.gdx.graphics.Pixmap; 25 import com.badlogic.gdx.graphics.Pixmap.Blending; 26 import com.badlogic.gdx.graphics.Pixmap.Format; 27 import com.badlogic.gdx.utils.BufferUtils; 28 import com.badlogic.gdx.utils.Disposable; 29 import com.badlogic.gdx.utils.GdxRuntimeException; 30 import com.badlogic.gdx.utils.LongMap; 31 import com.badlogic.gdx.utils.SharedLibraryLoader; 32 33 public class FreeType { 34 // @off 35 /*JNI 36 #include <ft2build.h> 37 #include FT_FREETYPE_H 38 #include FT_STROKER_H 39 */ 40 41 private static class Pointer { 42 long address; 43 Pointer(long address)44 Pointer(long address) { 45 this.address = address; 46 } 47 } 48 49 public static class Library extends Pointer implements Disposable { 50 LongMap<ByteBuffer> fontData = new LongMap<ByteBuffer>(); 51 Library(long address)52 Library (long address) { 53 super(address); 54 } 55 56 @Override dispose()57 public void dispose () { 58 doneFreeType(address); 59 for(ByteBuffer buffer: fontData.values()) { 60 BufferUtils.disposeUnsafeByteBuffer(buffer); 61 } 62 } 63 doneFreeType(long library)64 private static native void doneFreeType(long library); /* 65 FT_Done_FreeType((FT_Library)library); 66 */ 67 newFace(FileHandle font, int faceIndex)68 public Face newFace(FileHandle font, int faceIndex) { 69 byte[] data = font.readBytes(); 70 return newMemoryFace(data, data.length, faceIndex); 71 } 72 newMemoryFace(byte[] data, int dataSize, int faceIndex)73 public Face newMemoryFace(byte[] data, int dataSize, int faceIndex) { 74 ByteBuffer buffer = BufferUtils.newUnsafeByteBuffer(data.length); 75 BufferUtils.copy(data, 0, buffer, data.length); 76 return newMemoryFace(buffer, faceIndex); 77 } 78 newMemoryFace(ByteBuffer buffer, int faceIndex)79 public Face newMemoryFace(ByteBuffer buffer, int faceIndex) { 80 long face = newMemoryFace(address, buffer, buffer.remaining(), faceIndex); 81 if(face == 0) { 82 BufferUtils.disposeUnsafeByteBuffer(buffer); 83 throw new GdxRuntimeException("Couldn't load font"); 84 } 85 else { 86 fontData.put(face, buffer); 87 return new Face(face, this); 88 } 89 } 90 newMemoryFace(long library, ByteBuffer data, int dataSize, int faceIndex)91 private static native long newMemoryFace(long library, ByteBuffer data, int dataSize, int faceIndex); /* 92 FT_Face face = 0; 93 FT_Error error = FT_New_Memory_Face((FT_Library)library, (const FT_Byte*)data, dataSize, faceIndex, &face); 94 if(error) return 0; 95 else return (jlong)face; 96 */ 97 createStroker()98 public Stroker createStroker() { 99 long stroker = strokerNew(address); 100 if(stroker == 0) throw new GdxRuntimeException("Couldn't create FreeType stroker"); 101 return new Stroker(stroker); 102 } 103 strokerNew(long library)104 private static native long strokerNew(long library); /* 105 FT_Stroker stroker; 106 FT_Error error = FT_Stroker_New((FT_Library)library, &stroker); 107 if(error) return 0; 108 else return (jlong)stroker; 109 */ 110 } 111 112 public static class Face extends Pointer implements Disposable { 113 Library library; 114 Face(long address, Library library)115 public Face (long address, Library library) { 116 super(address); 117 this.library = library; 118 } 119 120 @Override dispose()121 public void dispose() { 122 doneFace(address); 123 ByteBuffer buffer = library.fontData.get(address); 124 if(buffer != null) { 125 library.fontData.remove(address); 126 BufferUtils.disposeUnsafeByteBuffer(buffer); 127 } 128 } 129 doneFace(long face)130 private static native void doneFace(long face); /* 131 FT_Done_Face((FT_Face)face); 132 */ 133 getFaceFlags()134 public int getFaceFlags() { 135 return getFaceFlags(address); 136 } 137 getFaceFlags(long face)138 private static native int getFaceFlags(long face); /* 139 return ((FT_Face)face)->face_flags; 140 */ 141 getStyleFlags()142 public int getStyleFlags() { 143 return getStyleFlags(address); 144 } 145 getStyleFlags(long face)146 private static native int getStyleFlags(long face); /* 147 return ((FT_Face)face)->style_flags; 148 */ 149 getNumGlyphs()150 public int getNumGlyphs() { 151 return getNumGlyphs(address); 152 } 153 getNumGlyphs(long face)154 private static native int getNumGlyphs(long face); /* 155 return ((FT_Face)face)->num_glyphs; 156 */ 157 getAscender()158 public int getAscender() { 159 return getAscender(address); 160 } 161 getAscender(long face)162 private static native int getAscender(long face); /* 163 return ((FT_Face)face)->ascender; 164 */ 165 getDescender()166 public int getDescender() { 167 return getDescender(address); 168 } 169 getDescender(long face)170 private static native int getDescender(long face); /* 171 return ((FT_Face)face)->descender; 172 */ 173 getHeight()174 public int getHeight() { 175 return getHeight(address); 176 } 177 getHeight(long face)178 private static native int getHeight(long face); /* 179 return ((FT_Face)face)->height; 180 */ 181 getMaxAdvanceWidth()182 public int getMaxAdvanceWidth() { 183 return getMaxAdvanceWidth(address); 184 } 185 getMaxAdvanceWidth(long face)186 private static native int getMaxAdvanceWidth(long face); /* 187 return ((FT_Face)face)->max_advance_width; 188 */ 189 getMaxAdvanceHeight()190 public int getMaxAdvanceHeight() { 191 return getMaxAdvanceHeight(address); 192 } 193 getMaxAdvanceHeight(long face)194 private static native int getMaxAdvanceHeight(long face); /* 195 return ((FT_Face)face)->max_advance_height; 196 */ 197 getUnderlinePosition()198 public int getUnderlinePosition() { 199 return getUnderlinePosition(address); 200 } 201 getUnderlinePosition(long face)202 private static native int getUnderlinePosition(long face); /* 203 return ((FT_Face)face)->underline_position; 204 */ 205 getUnderlineThickness()206 public int getUnderlineThickness() { 207 return getUnderlineThickness(address); 208 } 209 getUnderlineThickness(long face)210 private static native int getUnderlineThickness(long face); /* 211 return ((FT_Face)face)->underline_thickness; 212 */ 213 selectSize(int strikeIndex)214 public boolean selectSize(int strikeIndex) { 215 return selectSize(address, strikeIndex); 216 } 217 selectSize(long face, int strike_index)218 private static native boolean selectSize(long face, int strike_index); /* 219 return !FT_Select_Size((FT_Face)face, strike_index); 220 */ 221 setCharSize(int charWidth, int charHeight, int horzResolution, int vertResolution)222 public boolean setCharSize(int charWidth, int charHeight, int horzResolution, int vertResolution) { 223 return setCharSize(address, charWidth, charHeight, horzResolution, vertResolution); 224 } 225 setCharSize(long face, int charWidth, int charHeight, int horzResolution, int vertResolution)226 private static native boolean setCharSize(long face, int charWidth, int charHeight, int horzResolution, int vertResolution); /* 227 return !FT_Set_Char_Size((FT_Face)face, charWidth, charHeight, horzResolution, vertResolution); 228 */ 229 setPixelSizes(int pixelWidth, int pixelHeight)230 public boolean setPixelSizes(int pixelWidth, int pixelHeight) { 231 return setPixelSizes(address, pixelWidth, pixelHeight); 232 } 233 setPixelSizes(long face, int pixelWidth, int pixelHeight)234 private static native boolean setPixelSizes(long face, int pixelWidth, int pixelHeight); /* 235 return !FT_Set_Pixel_Sizes((FT_Face)face, pixelWidth, pixelHeight); 236 */ 237 loadGlyph(int glyphIndex, int loadFlags)238 public boolean loadGlyph(int glyphIndex, int loadFlags) { 239 return loadGlyph(address, glyphIndex, loadFlags); 240 } 241 loadGlyph(long face, int glyphIndex, int loadFlags)242 private static native boolean loadGlyph(long face, int glyphIndex, int loadFlags); /* 243 return !FT_Load_Glyph((FT_Face)face, glyphIndex, loadFlags); 244 */ 245 loadChar(int charCode, int loadFlags)246 public boolean loadChar(int charCode, int loadFlags) { 247 return loadChar(address, charCode, loadFlags); 248 } 249 loadChar(long face, int charCode, int loadFlags)250 private static native boolean loadChar(long face, int charCode, int loadFlags); /* 251 return !FT_Load_Char((FT_Face)face, charCode, loadFlags); 252 */ 253 getGlyph()254 public GlyphSlot getGlyph() { 255 return new GlyphSlot(getGlyph(address)); 256 } 257 getGlyph(long face)258 private static native long getGlyph(long face); /* 259 return (jlong)((FT_Face)face)->glyph; 260 */ 261 getSize()262 public Size getSize() { 263 return new Size(getSize(address)); 264 } 265 getSize(long face)266 private static native long getSize(long face); /* 267 return (jlong)((FT_Face)face)->size; 268 */ 269 hasKerning()270 public boolean hasKerning() { 271 return hasKerning(address); 272 } 273 hasKerning(long face)274 private static native boolean hasKerning(long face); /* 275 return FT_HAS_KERNING(((FT_Face)face)); 276 */ 277 getKerning(int leftGlyph, int rightGlyph, int kernMode)278 public int getKerning(int leftGlyph, int rightGlyph, int kernMode) { 279 return getKerning(address, leftGlyph, rightGlyph, kernMode); 280 } 281 getKerning(long face, int leftGlyph, int rightGlyph, int kernMode)282 private static native int getKerning(long face, int leftGlyph, int rightGlyph, int kernMode); /* 283 FT_Vector kerning; 284 FT_Error error = FT_Get_Kerning((FT_Face)face, leftGlyph, rightGlyph, kernMode, &kerning); 285 if(error) return 0; 286 return kerning.x; 287 */ 288 getCharIndex(int charCode)289 public int getCharIndex(int charCode) { 290 return getCharIndex(address, charCode); 291 } 292 getCharIndex(long face, int charCode)293 private static native int getCharIndex(long face, int charCode); /* 294 return FT_Get_Char_Index((FT_Face)face, charCode); 295 */ 296 297 } 298 299 public static class Size extends Pointer { Size(long address)300 Size (long address) { 301 super(address); 302 } 303 getMetrics()304 public SizeMetrics getMetrics() { 305 return new SizeMetrics(getMetrics(address)); 306 } 307 getMetrics(long address)308 private static native long getMetrics(long address); /* 309 return (jlong)&((FT_Size)address)->metrics; 310 */ 311 } 312 313 public static class SizeMetrics extends Pointer { SizeMetrics(long address)314 SizeMetrics (long address) { 315 super(address); 316 } 317 getXppem()318 public int getXppem() { 319 return getXppem(address); 320 } 321 getXppem(long metrics)322 private static native int getXppem(long metrics); /* 323 return ((FT_Size_Metrics*)metrics)->x_ppem; 324 */ 325 getYppem()326 public int getYppem() { 327 return getYppem(address); 328 } 329 getYppem(long metrics)330 private static native int getYppem(long metrics); /* 331 return ((FT_Size_Metrics*)metrics)->y_ppem; 332 */ 333 getXScale()334 public int getXScale() { 335 return getXscale(address); 336 } 337 getXscale(long metrics)338 private static native int getXscale(long metrics); /* 339 return ((FT_Size_Metrics*)metrics)->x_scale; 340 */ 341 getYscale()342 public int getYscale() { 343 return getYscale(address); 344 } 345 getYscale(long metrics)346 private static native int getYscale(long metrics); /* 347 return ((FT_Size_Metrics*)metrics)->x_scale; 348 */ 349 getAscender()350 public int getAscender() { 351 return getAscender(address); 352 } 353 getAscender(long metrics)354 private static native int getAscender(long metrics); /* 355 return ((FT_Size_Metrics*)metrics)->ascender; 356 */ 357 getDescender()358 public int getDescender() { 359 return getDescender(address); 360 } 361 getDescender(long metrics)362 private static native int getDescender(long metrics); /* 363 return ((FT_Size_Metrics*)metrics)->descender; 364 */ 365 getHeight()366 public int getHeight() { 367 return getHeight(address); 368 } 369 getHeight(long metrics)370 private static native int getHeight(long metrics); /* 371 return ((FT_Size_Metrics*)metrics)->height; 372 */ 373 getMaxAdvance()374 public int getMaxAdvance() { 375 return getMaxAdvance(address); 376 } 377 getMaxAdvance(long metrics)378 private static native int getMaxAdvance(long metrics); /* 379 return ((FT_Size_Metrics*)metrics)->max_advance; 380 */ 381 } 382 383 public static class GlyphSlot extends Pointer { GlyphSlot(long address)384 GlyphSlot (long address) { 385 super(address); 386 } 387 getMetrics()388 public GlyphMetrics getMetrics() { 389 return new GlyphMetrics(getMetrics(address)); 390 } 391 getMetrics(long slot)392 private static native long getMetrics(long slot); /* 393 return (jlong)&((FT_GlyphSlot)slot)->metrics; 394 */ 395 getLinearHoriAdvance()396 public int getLinearHoriAdvance() { 397 return getLinearHoriAdvance(address); 398 } 399 getLinearHoriAdvance(long slot)400 private static native int getLinearHoriAdvance(long slot); /* 401 return ((FT_GlyphSlot)slot)->linearHoriAdvance; 402 */ 403 getLinearVertAdvance()404 public int getLinearVertAdvance() { 405 return getLinearVertAdvance(address); 406 } 407 getLinearVertAdvance(long slot)408 private static native int getLinearVertAdvance(long slot); /* 409 return ((FT_GlyphSlot)slot)->linearVertAdvance; 410 */ 411 getAdvanceX()412 public int getAdvanceX() { 413 return getAdvanceX(address); 414 } 415 getAdvanceX(long slot)416 private static native int getAdvanceX(long slot); /* 417 return ((FT_GlyphSlot)slot)->advance.x; 418 */ 419 getAdvanceY()420 public int getAdvanceY() { 421 return getAdvanceY(address); 422 } 423 getAdvanceY(long slot)424 private static native int getAdvanceY(long slot); /* 425 return ((FT_GlyphSlot)slot)->advance.y; 426 */ 427 getFormat()428 public int getFormat() { 429 return getFormat(address); 430 } 431 getFormat(long slot)432 private static native int getFormat(long slot); /* 433 return ((FT_GlyphSlot)slot)->format; 434 */ 435 getBitmap()436 public Bitmap getBitmap() { 437 return new Bitmap(getBitmap(address)); 438 } 439 getBitmap(long slot)440 private static native long getBitmap(long slot); /* 441 FT_GlyphSlot glyph = ((FT_GlyphSlot)slot); 442 return (jlong)&(glyph->bitmap); 443 */ 444 getBitmapLeft()445 public int getBitmapLeft() { 446 return getBitmapLeft(address); 447 } 448 getBitmapLeft(long slot)449 private static native int getBitmapLeft(long slot); /* 450 return ((FT_GlyphSlot)slot)->bitmap_left; 451 */ 452 getBitmapTop()453 public int getBitmapTop() { 454 return getBitmapTop(address); 455 } 456 getBitmapTop(long slot)457 private static native int getBitmapTop(long slot); /* 458 return ((FT_GlyphSlot)slot)->bitmap_top; 459 */ 460 renderGlyph(int renderMode)461 public boolean renderGlyph(int renderMode) { 462 return renderGlyph(address, renderMode); 463 } 464 renderGlyph(long slot, int renderMode)465 private static native boolean renderGlyph(long slot, int renderMode); /* 466 return !FT_Render_Glyph((FT_GlyphSlot)slot, (FT_Render_Mode)renderMode); 467 */ 468 getGlyph()469 public Glyph getGlyph() { 470 long glyph = getGlyph(address); 471 if(glyph == 0) throw new GdxRuntimeException("Couldn't get glyph"); 472 return new Glyph(glyph); 473 } 474 getGlyph(long glyphSlot)475 private static native long getGlyph(long glyphSlot); /* 476 FT_Glyph glyph; 477 FT_Error error = FT_Get_Glyph((FT_GlyphSlot)glyphSlot, &glyph); 478 if(error) return 0; 479 else return (jlong)glyph; 480 */ 481 } 482 483 public static class Glyph extends Pointer implements Disposable { 484 private boolean rendered; 485 Glyph(long address)486 Glyph (long address) { 487 super(address); 488 } 489 490 @Override dispose()491 public void dispose () { 492 done(address); 493 } 494 done(long glyph)495 private static native void done(long glyph); /* 496 FT_Done_Glyph((FT_Glyph)glyph); 497 */ 498 strokeBorder(Stroker stroker, boolean inside)499 public void strokeBorder(Stroker stroker, boolean inside) { 500 address = strokeBorder(address, stroker.address, inside); 501 } 502 strokeBorder(long glyph, long stroker, boolean inside)503 private static native long strokeBorder(long glyph, long stroker, boolean inside); /* 504 FT_Glyph border_glyph = (FT_Glyph)glyph; 505 FT_Glyph_StrokeBorder(&border_glyph, (FT_Stroker)stroker, inside, 1); 506 return (jlong)border_glyph; 507 */ 508 toBitmap(int renderMode)509 public void toBitmap(int renderMode) { 510 long bitmap = toBitmap(address, renderMode); 511 if (bitmap == 0) throw new GdxRuntimeException("Couldn't render glyph"); 512 address = bitmap; 513 rendered = true; 514 } 515 toBitmap(long glyph, int renderMode)516 private static native long toBitmap(long glyph, int renderMode); /* 517 FT_Glyph bitmap = (FT_Glyph)glyph; 518 FT_Error error = FT_Glyph_To_Bitmap(&bitmap, (FT_Render_Mode)renderMode, NULL, 1); 519 if(error) return 0; 520 return (jlong)bitmap; 521 */ 522 getBitmap()523 public Bitmap getBitmap() { 524 if (!rendered) { 525 throw new GdxRuntimeException("Glyph is not yet rendered"); 526 } 527 return new Bitmap(getBitmap(address)); 528 } 529 getBitmap(long glyph)530 private static native long getBitmap(long glyph); /* 531 FT_BitmapGlyph glyph_bitmap = ((FT_BitmapGlyph)glyph); 532 return (jlong)&(glyph_bitmap->bitmap); 533 */ 534 getLeft()535 public int getLeft() { 536 if (!rendered) { 537 throw new GdxRuntimeException("Glyph is not yet rendered"); 538 } 539 return getLeft(address); 540 } 541 getLeft(long glyph)542 private static native int getLeft(long glyph); /* 543 FT_BitmapGlyph glyph_bitmap = ((FT_BitmapGlyph)glyph); 544 return glyph_bitmap->left; 545 */ 546 getTop()547 public int getTop() { 548 if (!rendered) { 549 throw new GdxRuntimeException("Glyph is not yet rendered"); 550 } 551 return getTop(address); 552 } 553 getTop(long glyph)554 private static native int getTop(long glyph); /* 555 FT_BitmapGlyph glyph_bitmap = ((FT_BitmapGlyph)glyph); 556 return glyph_bitmap->top; 557 */ 558 559 } 560 561 public static class Bitmap extends Pointer { Bitmap(long address)562 Bitmap (long address) { 563 super(address); 564 } 565 getRows()566 public int getRows() { 567 return getRows(address); 568 } 569 getRows(long bitmap)570 private static native int getRows(long bitmap); /* 571 return ((FT_Bitmap*)bitmap)->rows; 572 */ 573 getWidth()574 public int getWidth() { 575 return getWidth(address); 576 } 577 getWidth(long bitmap)578 private static native int getWidth(long bitmap); /* 579 return ((FT_Bitmap*)bitmap)->width; 580 */ 581 getPitch()582 public int getPitch() { 583 return getPitch(address); 584 } 585 getPitch(long bitmap)586 private static native int getPitch(long bitmap); /* 587 return ((FT_Bitmap*)bitmap)->pitch; 588 */ 589 getBuffer()590 public ByteBuffer getBuffer() { 591 if (getRows() == 0) 592 // Issue #768 - CheckJNI frowns upon env->NewDirectByteBuffer with NULL buffer or capacity 0 593 // "JNI WARNING: invalid values for address (0x0) or capacity (0)" 594 // FreeType sets FT_Bitmap::buffer to NULL when the bitmap is empty (e.g. for ' ') 595 // JNICheck is on by default on emulators and might have a point anyway... 596 // So let's avoid this and just return a dummy non-null non-zero buffer 597 return BufferUtils.newByteBuffer(1); 598 return getBuffer(address); 599 } 600 getBuffer(long bitmap)601 private static native ByteBuffer getBuffer(long bitmap); /* 602 FT_Bitmap* bmp = (FT_Bitmap*)bitmap; 603 return env->NewDirectByteBuffer((void*)bmp->buffer, bmp->rows * abs(bmp->pitch) * bmp->width); 604 */ 605 606 // @on getPixmap(Format format, Color color, float gamma)607 public Pixmap getPixmap (Format format, Color color, float gamma) { 608 int width = getWidth(), rows = getRows(); 609 ByteBuffer src = getBuffer(); 610 Pixmap pixmap; 611 int pixelMode = getPixelMode(); 612 int rowBytes = Math.abs(getPitch()); // We currently ignore negative pitch. 613 if (color == Color.WHITE && pixelMode == FT_PIXEL_MODE_GRAY && rowBytes == width && gamma == 1) { 614 pixmap = new Pixmap(width, rows, Format.Alpha); 615 BufferUtils.copy(src, pixmap.getPixels(), pixmap.getPixels().capacity()); 616 } else { 617 pixmap = new Pixmap(width, rows, Format.RGBA8888); 618 int rgba = Color.rgba8888(color); 619 byte[] srcRow = new byte[rowBytes]; 620 int[] dstRow = new int[width]; 621 IntBuffer dst = pixmap.getPixels().asIntBuffer(); 622 if (pixelMode == FT_PIXEL_MODE_MONO) { 623 // Use the specified color for each set bit. 624 for (int y = 0; y < rows; y++) { 625 src.get(srcRow); 626 for (int i = 0, x = 0; x < width; i++, x += 8) { 627 byte b = srcRow[i]; 628 for (int ii = 0, n = Math.min(8, width - x); ii < n; ii++) { 629 if ((b & (1 << (7 - ii))) != 0) 630 dstRow[x + ii] = rgba; 631 else 632 dstRow[x + ii] = 0; 633 } 634 } 635 dst.put(dstRow); 636 } 637 } else { 638 // Use the specified color for RGB, blend the FreeType bitmap with alpha. 639 int rgb = rgba & 0xffffff00; 640 int a = rgba & 0xff; 641 for (int y = 0; y < rows; y++) { 642 src.get(srcRow); 643 for (int x = 0; x < width; x++) { 644 float alpha = (srcRow[x] & 0xff) / 255f; 645 alpha = (float)Math.pow(alpha, gamma); // Inverse gamma. 646 dstRow[x] = rgb | (int)(a * alpha); 647 } 648 dst.put(dstRow); 649 } 650 } 651 } 652 653 Pixmap converted = pixmap; 654 if (format != pixmap.getFormat()) { 655 converted = new Pixmap(pixmap.getWidth(), pixmap.getHeight(), format); 656 Blending blending = Pixmap.getBlending(); 657 Pixmap.setBlending(Blending.None); 658 converted.drawPixmap(pixmap, 0, 0); 659 Pixmap.setBlending(blending); 660 pixmap.dispose(); 661 } 662 return converted; 663 } 664 // @off 665 getNumGray()666 public int getNumGray() { 667 return getNumGray(address); 668 } 669 getNumGray(long bitmap)670 private static native int getNumGray(long bitmap); /* 671 return ((FT_Bitmap*)bitmap)->num_grays; 672 */ 673 getPixelMode()674 public int getPixelMode() { 675 return getPixelMode(address); 676 } 677 getPixelMode(long bitmap)678 private static native int getPixelMode(long bitmap); /* 679 return ((FT_Bitmap*)bitmap)->pixel_mode; 680 */ 681 } 682 683 public static class GlyphMetrics extends Pointer { GlyphMetrics(long address)684 GlyphMetrics (long address) { 685 super(address); 686 } 687 getWidth()688 public int getWidth() { 689 return getWidth(address); 690 } 691 getWidth(long metrics)692 private static native int getWidth(long metrics); /* 693 return ((FT_Glyph_Metrics*)metrics)->width; 694 */ 695 getHeight()696 public int getHeight() { 697 return getHeight(address); 698 } 699 getHeight(long metrics)700 private static native int getHeight(long metrics); /* 701 return ((FT_Glyph_Metrics*)metrics)->height; 702 */ 703 getHoriBearingX()704 public int getHoriBearingX() { 705 return getHoriBearingX(address); 706 } 707 getHoriBearingX(long metrics)708 private static native int getHoriBearingX(long metrics); /* 709 return ((FT_Glyph_Metrics*)metrics)->horiBearingX; 710 */ 711 getHoriBearingY()712 public int getHoriBearingY() { 713 return getHoriBearingY(address); 714 } 715 getHoriBearingY(long metrics)716 private static native int getHoriBearingY(long metrics); /* 717 return ((FT_Glyph_Metrics*)metrics)->horiBearingY; 718 */ 719 getHoriAdvance()720 public int getHoriAdvance() { 721 return getHoriAdvance(address); 722 } 723 getHoriAdvance(long metrics)724 private static native int getHoriAdvance(long metrics); /* 725 return ((FT_Glyph_Metrics*)metrics)->horiAdvance; 726 */ 727 getVertBearingX()728 public int getVertBearingX() { 729 return getVertBearingX(address); 730 } 731 getVertBearingX(long metrics)732 private static native int getVertBearingX(long metrics); /* 733 return ((FT_Glyph_Metrics*)metrics)->vertBearingX; 734 */ 735 getVertBearingY()736 public int getVertBearingY() { 737 return getVertBearingY(address); 738 } 739 getVertBearingY(long metrics)740 private static native int getVertBearingY(long metrics); /* 741 return ((FT_Glyph_Metrics*)metrics)->vertBearingY; 742 */ 743 getVertAdvance()744 public int getVertAdvance() { 745 return getVertAdvance(address); 746 } 747 getVertAdvance(long metrics)748 private static native int getVertAdvance(long metrics); /* 749 return ((FT_Glyph_Metrics*)metrics)->vertAdvance; 750 */ 751 } 752 753 public static class Stroker extends Pointer implements Disposable { Stroker(long address)754 Stroker(long address) { 755 super(address); 756 } 757 set(int radius, int lineCap, int lineJoin, int miterLimit)758 public void set(int radius, int lineCap, int lineJoin, int miterLimit) { 759 set(address, radius, lineCap, lineJoin, miterLimit); 760 } 761 set(long stroker, int radius, int lineCap, int lineJoin, int miterLimit)762 private static native void set(long stroker, int radius, int lineCap, int lineJoin, int miterLimit); /* 763 FT_Stroker_Set((FT_Stroker)stroker, radius, (FT_Stroker_LineCap)lineCap, (FT_Stroker_LineJoin)lineJoin, miterLimit); 764 */ 765 766 @Override dispose()767 public void dispose() { 768 done(address); 769 } 770 done(long stroker)771 private static native void done(long stroker); /* 772 FT_Stroker_Done((FT_Stroker)stroker); 773 */ 774 } 775 776 public static int FT_PIXEL_MODE_NONE = 0; 777 public static int FT_PIXEL_MODE_MONO = 1; 778 public static int FT_PIXEL_MODE_GRAY = 2; 779 public static int FT_PIXEL_MODE_GRAY2 = 3; 780 public static int FT_PIXEL_MODE_GRAY4 = 4; 781 public static int FT_PIXEL_MODE_LCD = 5; 782 public static int FT_PIXEL_MODE_LCD_V = 6; 783 encode(char a, char b, char c, char d)784 private static int encode (char a, char b, char c, char d) { 785 return (a << 24) | (b << 16) | (c << 8) | d; 786 } 787 788 public static int FT_ENCODING_NONE = 0; 789 public static int FT_ENCODING_MS_SYMBOL = encode('s', 'y', 'm', 'b'); 790 public static int FT_ENCODING_UNICODE = encode('u', 'n', 'i', 'c'); 791 public static int FT_ENCODING_SJIS = encode('s', 'j', 'i', 's'); 792 public static int FT_ENCODING_GB2312 = encode('g', 'b', ' ', ' '); 793 public static int FT_ENCODING_BIG5 = encode('b', 'i', 'g', '5'); 794 public static int FT_ENCODING_WANSUNG = encode('w', 'a', 'n', 's'); 795 public static int FT_ENCODING_JOHAB = encode('j', 'o', 'h', 'a'); 796 public static int FT_ENCODING_ADOBE_STANDARD = encode('A', 'D', 'O', 'B'); 797 public static int FT_ENCODING_ADOBE_EXPERT = encode('A', 'D', 'B', 'E'); 798 public static int FT_ENCODING_ADOBE_CUSTOM = encode('A', 'D', 'B', 'C'); 799 public static int FT_ENCODING_ADOBE_LATIN_1 = encode('l', 'a', 't', '1'); 800 public static int FT_ENCODING_OLD_LATIN_2 = encode('l', 'a', 't', '2'); 801 public static int FT_ENCODING_APPLE_ROMAN = encode('a', 'r', 'm', 'n'); 802 803 public static int FT_FACE_FLAG_SCALABLE = ( 1 << 0 ); 804 public static int FT_FACE_FLAG_FIXED_SIZES = ( 1 << 1 ); 805 public static int FT_FACE_FLAG_FIXED_WIDTH = ( 1 << 2 ); 806 public static int FT_FACE_FLAG_SFNT = ( 1 << 3 ); 807 public static int FT_FACE_FLAG_HORIZONTAL = ( 1 << 4 ); 808 public static int FT_FACE_FLAG_VERTICAL = ( 1 << 5 ); 809 public static int FT_FACE_FLAG_KERNING = ( 1 << 6 ); 810 public static int FT_FACE_FLAG_FAST_GLYPHS = ( 1 << 7 ); 811 public static int FT_FACE_FLAG_MULTIPLE_MASTERS = ( 1 << 8 ); 812 public static int FT_FACE_FLAG_GLYPH_NAMES = ( 1 << 9 ); 813 public static int FT_FACE_FLAG_EXTERNAL_STREAM = ( 1 << 10 ); 814 public static int FT_FACE_FLAG_HINTER = ( 1 << 11 ); 815 public static int FT_FACE_FLAG_CID_KEYED = ( 1 << 12 ); 816 public static int FT_FACE_FLAG_TRICKY = ( 1 << 13 ); 817 818 public static int FT_STYLE_FLAG_ITALIC = ( 1 << 0 ); 819 public static int FT_STYLE_FLAG_BOLD = ( 1 << 1 ); 820 821 public static int FT_LOAD_DEFAULT = 0x0; 822 public static int FT_LOAD_NO_SCALE = 0x1; 823 public static int FT_LOAD_NO_HINTING = 0x2; 824 public static int FT_LOAD_RENDER = 0x4; 825 public static int FT_LOAD_NO_BITMAP = 0x8; 826 public static int FT_LOAD_VERTICAL_LAYOUT = 0x10; 827 public static int FT_LOAD_FORCE_AUTOHINT = 0x20; 828 public static int FT_LOAD_CROP_BITMAP = 0x40; 829 public static int FT_LOAD_PEDANTIC = 0x80; 830 public static int FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH = 0x200; 831 public static int FT_LOAD_NO_RECURSE = 0x400; 832 public static int FT_LOAD_IGNORE_TRANSFORM = 0x800; 833 public static int FT_LOAD_MONOCHROME = 0x1000; 834 public static int FT_LOAD_LINEAR_DESIGN = 0x2000; 835 public static int FT_LOAD_NO_AUTOHINT = 0x8000; 836 837 public static int FT_LOAD_TARGET_NORMAL = 0x0; 838 public static int FT_LOAD_TARGET_LIGHT = 0x10000; 839 public static int FT_LOAD_TARGET_MONO = 0x20000; 840 public static int FT_LOAD_TARGET_LCD = 0x30000; 841 public static int FT_LOAD_TARGET_LCD_V = 0x40000; 842 843 public static int FT_RENDER_MODE_NORMAL = 0; 844 public static int FT_RENDER_MODE_LIGHT = 1; 845 public static int FT_RENDER_MODE_MONO = 2; 846 public static int FT_RENDER_MODE_LCD = 3; 847 public static int FT_RENDER_MODE_LCD_V = 4; 848 public static int FT_RENDER_MODE_MAX = 5; 849 850 public static int FT_KERNING_DEFAULT = 0; 851 public static int FT_KERNING_UNFITTED = 1; 852 public static int FT_KERNING_UNSCALED = 2; 853 854 public static int FT_STROKER_LINECAP_BUTT = 0; 855 public static int FT_STROKER_LINECAP_ROUND = 1; 856 public static int FT_STROKER_LINECAP_SQUARE = 2; 857 858 public static int FT_STROKER_LINEJOIN_ROUND = 0; 859 public static int FT_STROKER_LINEJOIN_BEVEL = 1; 860 public static int FT_STROKER_LINEJOIN_MITER_VARIABLE = 2; 861 public static int FT_STROKER_LINEJOIN_MITER = FT_STROKER_LINEJOIN_MITER_VARIABLE; 862 public static int FT_STROKER_LINEJOIN_MITER_FIXED = 3; 863 initFreeType()864 public static Library initFreeType() { 865 new SharedLibraryLoader().load("gdx-freetype"); 866 long address = initFreeTypeJni(); 867 if(address == 0) throw new GdxRuntimeException("Couldn't initialize FreeType library"); 868 else return new Library(address); 869 } 870 initFreeTypeJni()871 private static native long initFreeTypeJni(); /* 872 FT_Library library = 0; 873 FT_Error error = FT_Init_FreeType(&library); 874 if(error) return 0; 875 else return (jlong)library; 876 */ 877 toInt(int value)878 public static int toInt (int value) { 879 return ((value + 63) & -64) >> 6; 880 } 881 882 // public static void main (String[] args) throws Exception { 883 // FreetypeBuild.main(args); 884 // new SharedLibraryLoader("libs/gdx-freetype-natives.jar").load("gdx-freetype"); 885 // String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890\"!`?'.,;:()[]{}<>|/@\\^$-%+=#_&~*�? �?�?�?�? ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿À�?ÂÃÄÅÆÇÈÉÊËÌ�?Î�?�?ÑÒÓÔÕÖ×ØÙÚÛÜ�?Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"; 886 // 887 // Library library = FreeType.initFreeType(); 888 // Face face = library.newFace(new FileHandle("arial.ttf"), 0); 889 // face.setPixelSizes(0, 15); 890 // SizeMetrics faceMetrics = face.getSize().getMetrics(); 891 // System.out.println(toInt(faceMetrics.getAscender()) + ", " + toInt(faceMetrics.getDescender()) + ", " + toInt(faceMetrics.getHeight())); 892 // 893 // for(int i = 0; i < chars.length(); i++) { 894 // if(!FreeType.loadGlyph(face, FreeType.getCharIndex(face, chars.charAt(i)), 0)) continue; 895 // if(!FreeType.renderGlyph(face.getGlyph(), FT_RENDER_MODE_NORMAL)) continue; 896 // Bitmap bitmap = face.getGlyph().getBitmap(); 897 // GlyphMetrics glyphMetrics = face.getGlyph().getMetrics(); 898 // System.out.println(toInt(glyphMetrics.getHoriBearingX()) + ", " + toInt(glyphMetrics.getHoriBearingY())); 899 // System.out.println(toInt(glyphMetrics.getWidth()) + ", " + toInt(glyphMetrics.getHeight()) + ", " + toInt(glyphMetrics.getHoriAdvance())); 900 // System.out.println(bitmap.getWidth() + ", " + bitmap.getRows() + ", " + bitmap.getPitch() + ", " + bitmap.getNumGray()); 901 // for(int y = 0; y < bitmap.getRows(); y++) { 902 // for(int x = 0; x < bitmap.getWidth(); x++) { 903 // System.out.print(bitmap.getBuffer().get(x + bitmap.getPitch() * y) != 0? "X": " "); 904 // } 905 // System.out.println(); 906 // } 907 // } 908 // 909 // face.dispose(); 910 // library.dispose(); 911 // } 912 } 913