0N/A/*
2362N/A * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.font;
0N/A
0N/Aimport java.awt.Font;
0N/Aimport java.awt.FontFormatException;
0N/Aimport java.awt.GraphicsEnvironment;
0N/Aimport java.awt.font.FontRenderContext;
0N/Aimport java.awt.geom.GeneralPath;
0N/Aimport java.awt.geom.Point2D;
0N/Aimport java.awt.geom.Rectangle2D;
0N/Aimport java.io.UnsupportedEncodingException;
0N/Aimport java.lang.ref.WeakReference;
0N/Aimport java.util.Locale;
0N/A
0N/A/*
0N/A * Ideally there would be no native fonts used, and this class would be
0N/A * unneeded and removed. Presently it is still needed until such time
0N/A * as font configuration files (or the implementation equivalent) can have
0N/A * all references to fonts that are not handled via Java 2D removed.
0N/A * Currently there are two cases where this class is needed, both on
0N/A * Unix, primarily Solaris, but useful on Linux too if fonts have moved.
0N/A * 1. Some legacy F3 fonts are still referenced so that AWT "X/Motif"
0N/A * can get dingbats and symbols from them. This can be dispensed with when
0N/A * either AWT is based on 2D, or when the X font path is known to always
0N/A * contain a Type1 or TrueType font that can be used in font configuration
0N/A * files to replace the F3 fonts.
0N/A * 2. When location of font files by 2D fails, because of some system
0N/A * configuration problem, it is desirable to have a fall back to some
0N/A * functionality that lessens the immediate impact on users. Being able
0N/A * to perform limited operations by using bitmaps from X11 helps here.
0N/A */
0N/A
0N/Apublic class NativeFont extends PhysicalFont {
0N/A
0N/A String encoding;
0N/A
0N/A private int numGlyphs = -1;
0N/A boolean isBitmapDelegate;
0N/A PhysicalFont delegateFont;
0N/A
0N/A /**
0N/A * Verifies native font is accessible.
0N/A * @throws FontFormatException - if the font can't be located.
0N/A */
0N/A public NativeFont(String platName, boolean bitmapDelegate)
0N/A throws FontFormatException {
0N/A super(platName, null);
0N/A
0N/A /* This is set true if this is an instance of a NativeFont
0N/A * created by some other font, to get native bitmaps.
0N/A * The delegating font will call this font only for "basic"
0N/A * cases - ie non-rotated, uniform scale, monochrome bitmaps.
0N/A * If this is false, then this instance may need to itself
0N/A * delegate to another font for non-basic cases. Since
0N/A * NativeFonts are used in that way only for symbol and dingbats
0N/A * we know its safe to delegate these to the JRE's default
0N/A * physical font (Lucida Sans Regular).
0N/A */
0N/A isBitmapDelegate = bitmapDelegate;
0N/A
0N/A if (GraphicsEnvironment.isHeadless()) {
0N/A throw new FontFormatException("Native font in headless toolkit");
0N/A }
0N/A fontRank = Font2D.NATIVE_RANK;
0N/A initNames();
0N/A if (getNumGlyphs() == 0) {
0N/A throw new FontFormatException("Couldn't locate font" + platName);
0N/A }
0N/A }
0N/A
0N/A private void initNames() throws FontFormatException {
0N/A /* Valid XLFD has exactly 14 "-" chars.
0N/A * First run over the string to verify have at least this many
0N/A * At the same time record the locations of the hyphens
0N/A * so we can just pick the right substring later on
0N/A */
0N/A int[] hPos = new int[14];
0N/A int hyphenCnt = 1;
0N/A int pos = 1;
0N/A
0N/A String xlfd = platName.toLowerCase(Locale.ENGLISH);
0N/A if (xlfd.startsWith("-")) {
0N/A while (pos != -1 && hyphenCnt < 14) {
0N/A pos = xlfd.indexOf('-', pos);
0N/A if (pos != -1) {
0N/A hPos[hyphenCnt++] = pos;
0N/A pos++;
0N/A }
0N/A }
0N/A }
0N/A
0N/A if (hyphenCnt == 14 && pos != -1) {
0N/A
0N/A /* Capitalise words in the Family name */
0N/A String tmpFamily = xlfd.substring(hPos[1]+1, hPos[2]);
0N/A StringBuilder sBuffer = new StringBuilder(tmpFamily);
0N/A char ch = Character.toUpperCase(sBuffer.charAt(0));
0N/A sBuffer.replace(0, 1, String.valueOf(ch));
0N/A for (int i=1;i<sBuffer.length()-1; i++) {
0N/A if (sBuffer.charAt(i) == ' ') {
0N/A ch = Character.toUpperCase(sBuffer.charAt(i+1));
0N/A sBuffer.replace(i+1, i+2, String.valueOf(ch));
0N/A }
0N/A }
0N/A familyName = sBuffer.toString();
0N/A
0N/A String tmpWeight = xlfd.substring(hPos[2]+1, hPos[3]);
0N/A String tmpSlant = xlfd.substring(hPos[3]+1, hPos[4]);
0N/A
0N/A String styleStr = null;
0N/A
0N/A if (tmpWeight.indexOf("bold") >= 0 ||
0N/A tmpWeight.indexOf("demi") >= 0) {
0N/A style |= Font.BOLD;
0N/A styleStr = "Bold";
0N/A }
0N/A
0N/A if (tmpSlant.equals("i") ||
0N/A tmpSlant.indexOf("italic") >= 0) {
0N/A style |= Font.ITALIC;
0N/A
0N/A if (styleStr == null) {
0N/A styleStr = "Italic";
0N/A } else {
0N/A styleStr = styleStr + " Italic";
0N/A }
0N/A }
0N/A else if (tmpSlant.equals("o") ||
0N/A tmpSlant.indexOf("oblique") >= 0) {
0N/A style |= Font.ITALIC;
0N/A if (styleStr == null) {
0N/A styleStr = "Oblique";
0N/A } else {
0N/A styleStr = styleStr + " Oblique";
0N/A }
0N/A }
0N/A
0N/A if (styleStr == null) {
0N/A fullName = familyName;
0N/A } else {
0N/A fullName = familyName + " " + styleStr;
0N/A }
0N/A
0N/A encoding = xlfd.substring(hPos[12]+1);
0N/A if (encoding.startsWith("-")) {
0N/A encoding = xlfd.substring(hPos[13]+1);
0N/A }
0N/A if (encoding.indexOf("fontspecific") >= 0) {
0N/A if (tmpFamily.indexOf("dingbats") >= 0) {
0N/A encoding = "dingbats";
0N/A } else if (tmpFamily.indexOf("symbol") >= 0) {
0N/A encoding = "symbol";
0N/A } else {
0N/A encoding = "iso8859-1";
0N/A }
0N/A }
0N/A } else {
0N/A throw new FontFormatException("Bad native name " + platName);
0N/A// familyName = "Unknown";
0N/A// fullName = "Unknown";
0N/A// style = Font.PLAIN;
0N/A// encoding = "iso8859-1";
0N/A }
0N/A }
0N/A
0N/A /* Wildcard all the size fields in the XLFD and retrieve a list of
0N/A * XLFD's that match.
0N/A * We only look for scaleable fonts, so we can just replace the 0's
0N/A * with *'s and see what we get back
0N/A * No matches means even the scaleable version wasn't found. This is
0N/A * means the X font path isn't set up for this font at all.
0N/A * One match means only the scaleable version we started with was found
0N/A * -monotype-arial-bold-i-normal--0-0-0-0-p-0-iso8859-1
0N/A * Two matches apparently means as well as the above, a scaleable
0N/A * specified for 72 dpi is found, not that there are bitmaps : eg
0N/A * -monotype-arial-bold-i-normal--0-0-72-72-p-0-iso8859-1
0N/A * So require at least 3 matches (no need to parse) to determine that
0N/A * there are external bitmaps.
0N/A */
0N/A static boolean hasExternalBitmaps(String platName) {
0N/A /* Turn -monotype-arial-bold-i-normal--0-0-0-0-p-0-iso8859-1
0N/A * into -monotype-arial-bold-i-normal--*-*-*-*-p-*-iso8859-1
0N/A * by replacing all -0- substrings with -*-
0N/A */
0N/A StringBuilder sb = new StringBuilder(platName);
0N/A int pos = sb.indexOf("-0-");
0N/A while (pos >=0) {
0N/A sb.replace(pos+1, pos+2, "*");
0N/A pos = sb.indexOf("-0-", pos);
0N/A };
0N/A String xlfd = sb.toString();
0N/A byte[] bytes = null;
0N/A try {
0N/A bytes = xlfd.getBytes("UTF-8");
0N/A } catch (UnsupportedEncodingException e) {
0N/A bytes = xlfd.getBytes();
0N/A }
0N/A return haveBitmapFonts(bytes);
0N/A }
0N/A
0N/A public static boolean fontExists(String xlfd) {
0N/A byte[] bytes = null;
0N/A try {
0N/A bytes = xlfd.getBytes("UTF-8");
0N/A } catch (UnsupportedEncodingException e) {
0N/A bytes = xlfd.getBytes();
0N/A }
0N/A return fontExists(bytes);
0N/A }
0N/A
0N/A private static native boolean haveBitmapFonts(byte[] xlfd);
0N/A private static native boolean fontExists(byte[] xlfd);
0N/A
0N/A public CharToGlyphMapper getMapper() {
0N/A if (mapper == null) {
0N/A if (isBitmapDelegate) {
0N/A /* we are a delegate */
0N/A mapper = new NativeGlyphMapper(this);
0N/A } else {
0N/A /* we need to delegate */
1686N/A SunFontManager fm = SunFontManager.getInstance();
1686N/A delegateFont = fm.getDefaultPhysicalFont();
0N/A mapper = delegateFont.getMapper();
0N/A }
0N/A }
0N/A return mapper;
0N/A }
0N/A
0N/A FontStrike createStrike(FontStrikeDesc desc) {
0N/A if (isBitmapDelegate) {
0N/A return new NativeStrike(this, desc);
0N/A } else {
0N/A if (delegateFont == null) {
1686N/A SunFontManager fm = SunFontManager.getInstance();
1686N/A delegateFont = fm.getDefaultPhysicalFont();
0N/A }
0N/A /* If no FileFont's are found, delegate font may be
0N/A * a NativeFont, so we need to avoid recursing here.
0N/A */
0N/A if (delegateFont instanceof NativeFont) {
0N/A return new NativeStrike((NativeFont)delegateFont, desc);
0N/A }
0N/A FontStrike delegate = delegateFont.createStrike(desc);
0N/A return new DelegateStrike(this, desc, delegate);
0N/A }
0N/A }
0N/A
0N/A public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
0N/A return null;
0N/A }
0N/A
0N/A native StrikeMetrics getFontMetrics(long pScalerContext);
0N/A
0N/A native float getGlyphAdvance(long pContext, int glyphCode);
0N/A
0N/A Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext,
0N/A int glyphCode) {
0N/A return new Rectangle2D.Float(0f, 0f, 0f, 0f);
0N/A }
0N/A
0N/A public GeneralPath getGlyphOutline(long pScalerContext,
0N/A int glyphCode,
0N/A float x,
0N/A float y) {
0N/A return null;
0N/A }
0N/A
0N/A native long getGlyphImage(long pScalerContext, int glyphCode);
0N/A
0N/A native long getGlyphImageNoDefault(long pScalerContext, int glyphCode);
0N/A
0N/A void getGlyphMetrics(long pScalerContext, int glyphCode,
0N/A Point2D.Float metrics) {
0N/A throw new RuntimeException("this should be called on the strike");
0N/A }
0N/A
0N/A public GeneralPath getGlyphVectorOutline(long pScalerContext,
0N/A int[] glyphs, int numGlyphs,
0N/A float x, float y) {
0N/A return null;
0N/A }
0N/A
0N/A private native int countGlyphs(byte[] platformNameBytes, int ptSize);
0N/A
0N/A public int getNumGlyphs() {
0N/A if (numGlyphs == -1) {
0N/A byte[] bytes = getPlatformNameBytes(8);
0N/A numGlyphs = countGlyphs(bytes, 8);
0N/A }
0N/A return numGlyphs;
0N/A }
0N/A
0N/A PhysicalFont getDelegateFont() {
0N/A if (delegateFont == null) {
1686N/A SunFontManager fm = SunFontManager.getInstance();
1686N/A delegateFont = fm.getDefaultPhysicalFont();
0N/A }
0N/A return delegateFont;
0N/A }
0N/A
0N/A /* Specify that the dpi is 72x72, as this corresponds to JDK's
0N/A * default user space. These are the 10th and 11th fields in the XLFD.
0N/A * ptSize in XLFD is in 10th's of a point so multiply by 10,
0N/A * Replace the 9th field in the XLFD (ie after the 8th hyphen)
0N/A * with this pt size (this corresponds to the field that's "%d" in the
0N/A * font configuration files). Wild card the other numeric fields.
0N/A * ie to request 12 pt Times New Roman italic font, use an XLFD like :
0N/A * -monotype-times new roman-regular-i---*-120-72-72-p-*-iso8859-1
0N/A */
0N/A byte[] getPlatformNameBytes(int ptSize) {
0N/A int[] hPos = new int[14];
0N/A int hyphenCnt = 1;
0N/A int pos = 1;
0N/A
0N/A while (pos != -1 && hyphenCnt < 14) {
0N/A pos = platName.indexOf('-', pos);
0N/A if (pos != -1) {
0N/A hPos[hyphenCnt++] = pos;
0N/A pos++;
0N/A }
0N/A }
0N/A String sizeStr = Integer.toString((int)Math.abs(ptSize)*10);
0N/A StringBuilder sb = new StringBuilder(platName);
0N/A /* work backwards so as to not invalidate the positions. */
0N/A sb.replace(hPos[11]+1, hPos[12], "*");
0N/A
0N/A sb.replace(hPos[9]+1, hPos[10], "72");
0N/A
0N/A sb.replace(hPos[8]+1, hPos[9], "72");
0N/A
0N/A /* replace the 3 lines above with the next 3 lines to get the 1.4.2
0N/A * behaviour
0N/A */
0N/A// sb.replace(hPos[11]+1, hPos[12], "0");
0N/A// sb.replace(hPos[9]+1, hPos[10], "0");
0N/A// sb.replace(hPos[8]+1, hPos[9], "0");
0N/A
0N/A sb.replace(hPos[7]+1, hPos[8], sizeStr);
0N/A
0N/A sb.replace(hPos[6]+1, hPos[7], "*");
0N/A
0N/A /* replace the 1 line above with the next line to get the 1.4.2
0N/A * behaviour
0N/A */
0N/A// sb.replace(hPos[6]+1, hPos[7], "0");
0N/A
0N/A /* comment out this block to the the 1.4.2 behaviour */
0N/A if (hPos[0] == 0 && hPos[1] == 1) {
0N/A /* null foundry name : some linux font configuration files have
0N/A * symbol font entries like this and its just plain wrong.
0N/A * Replace with a wild card. (Although those fonts should be
0N/A * located via disk access rather than X11).
0N/A */
0N/A sb.replace(hPos[0]+1, hPos[1], "*");
0N/A }
0N/A
0N/A String xlfd = sb.toString();
0N/A byte[] bytes = null;
0N/A try {
0N/A bytes = xlfd.getBytes("UTF-8");
0N/A } catch (UnsupportedEncodingException e) {
0N/A bytes = xlfd.getBytes();
0N/A }
0N/A return bytes;
0N/A }
0N/A
0N/A public String toString() {
0N/A return " ** Native Font: Family="+familyName+ " Name="+fullName+
0N/A " style="+style+" nativeName="+platName;
0N/A }
0N/A}