1 /* 2 * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.font.freetype; 27 28 import com.sun.javafx.font.Disposer; 29 import com.sun.javafx.font.FontResource; 30 import com.sun.javafx.font.FontStrikeDesc; 31 import com.sun.javafx.font.PrismFontFactory; 32 import com.sun.javafx.font.PrismFontFile; 33 import com.sun.javafx.font.PrismFontStrike; 34 import com.sun.javafx.geom.Path2D; 35 import com.sun.javafx.geom.transform.BaseTransform; 36 37 class FTFontFile extends PrismFontFile { 38 /* 39 * Font files can be accessed by several threads. In general this are the 40 * JFX thread (measuring) and the Prism thread (rendering). But, if a Text 41 * node is no connected a Scene it can be used in any user thread, thus a 42 * font resource can be accessed from any thread. 43 * 44 * Freetype resources are not thread safe. In this implementation each font 45 * resources has its own FT_Face and FT_Library, and while it permits these 46 * resources be used by different threads it does not allow concurrent access. 47 * This is enforced by converging all operation (from FTFontStrike and 48 * FTGlyph) to this object and synchronizing the access to the native 49 * resources using the same lock. 50 */ 51 private long library; 52 private long face; 53 private FTDisposer disposer; 54 55 FTFontFile(String name, String filename, int fIndex, boolean register, 56 boolean embedded, boolean copy, boolean tracked) throws Exception { 57 super(name, filename, fIndex, register, embedded, copy, tracked); 58 init(); 59 } 60 61 private synchronized void init() throws Exception { 62 long[] ptr = new long[1]; 63 int error = OSFreetype.FT_Init_FreeType(ptr); 64 if (error != 0) { 65 throw new Exception("FT_Init_FreeType Failed error " + error); 66 } 67 library = ptr[0]; 68 if (FTFactory.LCD_SUPPORT) { 69 OSFreetype.FT_Library_SetLcdFilter(library, OSFreetype.FT_LCD_FILTER_DEFAULT); 70 } 71 72 String file = getFileName(); 73 int fontIndex = getFontIndex(); 74 /* Freetype expects 'a standard C string' */ 75 byte[] buffer = (file+"\0").getBytes(); 76 error = OSFreetype.FT_New_Face(library, buffer, fontIndex, ptr); 77 if (error != 0) { 78 throw new Exception("FT_New_Face Failed error " + error + 79 " Font File " + file + 80 " Font Index " + fontIndex); 81 } 82 face = ptr[0]; 83 84 if (!isRegistered()) { 85 disposer = new FTDisposer(library, face); 86 Disposer.addRecord(this, disposer); 87 } 88 } 89 90 @Override 91 protected PrismFontStrike<?> createStrike(float size, BaseTransform transform, 92 int aaMode, FontStrikeDesc desc) { 93 return new FTFontStrike(this, size, transform, aaMode, desc); 94 } 95 96 @Override 97 protected synchronized int[] createGlyphBoundingBox(int gc) { 98 int flags = OSFreetype.FT_LOAD_NO_SCALE; 99 OSFreetype.FT_Load_Glyph(face, gc, flags); 100 int[] bbox = new int[4]; 101 FT_GlyphSlotRec glyphRec = OSFreetype.getGlyphSlot(face); 102 if (glyphRec != null && glyphRec.metrics != null) { 103 FT_Glyph_Metrics gm = glyphRec.metrics; 104 bbox[0] = (int)gm.horiBearingX; 105 bbox[1] = (int)(gm.horiBearingY - gm.height); 106 bbox[2] = (int)(gm.horiBearingX + gm.width); 107 bbox[3] = (int)gm.horiBearingY; 108 } 109 return bbox; 110 } 111 112 synchronized Path2D createGlyphOutline(int gc, float size) { 113 int size26dot6 = (int)(size * 64); 114 OSFreetype.FT_Set_Char_Size(face, 0, size26dot6, 72, 72); 115 int flags = OSFreetype.FT_LOAD_NO_HINTING | OSFreetype.FT_LOAD_NO_BITMAP | OSFreetype.FT_LOAD_IGNORE_TRANSFORM; 116 OSFreetype.FT_Load_Glyph(face, gc, flags); 117 return OSFreetype.FT_Outline_Decompose(face); 118 } 119 120 synchronized void initGlyph(FTGlyph glyph, FTFontStrike strike) { 121 float size = strike.getSize(); 122 if (size == 0) { 123 glyph.buffer = new byte[0]; 124 glyph.bitmap = new FT_Bitmap(); 125 return; 126 } 127 int size26dot6 = (int)(size * 64); 128 OSFreetype.FT_Set_Char_Size(face, 0, size26dot6, 72, 72); 129 130 boolean lcd = strike.getAAMode() == FontResource.AA_LCD && 131 FTFactory.LCD_SUPPORT; 132 133 int flags = OSFreetype.FT_LOAD_RENDER | OSFreetype.FT_LOAD_NO_HINTING | OSFreetype.FT_LOAD_NO_BITMAP; 134 FT_Matrix matrix = strike.matrix; 135 if (matrix != null) { 136 OSFreetype.FT_Set_Transform(face, matrix, 0, 0); 137 } else { 138 flags |= OSFreetype.FT_LOAD_IGNORE_TRANSFORM; 139 } 140 if (lcd) { 141 flags |= OSFreetype.FT_LOAD_TARGET_LCD; 142 } else { 143 flags |= OSFreetype.FT_LOAD_TARGET_NORMAL; 144 } 145 146 int glyphCode = glyph.getGlyphCode(); 147 int error = OSFreetype.FT_Load_Glyph(face, glyphCode, flags); 148 if (error != 0) { 149 if (PrismFontFactory.debugFonts) { 150 System.err.println("FT_Load_Glyph failed " + error + 151 " glyph code " + glyphCode + 152 " load falgs " + flags); 153 } 154 return; 155 } 156 157 FT_GlyphSlotRec glyphRec = OSFreetype.getGlyphSlot(face); 158 if (glyphRec == null) return; 159 FT_Bitmap bitmap = glyphRec.bitmap; 160 if (bitmap == null) return; 161 int pixelMode = bitmap.pixel_mode; 162 int width = bitmap.width; 163 int height = bitmap.rows; 164 int pitch = bitmap.pitch; 165 if (pixelMode != OSFreetype.FT_PIXEL_MODE_GRAY && pixelMode != OSFreetype.FT_PIXEL_MODE_LCD) { 166 /* This procedure only requests FT_RENDER_MODE_NORMAL and FT_RENDER_MODE_LCD, 167 * and for its output is expects FT_PIXEL_MODE_GRAY and FT_PIXEL_MODE_LCD, respectively. 168 * But it is possible the requested rendering mode is not supported and a different 169 * output is returned by Freetype. For example, a FT_PIXEL_MODE_MONO can be returned 170 * if the font contains a bitmap for the given glyph code. 171 */ 172 if (PrismFontFactory.debugFonts) { 173 System.err.println("Unexpected pixel mode: " + pixelMode + 174 " glyph code " + glyphCode + 175 " load falgs " + flags); 176 } 177 return; 178 } 179 byte[] buffer; 180 if (width != 0 && height != 0) { 181 buffer = OSFreetype.getBitmapData(face); 182 if (buffer != null && pitch != width) { 183 /* Common for LCD glyphs */ 184 byte[] newBuffer = new byte[width * height]; 185 int src = 0, dst = 0; 186 for (int y = 0; y < height; y++) { 187 for (int x = 0; x < width; x++) { 188 newBuffer[dst + x] = buffer[src + x]; 189 } 190 dst += width; 191 src += pitch; 192 } 193 buffer = newBuffer; 194 } 195 } else { 196 /* white space */ 197 buffer = new byte[0]; 198 } 199 200 glyph.buffer = buffer; 201 glyph.bitmap = bitmap; 202 glyph.bitmap_left = glyphRec.bitmap_left; 203 glyph.bitmap_top = glyphRec.bitmap_top; 204 glyph.advanceX = glyphRec.advance_x / 64f; /* Fixed 26.6*/ 205 glyph.advanceY = glyphRec.advance_y / 64f; 206 glyph.userAdvance = glyphRec.linearHoriAdvance / 65536.0f; /* Fixed 16.16 */ 207 glyph.lcd = lcd; 208 } 209 }