Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/font/NativeFont.java
32287 views
/*1* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.font;2627import java.awt.Font;28import java.awt.FontFormatException;29import java.awt.GraphicsEnvironment;30import java.awt.font.FontRenderContext;31import java.awt.geom.GeneralPath;32import java.awt.geom.Point2D;33import java.awt.geom.Rectangle2D;34import java.io.UnsupportedEncodingException;35import java.lang.ref.WeakReference;36import java.util.Locale;3738/*39* Ideally there would be no native fonts used, and this class would be40* unneeded and removed. Presently it is still needed until such time41* as font configuration files (or the implementation equivalent) can have42* all references to fonts that are not handled via Java 2D removed.43* Currently there are two cases where this class is needed, both on44* Unix, primarily Solaris, but useful on Linux too if fonts have moved.45* 1. Some legacy F3 fonts are still referenced so that AWT "X/Motif"46* can get dingbats and symbols from them. This can be dispensed with when47* either AWT is based on 2D, or when the X font path is known to always48* contain a Type1 or TrueType font that can be used in font configuration49* files to replace the F3 fonts.50* 2. When location of font files by 2D fails, because of some system51* configuration problem, it is desirable to have a fall back to some52* functionality that lessens the immediate impact on users. Being able53* to perform limited operations by using bitmaps from X11 helps here.54*/5556public class NativeFont extends PhysicalFont {5758String encoding;5960private int numGlyphs = -1;61boolean isBitmapDelegate;62PhysicalFont delegateFont;6364/**65* Verifies native font is accessible.66* @throws FontFormatException - if the font can't be located.67*/68public NativeFont(String platName, boolean bitmapDelegate)69throws FontFormatException {70super(platName, null);7172/* This is set true if this is an instance of a NativeFont73* created by some other font, to get native bitmaps.74* The delegating font will call this font only for "basic"75* cases - ie non-rotated, uniform scale, monochrome bitmaps.76* If this is false, then this instance may need to itself77* delegate to another font for non-basic cases. Since78* NativeFonts are used in that way only for symbol and dingbats79* we know its safe to delegate these to the JRE's default80* physical font (Lucida Sans Regular).81*/82isBitmapDelegate = bitmapDelegate;8384if (GraphicsEnvironment.isHeadless()) {85throw new FontFormatException("Native font in headless toolkit");86}87fontRank = Font2D.NATIVE_RANK;88initNames();89if (getNumGlyphs() == 0) {90throw new FontFormatException("Couldn't locate font" + platName);91}92}9394private void initNames() throws FontFormatException {95/* Valid XLFD has exactly 14 "-" chars.96* First run over the string to verify have at least this many97* At the same time record the locations of the hyphens98* so we can just pick the right substring later on99*/100int[] hPos = new int[14];101int hyphenCnt = 1;102int pos = 1;103104String xlfd = platName.toLowerCase(Locale.ENGLISH);105if (xlfd.startsWith("-")) {106while (pos != -1 && hyphenCnt < 14) {107pos = xlfd.indexOf('-', pos);108if (pos != -1) {109hPos[hyphenCnt++] = pos;110pos++;111}112}113}114115if (hyphenCnt == 14 && pos != -1) {116117/* Capitalise words in the Family name */118String tmpFamily = xlfd.substring(hPos[1]+1, hPos[2]);119StringBuilder sBuffer = new StringBuilder(tmpFamily);120char ch = Character.toUpperCase(sBuffer.charAt(0));121sBuffer.replace(0, 1, String.valueOf(ch));122for (int i=1;i<sBuffer.length()-1; i++) {123if (sBuffer.charAt(i) == ' ') {124ch = Character.toUpperCase(sBuffer.charAt(i+1));125sBuffer.replace(i+1, i+2, String.valueOf(ch));126}127}128familyName = sBuffer.toString();129130String tmpWeight = xlfd.substring(hPos[2]+1, hPos[3]);131String tmpSlant = xlfd.substring(hPos[3]+1, hPos[4]);132133String styleStr = null;134135if (tmpWeight.indexOf("bold") >= 0 ||136tmpWeight.indexOf("demi") >= 0) {137style |= Font.BOLD;138styleStr = "Bold";139}140141if (tmpSlant.equals("i") ||142tmpSlant.indexOf("italic") >= 0) {143style |= Font.ITALIC;144145if (styleStr == null) {146styleStr = "Italic";147} else {148styleStr = styleStr + " Italic";149}150}151else if (tmpSlant.equals("o") ||152tmpSlant.indexOf("oblique") >= 0) {153style |= Font.ITALIC;154if (styleStr == null) {155styleStr = "Oblique";156} else {157styleStr = styleStr + " Oblique";158}159}160161if (styleStr == null) {162fullName = familyName;163} else {164fullName = familyName + " " + styleStr;165}166167encoding = xlfd.substring(hPos[12]+1);168if (encoding.startsWith("-")) {169encoding = xlfd.substring(hPos[13]+1);170}171if (encoding.indexOf("fontspecific") >= 0) {172if (tmpFamily.indexOf("dingbats") >= 0) {173encoding = "dingbats";174} else if (tmpFamily.indexOf("symbol") >= 0) {175encoding = "symbol";176} else {177encoding = "iso8859-1";178}179}180} else {181throw new FontFormatException("Bad native name " + platName);182// familyName = "Unknown";183// fullName = "Unknown";184// style = Font.PLAIN;185// encoding = "iso8859-1";186}187}188189/* Wildcard all the size fields in the XLFD and retrieve a list of190* XLFD's that match.191* We only look for scaleable fonts, so we can just replace the 0's192* with *'s and see what we get back193* No matches means even the scaleable version wasn't found. This is194* means the X font path isn't set up for this font at all.195* One match means only the scaleable version we started with was found196* -monotype-arial-bold-i-normal--0-0-0-0-p-0-iso8859-1197* Two matches apparently means as well as the above, a scaleable198* specified for 72 dpi is found, not that there are bitmaps : eg199* -monotype-arial-bold-i-normal--0-0-72-72-p-0-iso8859-1200* So require at least 3 matches (no need to parse) to determine that201* there are external bitmaps.202*/203static boolean hasExternalBitmaps(String platName) {204/* Turn -monotype-arial-bold-i-normal--0-0-0-0-p-0-iso8859-1205* into -monotype-arial-bold-i-normal--*-*-*-*-p-*-iso8859-1206* by replacing all -0- substrings with -*-207*/208StringBuilder sb = new StringBuilder(platName);209int pos = sb.indexOf("-0-");210while (pos >=0) {211sb.replace(pos+1, pos+2, "*");212pos = sb.indexOf("-0-", pos);213};214String xlfd = sb.toString();215byte[] bytes = null;216try {217bytes = xlfd.getBytes("UTF-8");218} catch (UnsupportedEncodingException e) {219bytes = xlfd.getBytes();220}221return haveBitmapFonts(bytes);222}223224public static boolean fontExists(String xlfd) {225byte[] bytes = null;226try {227bytes = xlfd.getBytes("UTF-8");228} catch (UnsupportedEncodingException e) {229bytes = xlfd.getBytes();230}231return fontExists(bytes);232}233234private static native boolean haveBitmapFonts(byte[] xlfd);235private static native boolean fontExists(byte[] xlfd);236237public CharToGlyphMapper getMapper() {238if (mapper == null) {239if (isBitmapDelegate) {240/* we are a delegate */241mapper = new NativeGlyphMapper(this);242} else {243/* we need to delegate */244SunFontManager fm = SunFontManager.getInstance();245delegateFont = fm.getDefaultPhysicalFont();246mapper = delegateFont.getMapper();247}248}249return mapper;250}251252FontStrike createStrike(FontStrikeDesc desc) {253if (isBitmapDelegate) {254return new NativeStrike(this, desc);255} else {256if (delegateFont == null) {257SunFontManager fm = SunFontManager.getInstance();258delegateFont = fm.getDefaultPhysicalFont();259}260/* If no FileFont's are found, delegate font may be261* a NativeFont, so we need to avoid recursing here.262*/263if (delegateFont instanceof NativeFont) {264return new NativeStrike((NativeFont)delegateFont, desc);265}266FontStrike delegate = delegateFont.createStrike(desc);267return new DelegateStrike(this, desc, delegate);268}269}270271public Rectangle2D getMaxCharBounds(FontRenderContext frc) {272return null;273}274275native StrikeMetrics getFontMetrics(long pScalerContext);276277native float getGlyphAdvance(long pContext, int glyphCode);278279Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext,280int glyphCode) {281return new Rectangle2D.Float(0f, 0f, 0f, 0f);282}283284public GeneralPath getGlyphOutline(long pScalerContext,285int glyphCode,286float x,287float y) {288return null;289}290291native long getGlyphImage(long pScalerContext, int glyphCode);292293native long getGlyphImageNoDefault(long pScalerContext, int glyphCode);294295void getGlyphMetrics(long pScalerContext, int glyphCode,296Point2D.Float metrics) {297throw new RuntimeException("this should be called on the strike");298}299300public GeneralPath getGlyphVectorOutline(long pScalerContext,301int[] glyphs, int numGlyphs,302float x, float y) {303return null;304}305306private native int countGlyphs(byte[] platformNameBytes, int ptSize);307308public int getNumGlyphs() {309if (numGlyphs == -1) {310byte[] bytes = getPlatformNameBytes(8);311numGlyphs = countGlyphs(bytes, 8);312}313return numGlyphs;314}315316PhysicalFont getDelegateFont() {317if (delegateFont == null) {318SunFontManager fm = SunFontManager.getInstance();319delegateFont = fm.getDefaultPhysicalFont();320}321return delegateFont;322}323324/* Specify that the dpi is 72x72, as this corresponds to JDK's325* default user space. These are the 10th and 11th fields in the XLFD.326* ptSize in XLFD is in 10th's of a point so multiply by 10,327* Replace the 9th field in the XLFD (ie after the 8th hyphen)328* with this pt size (this corresponds to the field that's "%d" in the329* font configuration files). Wild card the other numeric fields.330* ie to request 12 pt Times New Roman italic font, use an XLFD like :331* -monotype-times new roman-regular-i---*-120-72-72-p-*-iso8859-1332*/333byte[] getPlatformNameBytes(int ptSize) {334int[] hPos = new int[14];335int hyphenCnt = 1;336int pos = 1;337338while (pos != -1 && hyphenCnt < 14) {339pos = platName.indexOf('-', pos);340if (pos != -1) {341hPos[hyphenCnt++] = pos;342pos++;343}344}345String sizeStr = Integer.toString((int)Math.abs(ptSize)*10);346StringBuilder sb = new StringBuilder(platName);347/* work backwards so as to not invalidate the positions. */348sb.replace(hPos[11]+1, hPos[12], "*");349350sb.replace(hPos[9]+1, hPos[10], "72");351352sb.replace(hPos[8]+1, hPos[9], "72");353354/* replace the 3 lines above with the next 3 lines to get the 1.4.2355* behaviour356*/357// sb.replace(hPos[11]+1, hPos[12], "0");358// sb.replace(hPos[9]+1, hPos[10], "0");359// sb.replace(hPos[8]+1, hPos[9], "0");360361sb.replace(hPos[7]+1, hPos[8], sizeStr);362363sb.replace(hPos[6]+1, hPos[7], "*");364365/* replace the 1 line above with the next line to get the 1.4.2366* behaviour367*/368// sb.replace(hPos[6]+1, hPos[7], "0");369370/* comment out this block to the the 1.4.2 behaviour */371if (hPos[0] == 0 && hPos[1] == 1) {372/* null foundry name : some linux font configuration files have373* symbol font entries like this and its just plain wrong.374* Replace with a wild card. (Although those fonts should be375* located via disk access rather than X11).376*/377sb.replace(hPos[0]+1, hPos[1], "*");378}379380String xlfd = sb.toString();381byte[] bytes = null;382try {383bytes = xlfd.getBytes("UTF-8");384} catch (UnsupportedEncodingException e) {385bytes = xlfd.getBytes();386}387return bytes;388}389390public String toString() {391return " ** Native Font: Family="+familyName+ " Name="+fullName+392" style="+style+" nativeName="+platName;393}394}395396397