Home | History | Annotate | Download | only in freetype
      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 
     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 
     52 		Library (long address) {
     53 			super(address);
     54 		}
     55 
     56 		@Override
     57 		public void dispose () {
     58 			doneFreeType(address);
     59 			for(ByteBuffer buffer: fontData.values()) {
     60 				BufferUtils.disposeUnsafeByteBuffer(buffer);
     61 			}
     62 		}
     63 
     64 		private static native void doneFreeType(long library); /*
     65 			FT_Done_FreeType((FT_Library)library);
     66 		*/
     67 
     68 		public Face newFace(FileHandle font, int faceIndex) {
     69 			byte[] data = font.readBytes();
     70 			return newMemoryFace(data, data.length, faceIndex);
     71 		}
     72 
     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 
     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 
     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 
     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 
    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 
    115 		public Face (long address, Library library) {
    116 			super(address);
    117 			this.library = library;
    118 		}
    119 
    120 		@Override
    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 
    130 		private static native void doneFace(long face); /*
    131 			FT_Done_Face((FT_Face)face);
    132 		*/
    133 
    134 		public int getFaceFlags() {
    135 			return getFaceFlags(address);
    136 		}
    137 
    138 		private static native int getFaceFlags(long face); /*
    139 			return ((FT_Face)face)->face_flags;
    140 		*/
    141 
    142 		public int getStyleFlags() {
    143 			return getStyleFlags(address);
    144 		}
    145 
    146 		private static native int getStyleFlags(long face); /*
    147 			return ((FT_Face)face)->style_flags;
    148 		*/
    149 
    150 		public int getNumGlyphs() {
    151 			return getNumGlyphs(address);
    152 		}
    153 
    154 		private static native int getNumGlyphs(long face); /*
    155 			return ((FT_Face)face)->num_glyphs;
    156 		*/
    157 
    158 		public int getAscender() {
    159 			return getAscender(address);
    160 		}
    161 
    162 		private static native int getAscender(long face); /*
    163 			return ((FT_Face)face)->ascender;
    164 		*/
    165 
    166 		public int getDescender() {
    167 			return getDescender(address);
    168 		}
    169 
    170 		private static native int getDescender(long face); /*
    171 			return ((FT_Face)face)->descender;
    172 		*/
    173 
    174 		public int getHeight() {
    175 			return getHeight(address);
    176 		}
    177 
    178 		private static native int getHeight(long face); /*
    179 			return ((FT_Face)face)->height;
    180 		*/
    181 
    182 		public int getMaxAdvanceWidth() {
    183 			return getMaxAdvanceWidth(address);
    184 		}
    185 
    186 		private static native int getMaxAdvanceWidth(long face); /*
    187 			return ((FT_Face)face)->max_advance_width;
    188 		*/
    189 
    190 		public int getMaxAdvanceHeight() {
    191 			return getMaxAdvanceHeight(address);
    192 		}
    193 
    194 		private static native int getMaxAdvanceHeight(long face); /*
    195 			return ((FT_Face)face)->max_advance_height;
    196 		*/
    197 
    198 		public int getUnderlinePosition() {
    199 			return getUnderlinePosition(address);
    200 		}
    201 
    202 		private static native int getUnderlinePosition(long face); /*
    203 			return ((FT_Face)face)->underline_position;
    204 		*/
    205 
    206 		public int getUnderlineThickness() {
    207 			return getUnderlineThickness(address);
    208 		}
    209 
    210 		private static native int getUnderlineThickness(long face); /*
    211 			return ((FT_Face)face)->underline_thickness;
    212 		*/
    213 
    214 		public boolean selectSize(int strikeIndex) {
    215 			return selectSize(address, strikeIndex);
    216 		}
    217 
    218 		private static native boolean selectSize(long face, int strike_index); /*
    219 			return !FT_Select_Size((FT_Face)face, strike_index);
    220 		*/
    221 
    222 		public boolean setCharSize(int charWidth, int charHeight, int horzResolution, int vertResolution) {
    223 			return setCharSize(address, charWidth, charHeight, horzResolution, vertResolution);
    224 		}
    225 
    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 
    230 		public boolean setPixelSizes(int pixelWidth, int pixelHeight) {
    231 			return setPixelSizes(address, pixelWidth, pixelHeight);
    232 		}
    233 
    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 
    238 		public boolean loadGlyph(int glyphIndex, int loadFlags) {
    239 			return loadGlyph(address, glyphIndex, loadFlags);
    240 		}
    241 
    242 		private static native boolean loadGlyph(long face, int glyphIndex, int loadFlags); /*
    243 			return !FT_Load_Glyph((FT_Face)face, glyphIndex, loadFlags);
    244 		*/
    245 
    246 		public boolean loadChar(int charCode, int loadFlags) {
    247 			return loadChar(address, charCode, loadFlags);
    248 		}
    249 
    250 		private static native boolean loadChar(long face, int charCode, int loadFlags); /*
    251 			return !FT_Load_Char((FT_Face)face, charCode, loadFlags);
    252 		*/
    253 
    254 		public GlyphSlot getGlyph() {
    255 			return new GlyphSlot(getGlyph(address));
    256 		}
    257 
    258 		private static native long getGlyph(long face); /*
    259 			return (jlong)((FT_Face)face)->glyph;
    260 		*/
    261 
    262 		public Size getSize() {
    263 			return new Size(getSize(address));
    264 		}
    265 
    266 		private static native long getSize(long face); /*
    267 			return (jlong)((FT_Face)face)->size;
    268 		*/
    269 
    270 		public boolean hasKerning() {
    271 			return hasKerning(address);
    272 		}
    273 
    274 		private static native boolean hasKerning(long face); /*
    275 			return FT_HAS_KERNING(((FT_Face)face));
    276 		*/
    277 
    278 		public int getKerning(int leftGlyph, int rightGlyph, int kernMode) {
    279 			return getKerning(address, leftGlyph, rightGlyph, kernMode);
    280 		}
    281 
    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 
    289 		public int getCharIndex(int charCode) {
    290 			return getCharIndex(address, charCode);
    291 		}
    292 
    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 {
    300 		Size (long address) {
    301 			super(address);
    302 		}
    303 
    304 		public SizeMetrics getMetrics() {
    305 			return new SizeMetrics(getMetrics(address));
    306 		}
    307 
    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 {
    314 		SizeMetrics (long address) {
    315 			super(address);
    316 		}
    317 
    318 		public int getXppem() {
    319 			return getXppem(address);
    320 		}
    321 
    322 		private static native int getXppem(long metrics); /*
    323 			return ((FT_Size_Metrics*)metrics)->x_ppem;
    324 		*/
    325 
    326 		public int getYppem() {
    327 			return getYppem(address);
    328 		}
    329 
    330 		private static native int getYppem(long metrics); /*
    331 			return ((FT_Size_Metrics*)metrics)->y_ppem;
    332 		*/
    333 
    334 		public int getXScale() {
    335 			return getXscale(address);
    336 		}
    337 
    338 		private static native int getXscale(long metrics); /*
    339 			return ((FT_Size_Metrics*)metrics)->x_scale;
    340 		*/
    341 
    342 		public int getYscale() {
    343 			return getYscale(address);
    344 		}
    345 
    346 		private static native int getYscale(long metrics); /*
    347 			return ((FT_Size_Metrics*)metrics)->x_scale;
    348 		*/
    349 
    350 		public int getAscender() {
    351 			return getAscender(address);
    352 		}
    353 
    354 		private static native int getAscender(long metrics); /*
    355 			return ((FT_Size_Metrics*)metrics)->ascender;
    356 		*/
    357 
    358 		public int getDescender() {
    359 			return getDescender(address);
    360 		}
    361 
    362 		private static native int getDescender(long metrics); /*
    363 			return ((FT_Size_Metrics*)metrics)->descender;
    364 		*/
    365 
    366 		public int getHeight() {
    367 			return getHeight(address);
    368 		}
    369 
    370 		private static native int getHeight(long metrics); /*
    371 			return ((FT_Size_Metrics*)metrics)->height;
    372 		*/
    373 
    374 		public int getMaxAdvance() {
    375 			return getMaxAdvance(address);
    376 		}
    377 
    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 {
    384 		GlyphSlot (long address) {
    385 			super(address);
    386 		}
    387 
    388 		public GlyphMetrics getMetrics() {
    389 			return new GlyphMetrics(getMetrics(address));
    390 		}
    391 
    392 		private static native long getMetrics(long slot); /*
    393 			return (jlong)&((FT_GlyphSlot)slot)->metrics;
    394 		*/
    395 
    396 		public int getLinearHoriAdvance() {
    397 			return getLinearHoriAdvance(address);
    398 		}
    399 
    400 		private static native int getLinearHoriAdvance(long slot); /*
    401 			return ((FT_GlyphSlot)slot)->linearHoriAdvance;
    402 		*/
    403 
    404 		public int getLinearVertAdvance() {
    405 			return getLinearVertAdvance(address);
    406 		}
    407 
    408 		private static native int getLinearVertAdvance(long slot); /*
    409 			return ((FT_GlyphSlot)slot)->linearVertAdvance;
    410 		*/
    411 
    412 		public int getAdvanceX() {
    413 			return getAdvanceX(address);
    414 		}
    415 
    416 		private static native int getAdvanceX(long slot); /*
    417 			return ((FT_GlyphSlot)slot)->advance.x;
    418 		*/
    419 
    420 		public int getAdvanceY() {
    421 			return getAdvanceY(address);
    422 		}
    423 
    424 		private static native int getAdvanceY(long slot); /*
    425 			return ((FT_GlyphSlot)slot)->advance.y;
    426 		*/
    427 
    428 		public int getFormat() {
    429 			return getFormat(address);
    430 		}
    431 
    432 		private static native int getFormat(long slot); /*
    433 			return ((FT_GlyphSlot)slot)->format;
    434 		*/
    435 
    436 		public Bitmap getBitmap() {
    437 			return new Bitmap(getBitmap(address));
    438 		}
    439 
    440 		private static native long getBitmap(long slot); /*
    441 			FT_GlyphSlot glyph = ((FT_GlyphSlot)slot);
    442 			return (jlong)&(glyph->bitmap);
    443 		*/
    444 
    445 		public int getBitmapLeft() {
    446 			return getBitmapLeft(address);
    447 		}
    448 
    449 		private static native int getBitmapLeft(long slot); /*
    450 			return ((FT_GlyphSlot)slot)->bitmap_left;
    451 		*/
    452 
    453 		public int getBitmapTop() {
    454 			return getBitmapTop(address);
    455 		}
    456 
    457 		private static native int getBitmapTop(long slot); /*
    458 			return ((FT_GlyphSlot)slot)->bitmap_top;
    459 		*/
    460 
    461 		public boolean renderGlyph(int renderMode) {
    462 			return renderGlyph(address, renderMode);
    463 		}
    464 
    465 		private static native boolean renderGlyph(long slot, int renderMode); /*
    466 			return !FT_Render_Glyph((FT_GlyphSlot)slot, (FT_Render_Mode)renderMode);
    467 		*/
    468 
    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 
    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 
    486 		Glyph (long address) {
    487 			super(address);
    488 		}
    489 
    490 		@Override
    491 		public void dispose () {
    492 			done(address);
    493 		}
    494 
    495 		private static native void done(long glyph); /*
    496 			FT_Done_Glyph((FT_Glyph)glyph);
    497 		*/
    498 
    499 		public void strokeBorder(Stroker stroker, boolean inside) {
    500 			address = strokeBorder(address, stroker.address, inside);
    501 		}
    502 
    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 
    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 
    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 
    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 
    530 		private static native long getBitmap(long glyph); /*
    531 			FT_BitmapGlyph glyph_bitmap = ((FT_BitmapGlyph)glyph);
    532 			return (jlong)&(glyph_bitmap->bitmap);
    533 		*/
    534 
    535 		public int getLeft() {
    536 			if (!rendered) {
    537 				throw new GdxRuntimeException("Glyph is not yet rendered");
    538 			}
    539 			return getLeft(address);
    540 		}
    541 
    542 		private static native int getLeft(long glyph); /*
    543 			FT_BitmapGlyph glyph_bitmap = ((FT_BitmapGlyph)glyph);
    544 			return glyph_bitmap->left;
    545 		*/
    546 
    547 		public int getTop() {
    548 			if (!rendered) {
    549 				throw new GdxRuntimeException("Glyph is not yet rendered");
    550 			}
    551 			return getTop(address);
    552 		}
    553 
    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 {
    562 		Bitmap (long address) {
    563 			super(address);
    564 		}
    565 
    566 		public int getRows() {
    567 			return getRows(address);
    568 		}
    569 
    570 		private static native int getRows(long bitmap); /*
    571 			return ((FT_Bitmap*)bitmap)->rows;
    572 		*/
    573 
    574 		public int getWidth() {
    575 			return getWidth(address);
    576 		}
    577 
    578 		private static native int getWidth(long bitmap); /*
    579 			return ((FT_Bitmap*)bitmap)->width;
    580 		*/
    581 
    582 		public int getPitch() {
    583 			return getPitch(address);
    584 		}
    585 
    586 		private static native int getPitch(long bitmap); /*
    587 			return ((FT_Bitmap*)bitmap)->pitch;
    588 		*/
    589 
    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 
    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
    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 
    666 		public int getNumGray() {
    667 			return getNumGray(address);
    668 		}
    669 
    670 		private static native int getNumGray(long bitmap); /*
    671 			return ((FT_Bitmap*)bitmap)->num_grays;
    672 		*/
    673 
    674 		public int getPixelMode() {
    675 			return getPixelMode(address);
    676 		}
    677 
    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 {
    684 		GlyphMetrics (long address) {
    685 			super(address);
    686 		}
    687 
    688 		public int getWidth() {
    689 			return getWidth(address);
    690 		}
    691 
    692 		private static native int getWidth(long metrics); /*
    693 			return ((FT_Glyph_Metrics*)metrics)->width;
    694 		*/
    695 
    696 		public int getHeight() {
    697 			return getHeight(address);
    698 		}
    699 
    700 		private static native int getHeight(long metrics); /*
    701 			return ((FT_Glyph_Metrics*)metrics)->height;
    702 		*/
    703 
    704 		public int getHoriBearingX() {
    705 			return getHoriBearingX(address);
    706 		}
    707 
    708 		private static native int getHoriBearingX(long metrics); /*
    709 			return ((FT_Glyph_Metrics*)metrics)->horiBearingX;
    710 		*/
    711 
    712 		public int getHoriBearingY() {
    713 			return getHoriBearingY(address);
    714 		}
    715 
    716 		private static native int getHoriBearingY(long metrics); /*
    717 			return ((FT_Glyph_Metrics*)metrics)->horiBearingY;
    718 		*/
    719 
    720 		public int getHoriAdvance() {
    721 			return getHoriAdvance(address);
    722 		}
    723 
    724 		private static native int getHoriAdvance(long metrics); /*
    725 			return ((FT_Glyph_Metrics*)metrics)->horiAdvance;
    726 		*/
    727 
    728 		public int getVertBearingX() {
    729 			return getVertBearingX(address);
    730 		}
    731 
    732 		private static native int getVertBearingX(long metrics); /*
    733 			return ((FT_Glyph_Metrics*)metrics)->vertBearingX;
    734 		*/
    735 
    736 		public int getVertBearingY() {
    737 			return getVertBearingY(address);
    738 		}
    739 
    740 		private static native int getVertBearingY(long metrics); /*
    741 			return ((FT_Glyph_Metrics*)metrics)->vertBearingY;
    742 		 */
    743 
    744 		public int getVertAdvance() {
    745 			return getVertAdvance(address);
    746 		}
    747 
    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 {
    754 		Stroker(long address) {
    755 			super(address);
    756 		}
    757 
    758 		public void set(int radius, int lineCap, int lineJoin, int miterLimit) {
    759 			set(address, radius, lineCap, lineJoin, miterLimit);
    760 		}
    761 
    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
    767 		public void dispose() {
    768 			done(address);
    769 		}
    770 
    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 
    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 
    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 
    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 
    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