• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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