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.directwrite; 27 28 import com.sun.javafx.font.Disposer; 29 import com.sun.javafx.font.FontStrikeDesc; 30 import com.sun.javafx.font.PrismFontFactory; 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.RectBounds; 35 import com.sun.javafx.geom.transform.BaseTransform; 36 37 class DWFontFile extends PrismFontFile { 38 private IDWriteFontFace fontFace; 39 private DWDisposer disposer; 40 41 DWFontFile(String name, String filename, int fIndex, boolean register, 42 boolean embedded, boolean copy, boolean tracked) throws Exception { 43 super(name, filename, fIndex, register, embedded, copy, tracked); 44 fontFace = createFontFace(); 45 46 if (PrismFontFactory.debugFonts) { 47 if (fontFace == null) { 48 System.err.println("Failed to create IDWriteFontFace for " + this); 49 } 50 } 51 52 if (!isRegistered()) { 53 disposer = new DWDisposer(fontFace); 54 Disposer.addRecord(this, disposer); 55 } 56 } 57 58 private IDWriteFontFace createEmbeddedFontFace() { 59 IDWriteFactory factory = DWFactory.getDWriteFactory(); 60 IDWriteFontFile fontFile = factory.CreateFontFileReference(getFileName()); 61 if (fontFile == null) return null; 62 boolean[] isSupportedFontType = new boolean[1]; 63 int[] fontFileType = new int[1]; 64 int[] fontFaceType = new int[1]; 65 int[] numberOfFaces = new int[1]; 66 int hr = fontFile.Analyze(isSupportedFontType, fontFileType, fontFaceType, numberOfFaces); 67 IDWriteFontFace face = null; 68 if (hr == OS.S_OK && isSupportedFontType[0]) { 69 int faceIndex = getFontIndex(); 70 int simulation = OS.DWRITE_FONT_SIMULATIONS_NONE; 71 face = factory.CreateFontFace(fontFaceType[0], fontFile, faceIndex, simulation); 72 } 73 fontFile.Release(); 74 return face; 75 } 76 77 private IDWriteFontFace createFontFace() { 78 if (isEmbeddedFont()) { 79 return createEmbeddedFontFace(); 80 } 81 82 IDWriteFontCollection collection = DWFactory.getFontCollection(); 83 int index = collection.FindFamilyName(getFamilyName()); 84 if (index == -1) { 85 /* This can happen when the family name reported by GDI does not 86 * match family name in DirectWrite. For example, GDI reports 87 * 'Arial Black' as family name while DirectWrite represents the 88 * same font using family equals to 'Arial' and style equals to 89 * DWRITE_FONT_WEIGHT_BLACK. The fix to try to create the font 90 * using the font file. 91 */ 92 return createEmbeddedFontFace(); 93 } 94 95 IDWriteFontFamily family = collection.GetFontFamily(index); 96 if (family == null) return null; 97 int weight = isBold() ? OS.DWRITE_FONT_WEIGHT_BOLD : 98 OS.DWRITE_FONT_WEIGHT_NORMAL; 99 int stretch = OS.DWRITE_FONT_STRETCH_NORMAL; 100 int style = isItalic() ? OS.DWRITE_FONT_STYLE_ITALIC : 101 OS.DWRITE_FONT_STYLE_NORMAL; 102 IDWriteFont font = family.GetFirstMatchingFont(weight, stretch, style); 103 family.Release(); 104 if (font == null) return null; 105 IDWriteFontFace face = font.CreateFontFace(); 106 font.Release(); 107 return face; 108 } 109 110 IDWriteFontFace getFontFace() { 111 return fontFace; 112 } 113 114 Path2D getGlyphOutline(int gc, float size) { 115 if (fontFace == null) return null; 116 if (size == 0) return new Path2D(); 117 return fontFace.GetGlyphRunOutline(size, (short)gc, false); 118 } 119 120 RectBounds getBBox(int glyphCode, float size) { 121 /* In coretext and t2k this is the bounds for the path of the glyph */ 122 float[] bb = new float[4]; 123 getGlyphBoundingBox(glyphCode, size, bb); 124 return new RectBounds(bb[0], bb[1], bb[2], bb[3]); 125 } 126 127 @Override protected int[] createGlyphBoundingBox(int gc) { 128 if (fontFace == null) return null; 129 DWRITE_GLYPH_METRICS metrics = fontFace.GetDesignGlyphMetrics((short)gc, false); 130 if (metrics == null) return null; 131 int[] bb = new int[4]; 132 bb[0] = metrics.leftSideBearing; 133 bb[1] = metrics.verticalOriginY - metrics.advanceHeight + metrics.bottomSideBearing; 134 bb[2] = metrics.advanceWidth - metrics.rightSideBearing; 135 bb[3] = metrics.verticalOriginY - metrics.topSideBearing; 136 return bb; 137 } 138 139 @Override 140 protected PrismFontStrike<DWFontFile> createStrike(float size, BaseTransform transform, 141 int aaMode, FontStrikeDesc desc) { 142 return new DWFontStrike(this, size, transform, aaMode, desc); 143 } 144 }