1 /* 2 * Copyright (c) 2013, 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.coretext; 27 28 import com.sun.javafx.font.Disposer; 29 import com.sun.javafx.font.DisposerRecord; 30 import com.sun.javafx.font.FontStrikeDesc; 31 import com.sun.javafx.font.PrismFontFile; 32 import com.sun.javafx.font.PrismFontStrike; 33 import com.sun.javafx.geom.Path2D; 34 import com.sun.javafx.geom.transform.BaseTransform; 35 36 class CTFontFile extends PrismFontFile { 37 38 private final long cgFontRef; 39 /* Transform used for outline and bounds */ 40 private final static CGAffineTransform tx = new CGAffineTransform(); 41 static { 42 tx.a = 1; /* scale x */ 43 tx.d = -1; /* scale y */ 44 } 45 46 private static class SelfDisposerRecord implements DisposerRecord { 47 private long cgFontRef; 48 49 SelfDisposerRecord(long cgFontRef) { 50 this.cgFontRef = cgFontRef; 51 } 52 53 @Override 54 public synchronized void dispose() { 55 if (cgFontRef != 0) { 56 OS.CFRelease(cgFontRef); 57 cgFontRef = 0; 58 } 59 } 60 } 61 62 CTFontFile(String name, String filename, int fIndex, boolean register, 63 boolean embedded, boolean copy, boolean tracked) throws Exception { 64 super(name, filename, fIndex, register, embedded, copy, tracked); 65 66 if (embedded) { 67 cgFontRef = createCGFontForEmbeddedFont(); 68 Disposer.addRecord(this, new SelfDisposerRecord(cgFontRef)); 69 } else { 70 cgFontRef = 0; 71 } 72 } 73 74 public static boolean registerFont(String fontfile) { 75 if (fontfile == null) return false; 76 long alloc = OS.kCFAllocatorDefault(); 77 boolean result = false; 78 long fileRef = OS.CFStringCreate(fontfile); 79 if (fileRef != 0) { 80 int pathStyle = OS.kCFURLPOSIXPathStyle; 81 long urlRef = OS.CFURLCreateWithFileSystemPath(alloc, fileRef, pathStyle, false); 82 if (urlRef != 0) { 83 int scope = OS.kCTFontManagerScopeProcess; 84 result = OS.CTFontManagerRegisterFontsForURL(urlRef, scope, 0); 85 OS.CFRelease(urlRef); 86 } 87 OS.CFRelease(fileRef); 88 } 89 return result; 90 } 91 92 private long createCGFontForEmbeddedFont() { 93 long cgFontRef = 0; 94 final long fileNameRef = OS.CFStringCreate(getFileName()); 95 if (fileNameRef != 0) { 96 final long url = OS.CFURLCreateWithFileSystemPath( 97 OS.kCFAllocatorDefault(), fileNameRef, 98 OS.kCFURLPOSIXPathStyle, false); 99 if (url != 0) { 100 final long dataProvider = OS.CGDataProviderCreateWithURL(url); 101 if (dataProvider != 0) { 102 cgFontRef = OS.CGFontCreateWithDataProvider(dataProvider); 103 OS.CFRelease(dataProvider); 104 } 105 OS.CFRelease(url); 106 } 107 OS.CFRelease(fileNameRef); 108 } 109 return cgFontRef; 110 } 111 112 long getCGFontRef() { 113 return cgFontRef; 114 } 115 116 CGRect getBBox(int gc, float size) { 117 CTFontStrike strike = (CTFontStrike)getStrike(size, BaseTransform.IDENTITY_TRANSFORM); 118 long fontRef = strike.getFontRef(); 119 if (fontRef == 0) return null; 120 long pathRef = OS.CTFontCreatePathForGlyph(fontRef, (short)gc, tx); 121 if (pathRef == 0) return null; 122 CGRect rect = OS.CGPathGetPathBoundingBox(pathRef); 123 OS.CGPathRelease(pathRef); 124 return rect; 125 } 126 127 Path2D getGlyphOutline(int gc, float size) { 128 CTFontStrike strike = (CTFontStrike)getStrike(size, BaseTransform.IDENTITY_TRANSFORM); 129 long fontRef = strike.getFontRef(); 130 if (fontRef == 0) return null; 131 long pathRef = OS.CTFontCreatePathForGlyph(fontRef, (short)gc, tx); 132 if (pathRef == 0) return null; 133 Path2D path = OS.CGPathApply(pathRef); 134 OS.CGPathRelease(pathRef); 135 return path; 136 } 137 138 @Override protected int[] createGlyphBoundingBox(int gc) { 139 float size = 12; 140 CTFontStrike strike = (CTFontStrike)getStrike(size, 141 BaseTransform.IDENTITY_TRANSFORM); 142 143 long fontRef = strike.getFontRef(); 144 if (fontRef == 0) return null; 145 int[] bb = new int[4]; 146 147 /* For some reason CTFontGetBoundingRectsForGlyphs has poor performance. 148 * The fix is to use the 'loca' and the 'glyf' tables to determine 149 * the glyph bounding box (same as T2K). This implementation 150 * uses native code to read these tables since they can be large. 151 * In case it fails, or the font doesn't have a glyph table 152 * (CFF fonts), then the bounds of the glyph outline is used instead. 153 */ 154 if (!isCFF()) { 155 short format = getIndexToLocFormat(); 156 if (OS.CTFontGetBoundingRectForGlyphUsingTables(fontRef, (short)gc, format, bb)) { 157 return bb; 158 } 159 } 160 /* Note: not using tx here as the bounds need to be y up */ 161 long pathRef = OS.CTFontCreatePathForGlyph(fontRef, (short)gc, null); 162 if (pathRef == 0) return null; 163 CGRect rect = OS.CGPathGetPathBoundingBox(pathRef); 164 OS.CGPathRelease(pathRef); 165 float scale = getUnitsPerEm() / size; 166 bb[0] = (int)(Math.round(rect.origin.x * scale)); 167 bb[1] = (int)(Math.round(rect.origin.y * scale)); 168 bb[2] = (int)(Math.round((rect.origin.x + rect.size.width) * scale)); 169 bb[3] = (int)(Math.round((rect.origin.y + rect.size.height) * scale)); 170 return bb; 171 } 172 173 @Override 174 protected PrismFontStrike<CTFontFile> createStrike(float size, 175 BaseTransform transform, int aaMode, FontStrikeDesc desc) { 176 return new CTFontStrike(this, size, transform, aaMode, desc); 177 } 178 179 }