org.eclipse.swt.graphics.FontData.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.swt.graphics.FontData.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2012 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.graphics;

import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.win32.*;
import org.eclipse.swt.*;

/**
 * Instances of this class describe operating system fonts.
 * <p>
 * For platform-independent behaviour, use the get and set methods
 * corresponding to the following properties:
 * <dl>
 * <dt>height</dt><dd>the height of the font in points</dd>
 * <dt>name</dt><dd>the face name of the font, which may include the foundry</dd>
 * <dt>style</dt><dd>A bitwise combination of NORMAL, ITALIC and BOLD</dd>
 * </dl>
 * If extra, platform-dependent functionality is required:
 * <ul>
 * <li>On <em>Windows</em>, the data member of the <code>FontData</code>
 * corresponds to a Windows <code>LOGFONT</code> structure whose fields
 * may be retrieved and modified.</li>
 * <li>On <em>X</em>, the fields of the <code>FontData</code> correspond
 * to the entries in the font's XLFD name and may be retrieved and modified.
 * </ul>
 * Application code does <em>not</em> need to explicitly release the
 * resources managed by each instance when those instances are no longer
 * required, and thus no <code>dispose()</code> method is provided.
 *
 * @see Font
 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
 */
public final class FontData {

    /**
     * A Win32 LOGFONT struct
     * (Warning: This field is platform dependent)
     * <p>
     * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
     * public API. It is marked public only so that it can be shared
     * within the packages provided by SWT. It is not available on all
     * platforms and should never be accessed from application code.
     * </p>
     *
     * @noreference This field is not intended to be referenced by clients.
     */
    public LOGFONT data;

    /**
     * The height of the font data in points
     * (Warning: This field is platform dependent)
     * <p>
     * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
     * public API. It is marked public only so that it can be shared
     * within the packages provided by SWT. It is not available on all
     * platforms and should never be accessed from application code.
     * </p>
     *
     * @noreference This field is not intended to be referenced by clients.
     */
    public float height;

    /**
     * The locales of the font
     */
    String lang, country, variant;

    /**
     * Constructs a new uninitialized font data.
     */
    public FontData() {
        data = new LOGFONT();
        // We set the charset field so that
        // wildcard searching will work properly
        // out of the box
        data.lfCharSet = (byte) OS.DEFAULT_CHARSET;
        height = 12;
    }

    /**
     * Constructs a new font data given the Windows <code>LOGFONT</code>
     * that it should represent.
     *
     * @param data the <code>LOGFONT</code> for the result
     */
    FontData(LOGFONT data, float height) {
        this.data = data;
        this.height = height;
    }

    /**
     * Constructs a new FontData given a string representation
     * in the form generated by the <code>FontData.toString</code>
     * method.
     * <p>
     * Note that the representation varies between platforms,
     * and a FontData can only be created from a string that was
     * generated on the same platform.
     * </p>
     *
     * @param string the string representation of a <code>FontData</code> (must not be null)
     *
     * @exception IllegalArgumentException <ul>
     *    <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
     *    <li>ERROR_INVALID_ARGUMENT - if the argument does not represent a valid description</li>
     * </ul>
     *
     * @see #toString
     */
    public FontData(String string) {
        if (string == null)
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        int start = 0;
        int end = string.indexOf('|');
        if (end == -1)
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        String version1 = string.substring(start, end);
        try {
            if (Integer.parseInt(version1) != 1)
                SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        } catch (NumberFormatException e) {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }

        start = end + 1;
        end = string.indexOf('|', start);
        if (end == -1)
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        String name = string.substring(start, end);

        start = end + 1;
        end = string.indexOf('|', start);
        if (end == -1)
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        float height = 0;
        try {
            height = Float.parseFloat(string.substring(start, end));
        } catch (NumberFormatException e) {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }

        start = end + 1;
        end = string.indexOf('|', start);
        if (end == -1)
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        int style = 0;
        try {
            style = Integer.parseInt(string.substring(start, end));
        } catch (NumberFormatException e) {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }

        start = end + 1;
        end = string.indexOf('|', start);
        data = new LOGFONT();
        data.lfCharSet = (byte) OS.DEFAULT_CHARSET;
        setName(name);
        setHeight(height);
        setStyle(style);
        if (end == -1)
            return;
        String platform = string.substring(start, end);

        start = end + 1;
        end = string.indexOf('|', start);
        if (end == -1)
            return;
        String version2 = string.substring(start, end);

        if (platform.equals("WINDOWS") && version2.equals("1")) { //$NON-NLS-1$//$NON-NLS-2$
            LOGFONT newData = new LOGFONT();
            try {
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfHeight = Integer.parseInt(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfWidth = Integer.parseInt(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfEscapement = Integer.parseInt(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfOrientation = Integer.parseInt(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfWeight = Integer.parseInt(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfItalic = Byte.parseByte(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfUnderline = Byte.parseByte(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfStrikeOut = Byte.parseByte(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfCharSet = Byte.parseByte(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfOutPrecision = Byte.parseByte(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfClipPrecision = Byte.parseByte(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfQuality = Byte.parseByte(string.substring(start, end));
                start = end + 1;
                end = string.indexOf('|', start);
                if (end == -1)
                    return;
                newData.lfPitchAndFamily = Byte.parseByte(string.substring(start, end));
                start = end + 1;
            } catch (NumberFormatException e) {
                setName(name);
                setHeight(height);
                setStyle(style);
                return;
            }
            int length = Math.min(newData.lfFaceName.length - 1, string.length() - start);
            string.getChars(start, start + length, newData.lfFaceName, 0);
            data = newData;
        }
    }

    /**
     * Constructs a new font data given a font name,
     * the height of the desired font in points,
     * and a font style.
     *
     * @param name the name of the font (must not be null)
     * @param height the font height in points
     * @param style a bit or combination of NORMAL, BOLD, ITALIC
     *
     * @exception IllegalArgumentException <ul>
     *    <li>ERROR_NULL_ARGUMENT - when the font name is null</li>
     *    <li>ERROR_INVALID_ARGUMENT - if the height is negative</li>
     * </ul>
     */
    public FontData(String name, int height, int style) {
        if (name == null)
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        data = new LOGFONT();
        setName(name);
        setHeight(height);
        setStyle(style);
        // We set the charset field so that
        // wildcard searching will work properly
        // out of the box
        data.lfCharSet = (byte) OS.DEFAULT_CHARSET;
    }

    /*public*/ FontData(String name, float height, int style) {
        if (name == null)
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        data = new LOGFONT();
        setName(name);
        setHeight(height);
        setStyle(style);
        // We set the charset field so that
        // wildcard searching will work properly
        // out of the box
        data.lfCharSet = (byte) OS.DEFAULT_CHARSET;
    }

    /**
     * Compares the argument to the receiver, and returns true
     * if they represent the <em>same</em> object using a class
     * specific comparison.
     *
     * @param object the object to compare with this object
     * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
     *
     * @see #hashCode
     */
    @Override
    public boolean equals(Object object) {
        if (object == this)
            return true;
        if (!(object instanceof FontData))
            return false;
        FontData fd = (FontData) object;
        LOGFONT lf = fd.data;
        return data.lfCharSet == lf.lfCharSet &&
        /*
        * This code is intentionally commented.  When creating
        * a FontData, lfHeight is not necessarily set.  Instead
        * we check the height field which is always set.
        */
        //      data.lfHeight == lf.lfHeight &&
                height == fd.height && data.lfWidth == lf.lfWidth && data.lfEscapement == lf.lfEscapement
                && data.lfOrientation == lf.lfOrientation && data.lfWeight == lf.lfWeight
                && data.lfItalic == lf.lfItalic && data.lfUnderline == lf.lfUnderline
                && data.lfStrikeOut == lf.lfStrikeOut && data.lfCharSet == lf.lfCharSet
                && data.lfOutPrecision == lf.lfOutPrecision && data.lfClipPrecision == lf.lfClipPrecision
                && data.lfQuality == lf.lfQuality && data.lfPitchAndFamily == lf.lfPitchAndFamily
                && getName().equals(fd.getName());
    }

    long EnumLocalesProc(long lpLocaleString) {

        /* Get the locale ID */
        int length = 8;
        TCHAR buffer = new TCHAR(0, length);
        int byteCount = length * TCHAR.sizeof;
        OS.MoveMemory(buffer, lpLocaleString, byteCount);
        int lcid = Integer.parseInt(buffer.toString(0, buffer.strlen()), 16);

        /* Check the language */
        int size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO639LANGNAME, buffer, length);
        if (size <= 0 || !lang.equals(buffer.toString(0, size - 1)))
            return 1;

        /* Check the country */
        if (country != null) {
            size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO3166CTRYNAME, buffer, length);
            if (size <= 0 || !country.equals(buffer.toString(0, size - 1)))
                return 1;
        }

        /* Get the charset */
        size = OS.GetLocaleInfo(lcid, OS.LOCALE_IDEFAULTANSICODEPAGE, buffer, length);
        if (size <= 0)
            return 1;
        int cp = Integer.parseInt(buffer.toString(0, size - 1));
        int[] lpCs = new int[8];
        OS.TranslateCharsetInfo(cp, lpCs, OS.TCI_SRCCODEPAGE);
        data.lfCharSet = (byte) lpCs[0];

        return 0;
    }

    /**
     * Returns the height of the receiver in points.
     *
     * @return the height of this FontData
     *
     * @see #setHeight(int)
     */
    public int getHeight() {
        return (int) (0.5f + height);
    }

    /*public*/ float getHeightF() {
        return height;
    }

    /**
     * Returns the locale of the receiver.
     * <p>
     * The locale determines which platform character set this
     * font is going to use. Widgets and graphics operations that
     * use this font will convert UNICODE strings to the platform
     * character set of the specified locale.
     * </p>
     * <p>
     * On platforms where there are multiple character sets for a
     * given language/country locale, the variant portion of the
     * locale will determine the character set.
     * </p>
     *
     * @return the <code>String</code> representing a Locale object
     * @since 3.0
     */
    public String getLocale() {
        StringBuilder buffer = new StringBuilder();
        char sep = '_';
        if (lang != null) {
            buffer.append(lang);
            buffer.append(sep);
        }
        if (country != null) {
            buffer.append(country);
            buffer.append(sep);
        }
        if (variant != null) {
            buffer.append(variant);
        }

        String result = buffer.toString();
        int length = result.length();
        if (length > 0) {
            if (result.charAt(length - 1) == sep) {
                result = result.substring(0, length - 1);
            }
        }
        return result;
    }

    /**
     * Returns the name of the receiver.
     * On platforms that support font foundries, the return value will
     * be the foundry followed by a dash ("-") followed by the face name.
     *
     * @return the name of this <code>FontData</code>
     *
     * @see #setName
     */
    public String getName() {
        char[] chars = data.lfFaceName;
        int index = 0;
        while (index < chars.length) {
            if (chars[index] == 0)
                break;
            index++;
        }
        return new String(chars, 0, index);
    }

    /**
     * Returns the style of the receiver which is a bitwise OR of
     * one or more of the <code>SWT</code> constants NORMAL, BOLD
     * and ITALIC.
     *
     * @return the style of this <code>FontData</code>
     *
     * @see #setStyle
     */
    public int getStyle() {
        int style = SWT.NORMAL;
        if (data.lfWeight == 700)
            style |= SWT.BOLD;
        if (data.lfItalic != 0)
            style |= SWT.ITALIC;
        return style;
    }

    /**
     * Returns an integer hash code for the receiver. Any two
     * objects that return <code>true</code> when passed to
     * <code>equals</code> must return the same value for this
     * method.
     *
     * @return the receiver's hash
     *
     * @see #equals
     */
    @Override
    public int hashCode() {
        return data.lfCharSet ^ getHeight() << 8 ^ data.lfWidth ^ data.lfEscapement ^ data.lfOrientation
                ^ data.lfWeight ^ data.lfItalic ^ data.lfUnderline ^ data.lfStrikeOut ^ data.lfCharSet
                ^ data.lfOutPrecision ^ data.lfClipPrecision ^ data.lfQuality ^ data.lfPitchAndFamily
                ^ getName().hashCode();
    }

    /**
     * Sets the height of the receiver. The parameter is
     * specified in terms of points, where a point is one
     * seventy-second of an inch.
     *
     * @param height the height of the <code>FontData</code>
     *
     * @exception IllegalArgumentException <ul>
     *    <li>ERROR_INVALID_ARGUMENT - if the height is negative</li>
     * </ul>
     *
     * @see #getHeight
     */
    public void setHeight(int height) {
        if (height < 0)
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        this.height = height;
        data.lfWidth = 0;
    }

    /*public*/ void setHeight(float height) {
        if (height < 0)
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        this.height = height;
    }

    /**
     * Sets the locale of the receiver.
     * <p>
     * The locale determines which platform character set this
     * font is going to use. Widgets and graphics operations that
     * use this font will convert UNICODE strings to the platform
     * character set of the specified locale.
     * </p>
     * <p>
     * On platforms where there are multiple character sets for a
     * given language/country locale, the variant portion of the
     * locale will determine the character set.
     * </p>
     *
     * @param locale the <code>String</code> representing a Locale object
     * @see java.util.Locale#toString
     */
    public void setLocale(String locale) {
        lang = country = variant = null;
        if (locale != null) {
            char sep = '_';
            int length = locale.length();
            int firstSep, secondSep;

            firstSep = locale.indexOf(sep);
            if (firstSep == -1) {
                firstSep = secondSep = length;
            } else {
                secondSep = locale.indexOf(sep, firstSep + 1);
                if (secondSep == -1)
                    secondSep = length;
            }
            if (firstSep > 0)
                lang = locale.substring(0, firstSep);
            if (secondSep > firstSep + 1)
                country = locale.substring(firstSep + 1, secondSep);
            if (length > secondSep + 1)
                variant = locale.substring(secondSep + 1);
        }
        if (lang == null) {
            data.lfCharSet = (byte) OS.DEFAULT_CHARSET;
        } else {
            Callback callback = new Callback(this, "EnumLocalesProc", 1); //$NON-NLS-1$
            long lpEnumLocalesProc = callback.getAddress();
            if (lpEnumLocalesProc == 0)
                SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
            OS.EnumSystemLocales(lpEnumLocalesProc, OS.LCID_SUPPORTED);
            callback.dispose();
        }
    }

    /**
     * Sets the name of the receiver.
     * <p>
     * Some platforms support font foundries. On these platforms, the name
     * of the font specified in setName() may have one of the following forms:</p>
     * <ol>
     * <li>a face name (for example, "courier")</li>
     * <li>a foundry followed by a dash ("-") followed by a face name (for example, "adobe-courier")</li>
     * </ol>
     * <p>
     * In either case, the name returned from getName() will include the
     * foundry.
     * </p>
     * <p>
     * On platforms that do not support font foundries, only the face name
     * (for example, "courier") is used in <code>setName()</code> and
     * <code>getName()</code>.
     * </p>
     *
     * @param name the name of the font data (must not be null)
     * @exception IllegalArgumentException <ul>
     *    <li>ERROR_NULL_ARGUMENT - when the font name is null</li>
     * </ul>
     *
     * @see #getName
     */
    public void setName(String name) {
        if (name == null)
            SWT.error(SWT.ERROR_NULL_ARGUMENT);

        /* The field lfFaceName must be NULL terminated */
        char[] lfFaceName = data.lfFaceName;
        int length = Math.min(lfFaceName.length - 1, name.length());
        name.getChars(0, length, lfFaceName, 0);
        for (int i = length; i < lfFaceName.length; i++)
            lfFaceName[i] = 0;
    }

    /**
     * Sets the style of the receiver to the argument which must
     * be a bitwise OR of one or more of the <code>SWT</code>
     * constants NORMAL, BOLD and ITALIC.  All other style bits are
     * ignored.
     *
     * @param style the new style for this <code>FontData</code>
     *
     * @see #getStyle
     */
    public void setStyle(int style) {
        if ((style & SWT.BOLD) == SWT.BOLD) {
            data.lfWeight = 700;
        } else {
            data.lfWeight = 0;
        }
        if ((style & SWT.ITALIC) == SWT.ITALIC) {
            data.lfItalic = 1;
        } else {
            data.lfItalic = 0;
        }
    }

    /**
     * Returns a string representation of the receiver which is suitable
     * for constructing an equivalent instance using the
     * <code>FontData(String)</code> constructor.
     *
     * @return a string representation of the FontData
     *
     * @see FontData
     */
    @Override
    public String toString() {
        StringBuilder buffer = new StringBuilder(128);
        buffer.append("1|"); //$NON-NLS-1$
        String name = getName();
        buffer.append(name);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(getHeightF());
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(getStyle());
        buffer.append("|"); //$NON-NLS-1$
        buffer.append("WINDOWS|1|"); //$NON-NLS-1$
        buffer.append(data.lfHeight);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfWidth);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfEscapement);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfOrientation);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfWeight);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfItalic);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfUnderline);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfStrikeOut);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfCharSet);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfOutPrecision);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfClipPrecision);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfQuality);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(data.lfPitchAndFamily);
        buffer.append("|"); //$NON-NLS-1$
        buffer.append(name);
        return buffer.toString();
    }

    /**
     * Invokes platform specific functionality to allocate a new font data.
     * <p>
     * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
     * API for <code>FontData</code>. It is marked public only so that
     * it can be shared within the packages provided by SWT. It is not
     * available on all platforms, and should never be called from
     * application code.
     * </p>
     *
     * @param data the <code>LOGFONT</code> for the font data
     * @param height the height of the font data
     * @return a new font data object containing the specified <code>LOGFONT</code> and height
     *
     * @noreference This method is not intended to be referenced by clients.
     */
    public static FontData win32_new(LOGFONT data, float height) {
        return new FontData(data, height);
    }

}