/* * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.font; import java.awt.Font; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath;; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; // Right now this class is final to avoid a problem with native code. // For some reason the JNI IsInstanceOf was not working correctly // so we are checking the class specifically. If we subclass this // we need to modify the native code in CFontWrapper.m public final class CFont extends PhysicalFont { /* CFontStrike doesn't call these methods so they are unimplemented. * They are here to meet the requirements of PhysicalFont, needed * because a CFont can sometimes be returned where a PhysicalFont * is expected. */ StrikeMetrics getFontMetrics(long pScalerContext) { throw new InternalError("Not implemented"); } float getGlyphAdvance(long pScalerContext, int glyphCode) { throw new InternalError("Not implemented"); } void getGlyphMetrics(long pScalerContext, int glyphCode, Point2D.Float metrics) { throw new InternalError("Not implemented"); } long getGlyphImage(long pScalerContext, int glyphCode) { throw new InternalError("Not implemented"); } Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext, int glyphCode) { throw new InternalError("Not implemented"); } GeneralPath getGlyphOutline(long pScalerContext, int glyphCode, float x, float y) { throw new InternalError("Not implemented"); } GeneralPath getGlyphVectorOutline(long pScalerContext, int[] glyphs, int numGlyphs, float x, float y) { throw new InternalError("Not implemented"); } private static native long createNativeFont(final String nativeFontName, final int style); private static native void disposeNativeFont(final long nativeFontPtr); private boolean isFakeItalic; private String nativeFontName; private long nativeFontPtr; private native float getWidthNative(final long nativeFontPtr); private native float getWeightNative(final long nativeFontPtr); private int fontWidth = -1; private int fontWeight = -1; @Override public int getWidth() { if (fontWidth == -1) { // Apple use a range of -1 -> +1, where 0.0 is normal // OpenType uses a % range from 50% -> 200% where 100% is normal // and maps these onto the integer values 1->9. // Since that is what Font2D.getWidth() expects, remap to that. float fw = getWidthNative(getNativeFontPtr()); if (fw == 0.0) { // short cut the common case fontWidth = Font2D.FWIDTH_NORMAL; return fontWidth; } fw += 1.0; fw *= 100.0; if (fw <= 50.0) { fontWidth = 1; } else if (fw <= 62.5) { fontWidth = 2; } else if (fw <= 75.0) { fontWidth = 3; } else if (fw <= 87.5) { fontWidth = 4; } else if (fw <= 100.0) { fontWidth = 5; } else if (fw <= 112.5) { fontWidth = 6; } else if (fw <= 125.0) { fontWidth = 7; } else if (fw <= 150.0) { fontWidth = 8; } else { fontWidth = 9; } } return fontWidth; } @Override public int getWeight() { if (fontWeight == -1) { // Apple use a range of -1 -> +1, where 0 is medium/regular // Map this on to the OpenType range of 100->900 where // 500 is medium/regular. // We'll actually map to 0->1000 but that's close enough. float fw = getWeightNative(getNativeFontPtr()); if (fw == 0) { return Font2D.FWEIGHT_NORMAL; } fw += 1.0; fw *= 500; fontWeight = (int)fw; } return fontWeight; } // this constructor is called from CFontWrapper.m public CFont(String name) { this(name, name); } public CFont(String name, String inFamilyName) { handle = new Font2DHandle(this); fullName = name; familyName = inFamilyName; nativeFontName = fullName; setStyle(); } /* Called from CFontManager too */ public CFont(CFont other, String logicalFamilyName) { handle = new Font2DHandle(this); fullName = logicalFamilyName; familyName = logicalFamilyName; nativeFontName = other.nativeFontName; style = other.style; isFakeItalic = other.isFakeItalic; } public CFont createItalicVariant() { CFont font = new CFont(this, familyName); font.nativeFontName = fullName; font.fullName = fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived"; font.style |= Font.ITALIC; font.isFakeItalic = true; return font; } protected synchronized long getNativeFontPtr() { if (nativeFontPtr == 0L) { nativeFontPtr = createNativeFont(nativeFontName, style); } return nativeFontPtr; } protected synchronized void finalize() { if (nativeFontPtr != 0) { disposeNativeFont(nativeFontPtr); } nativeFontPtr = 0; } protected CharToGlyphMapper getMapper() { if (mapper == null) { mapper = new CCharToGlyphMapper(this); } return mapper; } protected FontStrike createStrike(FontStrikeDesc desc) { if (isFakeItalic) { desc = new FontStrikeDesc(desc); desc.glyphTx.concatenate(AffineTransform.getShearInstance(-0.2, 0)); } return new CStrike(this, desc); } // sun.font.Font2D caches the last used strike, // but does not check if the properties of the strike match the properties // of the incoming java.awt.Font object (size, style, etc). // Simple answer: don't cache. private static FontRenderContext DEFAULT_FRC = new FontRenderContext(null, false, false); public FontStrike getStrike(final Font font) { return getStrike(font, DEFAULT_FRC); } public String toString() { return "CFont { fullName: " + fullName + ", familyName: " + familyName + ", style: " + style + " } aka: " + super.toString(); } }