alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (NativeFont.java)

This example Java source code file (NativeFont.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

awt, couldn\'t, font, fontformatexception, fontstrike, generalpath, geometry, italic, nativefont, nativestrike, oblique, physicalfont, string, stringbuilder, sunfontmanager, unsupportedencodingexception, utf\-8, util

The NativeFont.java Java example source code

/*
 * Copyright (c) 2003, 2006, 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.FontFormatException;
import java.awt.GraphicsEnvironment;
import java.awt.font.FontRenderContext;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.util.Locale;

/*
 * Ideally there would be no native fonts used, and this class would be
 * unneeded and removed. Presently it is still needed until such time
 * as font configuration files (or the implementation equivalent) can have
 * all references to fonts that are not handled via Java 2D removed.
 * Currently there are two cases where this class is needed, both on
 * Unix, primarily Solaris, but useful on Linux too if fonts have moved.
 * 1. Some legacy F3 fonts are still referenced so that AWT "X/Motif"
 * can get dingbats and symbols from them. This can be dispensed with when
 * either AWT is based on 2D, or when the X font path is known to always
 * contain a Type1 or TrueType font that can be used in font configuration
 * files to replace the F3 fonts.
 * 2. When location of font files by 2D fails, because of some system
 * configuration problem, it is desirable to have a fall back to some
 * functionality that lessens the immediate impact on users. Being able
 * to perform limited operations by using bitmaps from X11 helps here.
 */

public class NativeFont extends PhysicalFont {

    String encoding;

    private int numGlyphs = -1;
    boolean isBitmapDelegate;
    PhysicalFont delegateFont;

    /**
     * Verifies native font is accessible.
     * @throws FontFormatException - if the font can't be located.
     */
    public NativeFont(String platName, boolean bitmapDelegate)
        throws FontFormatException {
        super(platName, null);

        /* This is set true if this is an instance of a NativeFont
         * created by some other font, to get native bitmaps.
         * The delegating font will call this font only for "basic"
         * cases - ie non-rotated, uniform scale, monochrome bitmaps.
         * If this is false, then this instance may need to itself
         * delegate to another font for non-basic cases. Since
         * NativeFonts are used in that way only for symbol and dingbats
         * we know its safe to delegate these to the JRE's default
         * physical font (Lucida Sans Regular).
         */
        isBitmapDelegate = bitmapDelegate;

        if (GraphicsEnvironment.isHeadless()) {
            throw new FontFormatException("Native font in headless toolkit");
        }
        fontRank = Font2D.NATIVE_RANK;
        initNames();
        if (getNumGlyphs() == 0) {
          throw new FontFormatException("Couldn't locate font" + platName);
        }
    }

    private void initNames() throws FontFormatException {
        /* Valid XLFD has exactly 14 "-" chars.
         * First run over the string to verify have at least this many
         * At the same time record the locations of the hyphens
         * so we can just pick the right substring later on
         */
        int[] hPos = new int[14];
        int hyphenCnt = 1;
        int pos = 1;

        String xlfd = platName.toLowerCase(Locale.ENGLISH);
        if (xlfd.startsWith("-")) {
            while (pos != -1 && hyphenCnt < 14) {
                pos = xlfd.indexOf('-', pos);
                if (pos != -1) {
                    hPos[hyphenCnt++] = pos;
                    pos++;
                }
            }
        }

        if (hyphenCnt == 14 && pos != -1) {

            /* Capitalise words in the Family name */
            String tmpFamily = xlfd.substring(hPos[1]+1, hPos[2]);
            StringBuilder sBuffer = new StringBuilder(tmpFamily);
            char ch = Character.toUpperCase(sBuffer.charAt(0));
            sBuffer.replace(0, 1, String.valueOf(ch));
            for (int i=1;i<sBuffer.length()-1; i++) {
                if (sBuffer.charAt(i) == ' ') {
                    ch = Character.toUpperCase(sBuffer.charAt(i+1));
                    sBuffer.replace(i+1, i+2, String.valueOf(ch));
                }
            }
            familyName = sBuffer.toString();

            String tmpWeight = xlfd.substring(hPos[2]+1, hPos[3]);
            String tmpSlant = xlfd.substring(hPos[3]+1, hPos[4]);

            String styleStr = null;

            if (tmpWeight.indexOf("bold") >= 0 ||
                tmpWeight.indexOf("demi") >= 0) {
                style |= Font.BOLD;
                styleStr = "Bold";
            }

            if (tmpSlant.equals("i") ||
                tmpSlant.indexOf("italic") >= 0) {
                style |= Font.ITALIC;

                if (styleStr == null) {
                    styleStr = "Italic";
                } else {
                    styleStr = styleStr + " Italic";
                }
            }
            else if (tmpSlant.equals("o") ||
                tmpSlant.indexOf("oblique") >= 0) {
                style |= Font.ITALIC;
                if (styleStr == null) {
                    styleStr = "Oblique";
                } else {
                    styleStr = styleStr + " Oblique";
                }
            }

            if (styleStr == null) {
                fullName = familyName;
            } else {
                fullName = familyName + " " + styleStr;
            }

            encoding = xlfd.substring(hPos[12]+1);
            if (encoding.startsWith("-")) {
                encoding = xlfd.substring(hPos[13]+1);
            }
            if (encoding.indexOf("fontspecific") >= 0) {
                if (tmpFamily.indexOf("dingbats") >= 0) {
                    encoding = "dingbats";
                } else if (tmpFamily.indexOf("symbol") >= 0) {
                    encoding = "symbol";
                } else {
                    encoding = "iso8859-1";
                }
            }
        } else {
            throw new FontFormatException("Bad native name " + platName);
//             familyName = "Unknown";
//             fullName = "Unknown";
//             style = Font.PLAIN;
//             encoding = "iso8859-1";
        }
    }

    /* Wildcard all the size fields in the XLFD and retrieve a list of
     * XLFD's that match.
     * We only look for scaleable fonts, so we can just replace the 0's
     * with *'s and see what we get back
     * No matches means even the scaleable version wasn't found. This is
     * means the X font path isn't set up for this font at all.
     * One match means only the scaleable version we started with was found
     * -monotype-arial-bold-i-normal--0-0-0-0-p-0-iso8859-1
     * Two matches apparently means as well as the above, a scaleable
     * specified for 72 dpi is found, not that there are bitmaps : eg
     * -monotype-arial-bold-i-normal--0-0-72-72-p-0-iso8859-1
     * So require at least 3 matches (no need to parse) to determine that
     * there are external bitmaps.
     */
    static boolean hasExternalBitmaps(String platName) {
        /* Turn -monotype-arial-bold-i-normal--0-0-0-0-p-0-iso8859-1
         * into -monotype-arial-bold-i-normal--*-*-*-*-p-*-iso8859-1
         * by replacing all -0- substrings with -*-
         */
        StringBuilder sb = new StringBuilder(platName);
        int pos = sb.indexOf("-0-");
        while (pos >=0) {
            sb.replace(pos+1, pos+2, "*");
            pos = sb.indexOf("-0-", pos);
        };
        String xlfd = sb.toString();
        byte[] bytes = null;
        try {
            bytes = xlfd.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            bytes = xlfd.getBytes();
        }
        return haveBitmapFonts(bytes);
    }

    public static boolean fontExists(String xlfd) {
        byte[] bytes = null;
        try {
            bytes = xlfd.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            bytes = xlfd.getBytes();
        }
        return fontExists(bytes);
    }

    private static native boolean haveBitmapFonts(byte[] xlfd);
    private static native boolean fontExists(byte[] xlfd);

    public CharToGlyphMapper getMapper() {
        if (mapper == null) {
            if (isBitmapDelegate) {
                /* we are a delegate */
                mapper = new NativeGlyphMapper(this);
            } else {
                /* we need to delegate */
                SunFontManager fm = SunFontManager.getInstance();
                delegateFont = fm.getDefaultPhysicalFont();
                mapper = delegateFont.getMapper();
            }
        }
        return mapper;
    }

    FontStrike createStrike(FontStrikeDesc desc) {
        if (isBitmapDelegate) {
            return new NativeStrike(this, desc);
        } else {
            if (delegateFont == null) {
                SunFontManager fm = SunFontManager.getInstance();
                delegateFont = fm.getDefaultPhysicalFont();
            }
            /* If no FileFont's are found, delegate font may be
             * a NativeFont, so we need to avoid recursing here.
             */
            if (delegateFont instanceof NativeFont) {
                return new NativeStrike((NativeFont)delegateFont, desc);
            }
            FontStrike delegate = delegateFont.createStrike(desc);
            return new DelegateStrike(this, desc, delegate);
        }
    }

    public Rectangle2D getMaxCharBounds(FontRenderContext frc) {
            return null;
    }

    native StrikeMetrics getFontMetrics(long pScalerContext);

    native float getGlyphAdvance(long pContext, int glyphCode);

    Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext,
                                            int glyphCode) {
        return new Rectangle2D.Float(0f, 0f, 0f, 0f);
    }

    public GeneralPath getGlyphOutline(long pScalerContext,
                                       int glyphCode,
                                       float x,
                                       float y) {
        return null;
    }

    native long getGlyphImage(long pScalerContext, int glyphCode);

    native long getGlyphImageNoDefault(long pScalerContext, int glyphCode);

    void getGlyphMetrics(long pScalerContext, int glyphCode,
                        Point2D.Float metrics) {
        throw new RuntimeException("this should be called on the strike");
    }

    public  GeneralPath getGlyphVectorOutline(long pScalerContext,
                                              int[] glyphs, int numGlyphs,
                                              float x,  float y) {
        return null;
    }

    private native int countGlyphs(byte[] platformNameBytes, int ptSize);

    public int getNumGlyphs() {
        if (numGlyphs == -1) {
            byte[] bytes = getPlatformNameBytes(8);
            numGlyphs = countGlyphs(bytes, 8);
        }
        return numGlyphs;
    }

    PhysicalFont getDelegateFont() {
        if (delegateFont == null) {
            SunFontManager fm = SunFontManager.getInstance();
            delegateFont = fm.getDefaultPhysicalFont();
        }
        return delegateFont;
    }

    /* Specify that the dpi is 72x72, as this corresponds to JDK's
     * default user space. These are the 10th and 11th fields in the XLFD.
     * ptSize in XLFD is in 10th's of a point so multiply by 10,
     * Replace the 9th field in the XLFD (ie after the 8th hyphen)
     * with this pt size (this corresponds to the field that's "%d" in the
     * font configuration files). Wild card the other numeric fields.
     * ie to request 12 pt Times New Roman italic font, use an XLFD like :
     * -monotype-times new roman-regular-i---*-120-72-72-p-*-iso8859-1
     */
    byte[] getPlatformNameBytes(int ptSize) {
        int[] hPos = new int[14];
        int hyphenCnt = 1;
        int pos = 1;

        while (pos != -1 && hyphenCnt < 14) {
            pos = platName.indexOf('-', pos);
            if (pos != -1) {
                hPos[hyphenCnt++] = pos;
                    pos++;
            }
        }
        String sizeStr = Integer.toString((int)Math.abs(ptSize)*10);
        StringBuilder sb = new StringBuilder(platName);
        /* work backwards so as to not invalidate the positions. */
        sb.replace(hPos[11]+1, hPos[12], "*");

        sb.replace(hPos[9]+1, hPos[10], "72");

        sb.replace(hPos[8]+1, hPos[9], "72");

        /* replace the 3 lines above with the next 3 lines to get the 1.4.2
         * behaviour
         */
//      sb.replace(hPos[11]+1, hPos[12], "0");
//      sb.replace(hPos[9]+1, hPos[10], "0");
//      sb.replace(hPos[8]+1, hPos[9], "0");

        sb.replace(hPos[7]+1, hPos[8], sizeStr);

        sb.replace(hPos[6]+1, hPos[7], "*");

        /* replace the 1 line above with the next line to get the 1.4.2
         * behaviour
         */
//      sb.replace(hPos[6]+1, hPos[7], "0");

        /* comment out this block to the the 1.4.2 behaviour */
        if (hPos[0] == 0 && hPos[1] == 1) {
            /* null foundry name : some linux font configuration files have
             * symbol font entries like this and its just plain wrong.
             * Replace with a wild card. (Although those fonts should be
             * located via disk access rather than X11).
             */
           sb.replace(hPos[0]+1, hPos[1], "*");
        }

        String xlfd = sb.toString();
        byte[] bytes = null;
        try {
            bytes = xlfd.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            bytes = xlfd.getBytes();
        }
        return bytes;
    }

    public String toString() {
        return " ** Native Font: Family="+familyName+ " Name="+fullName+
            " style="+style+" nativeName="+platName;
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java NativeFont.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.