Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/font/FontFamily.java
38829 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.io.File;28import java.awt.Font;29import java.io.IOException;30import java.util.Collection;31import java.util.HashMap;32import java.util.concurrent.ConcurrentHashMap;33import java.util.Locale;3435public class FontFamily {3637private static ConcurrentHashMap<String, FontFamily>38familyNameMap = new ConcurrentHashMap<String, FontFamily>();39private static HashMap<String, FontFamily> allLocaleNames;4041protected String familyName;42protected Font2D plain;43protected Font2D bold;44protected Font2D italic;45protected Font2D bolditalic;46protected boolean logicalFont = false;47protected int familyRank;4849public static FontFamily getFamily(String name) {50return familyNameMap.get(name.toLowerCase(Locale.ENGLISH));51}5253public static String[] getAllFamilyNames() {54return null;55}5657/* Only for use by FontManager.deRegisterBadFont(..).58* If this was the only font in the family, the family is removed59* from the map60*/61static void remove(Font2D font2D) {6263String name = font2D.getFamilyName(Locale.ENGLISH);64FontFamily family = getFamily(name);65if (family == null) {66return;67}68if (family.plain == font2D) {69family.plain = null;70}71if (family.bold == font2D) {72family.bold = null;73}74if (family.italic == font2D) {75family.italic = null;76}77if (family.bolditalic == font2D) {78family.bolditalic = null;79}80if (family.plain == null && family.bold == null &&81family.plain == null && family.bold == null) {82familyNameMap.remove(name);83}84}8586public FontFamily(String name, boolean isLogFont, int rank) {87logicalFont = isLogFont;88familyName = name;89familyRank = rank;90familyNameMap.put(name.toLowerCase(Locale.ENGLISH), this);91}9293/* Create a family for created fonts which aren't listed in the94* main map.95*/96FontFamily(String name) {97logicalFont = false;98familyName = name;99familyRank = Font2D.DEFAULT_RANK;100}101102public String getFamilyName() {103return familyName;104}105106public int getRank() {107return familyRank;108}109110private boolean isFromSameSource(Font2D font) {111if (!(font instanceof FileFont)) {112return false;113}114115FileFont existingFont = null;116if (plain instanceof FileFont) {117existingFont = (FileFont)plain;118} else if (bold instanceof FileFont) {119existingFont = (FileFont)bold;120} else if (italic instanceof FileFont) {121existingFont = (FileFont)italic;122} else if (bolditalic instanceof FileFont) {123existingFont = (FileFont)bolditalic;124}125// A family isn't created until there's a font.126// So if we didn't find a file font it means this127// isn't a file-based family.128if (existingFont == null) {129return false;130}131File existDir = (new File(existingFont.platName)).getParentFile();132133FileFont newFont = (FileFont)font;134File newDir = (new File(newFont.platName)).getParentFile();135if (existDir != null) {136try {137existDir = existDir.getCanonicalFile();138} catch (IOException ignored) {}139}140if (newDir != null) {141try {142newDir = newDir.getCanonicalFile();143} catch (IOException ignored) {}144}145return java.util.Objects.equals(newDir, existDir);146}147148/*149* We want a family to be of the same width and prefer medium/normal width.150* Once we find a particular width we accept more of the same width151* until we find one closer to normal when we 'evict' all existing fonts.152* So once we see a 'normal' width font we evict all members that are not153* normal width and then accept only new ones that are normal width.154*155* Once a font passes the width test we subject it to the weight test.156* For Plain we target the weight the closest that is <= NORMAL (400)157* For Bold we target the weight that is closest to BOLD (700).158*159* In the future, rather than discarding these fonts, we should160* extend the family to include these so lookups on these properties161* can locate them, as presently they will only be located by full name162* based lookup.163*/164165private int familyWidth = 0;166private boolean preferredWidth(Font2D font) {167168int newWidth = font.getWidth();169170if (familyWidth == 0) {171familyWidth = newWidth;172return true;173}174175if (newWidth == familyWidth) {176return true;177}178179if (Math.abs(Font2D.FWIDTH_NORMAL - newWidth) <180Math.abs(Font2D.FWIDTH_NORMAL - familyWidth))181{182if (FontUtilities.debugFonts()) {183FontUtilities.getLogger().info(184"Found more preferred width. New width = " + newWidth +185" Old width = " + familyWidth + " in font " + font +186" nulling out fonts plain: " + plain + " bold: " + bold +187" italic: " + italic + " bolditalic: " + bolditalic);188}189familyWidth = newWidth;190plain = bold = italic = bolditalic = null;191return true;192} else if (FontUtilities.debugFonts()) {193FontUtilities.getLogger().info(194"Family rejecting font " + font +195" of less preferred width " + newWidth);196}197return false;198}199200private boolean closerWeight(Font2D currFont, Font2D font, int style) {201if (familyWidth != font.getWidth()) {202return false;203}204205if (currFont == null) {206return true;207}208209if (FontUtilities.debugFonts()) {210FontUtilities.getLogger().info(211"New weight for style " + style + ". Curr.font=" + currFont +212" New font="+font+" Curr.weight="+ + currFont.getWeight()+213" New weight="+font.getWeight());214}215216int newWeight = font.getWeight();217switch (style) {218case Font.PLAIN:219case Font.ITALIC:220return (newWeight <= Font2D.FWEIGHT_NORMAL &&221newWeight > currFont.getWeight());222223case Font.BOLD:224case Font.BOLD|Font.ITALIC:225return (Math.abs(newWeight - Font2D.FWEIGHT_BOLD) <226Math.abs(currFont.getWeight() - Font2D.FWEIGHT_BOLD));227228default:229return false;230}231}232233public void setFont(Font2D font, int style) {234235if (FontUtilities.isLogging()) {236String msg;237if (font instanceof CompositeFont) {238msg = "Request to add " + font.getFamilyName(null) +239" with style " + style + " to family " + familyName;240} else {241msg = "Request to add " + font +242" with style " + style + " to family " + this;243}244FontUtilities.getLogger().info(msg);245}246/* Allow a lower-rank font only if its a file font247* from the exact same source as any previous font.248*/249if ((font.getRank() > familyRank) && !isFromSameSource(font)) {250if (FontUtilities.isLogging()) {251FontUtilities.getLogger()252.warning("Rejecting adding " + font +253" of lower rank " + font.getRank() +254" to family " + this +255" of rank " + familyRank);256}257return;258}259260switch (style) {261262case Font.PLAIN:263if (preferredWidth(font) && closerWeight(plain, font, style)) {264plain = font;265}266break;267268case Font.BOLD:269if (preferredWidth(font) && closerWeight(bold, font, style)) {270bold = font;271}272break;273274case Font.ITALIC:275if (preferredWidth(font) && closerWeight(italic, font, style)) {276italic = font;277}278break;279280case Font.BOLD|Font.ITALIC:281if (preferredWidth(font) && closerWeight(bolditalic, font, style)) {282bolditalic = font;283}284break;285286default:287break;288}289}290291public Font2D getFontWithExactStyleMatch(int style) {292293switch (style) {294295case Font.PLAIN:296return plain;297298case Font.BOLD:299return bold;300301case Font.ITALIC:302return italic;303304case Font.BOLD|Font.ITALIC:305return bolditalic;306307default:308return null;309}310}311312/* REMIND: if the callers of this method are operating in an313* environment in which not all fonts are registered, the returned314* font may be a algorithmically styled one, where in fact if loadfonts315* were executed, a styled font may be located. Our present "solution"316* to this is to register all fonts in a directory and assume that this317* registered all the styles of a font, since they would all be in the318* same location.319*/320public Font2D getFont(int style) {321322switch (style) {323324case Font.PLAIN:325return plain;326327case Font.BOLD:328if (bold != null) {329return bold;330} else if (plain != null && plain.canDoStyle(style)) {331return plain;332} else {333return null;334}335336case Font.ITALIC:337if (italic != null) {338return italic;339} else if (plain != null && plain.canDoStyle(style)) {340return plain;341} else {342return null;343}344345case Font.BOLD|Font.ITALIC:346if (bolditalic != null) {347return bolditalic;348} else if (bold != null && bold.canDoStyle(style)) {349return bold;350} else if (italic != null && italic.canDoStyle(style)) {351return italic;352} else if (plain != null && plain.canDoStyle(style)) {353return plain;354} else {355return null;356}357default:358return null;359}360}361362/* Only to be called if getFont(style) returns null363* This method will only return null if the family is completely empty!364* Note that it assumes the font of the style you need isn't in the365* family. The logic here is that if we must substitute something366* it might as well be from the same family.367*/368Font2D getClosestStyle(int style) {369370switch (style) {371/* if you ask for a plain font try to return a non-italic one,372* then a italic one, finally a bold italic one */373case Font.PLAIN:374if (bold != null) {375return bold;376} else if (italic != null) {377return italic;378} else {379return bolditalic;380}381382/* if you ask for a bold font try to return a non-italic one,383* then a bold italic one, finally an italic one */384case Font.BOLD:385if (plain != null) {386return plain;387} else if (bolditalic != null) {388return bolditalic;389} else {390return italic;391}392393/* if you ask for a italic font try to return a bold italic one,394* then a plain one, finally an bold one */395case Font.ITALIC:396if (bolditalic != null) {397return bolditalic;398} else if (plain != null) {399return plain;400} else {401return bold;402}403404case Font.BOLD|Font.ITALIC:405if (italic != null) {406return italic;407} else if (bold != null) {408return bold;409} else {410return plain;411}412}413return null;414}415416/* Font may have localized names. Store these in a separate map, so417* that only clients who use these names need be affected.418*/419static synchronized void addLocaleNames(FontFamily family, String[] names){420if (allLocaleNames == null) {421allLocaleNames = new HashMap<String, FontFamily>();422}423for (int i=0; i<names.length; i++) {424allLocaleNames.put(names[i].toLowerCase(), family);425}426}427428public static synchronized FontFamily getLocaleFamily(String name) {429if (allLocaleNames == null) {430return null;431}432return allLocaleNames.get(name.toLowerCase());433}434435public static FontFamily[] getAllFontFamilies() {436Collection<FontFamily> families = familyNameMap.values();437return families.toArray(new FontFamily[0]);438}439440public String toString() {441return442"Font family: " + familyName +443" plain="+plain+444" bold=" + bold +445" italic=" + italic +446" bolditalic=" + bolditalic;447448}449450}451452453