![JAR search and dependency download from the Maven repository](/logo.png)
com.adobe.fontengine.inlineformatting.css20.CSS20FontDatabase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
*
* File: CSSFontDatabase.java
*
*
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2004-2006 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property of
* Adobe Systems Incorporated and its suppliers, if any. The intellectual
* and technical concepts contained herein are proprietary to Adobe Systems
* Incorporated and its suppliers and may be covered by U.S. and Foreign
* Patents, patents in process, and are protected by trade secret or
* copyright law. Dissemination of this information or reproduction of this
* material is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
*/
package com.adobe.fontengine.inlineformatting.css20;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import com.adobe.agl.util.ULocale;
import com.adobe.fontengine.font.Font;
import com.adobe.fontengine.font.FontException;
import com.adobe.fontengine.font.FontLoadingException;
import com.adobe.fontengine.font.InvalidFontException;
import com.adobe.fontengine.font.UnsupportedFontException;
import com.adobe.fontengine.fontmanagement.FontProxy;
import com.adobe.fontengine.fontmanagement.FontResolutionPriority;
import com.adobe.fontengine.fontmanagement.FontSetStack;
import com.adobe.fontengine.fontmanagement.IntelligentResolver;
import com.adobe.fontengine.inlineformatting.FallbackFontSet;
import com.adobe.fontengine.inlineformatting.css20.CSS20Attribute.CSSStretchValue;
import com.adobe.fontengine.inlineformatting.css20.CSS20Attribute.CSSStyleValue;
import com.adobe.fontengine.inlineformatting.css20.CSS20Attribute.CSSVariantValue;
/**
* CSS20FontDatabase
*/
final public class CSS20FontDatabase extends FontSetStack implements CSS20FontSet
{
/* Serialization signature is explicitly set and should be
* incremented on each release to prevent compatibility.
*/
static final long serialVersionUID = 1;
private final FamilyNameNormalizer normalizer;
private final boolean ignoreVariant;
/* The CSSPDF16FontDescription objects are stored in ArrayLists with all of the other fonts that
* share the same name. Each of those ArrayLists is stored in a HashMap with the key
* being the font name.
*/
private HashMap/**/ fontsByFamilyName = new HashMap();
private FontResolutionPriority resolutionPriority = FontResolutionPriority.FIRST;
// Generic font families and the fallback fonts
private ArrayList/**/ serif = new ArrayList();
private ArrayList/**/ sansSerif = new ArrayList();
private ArrayList/**/ monospace = new ArrayList();
private ArrayList/**/ fantasy = new ArrayList();
private ArrayList/**/ cursive = new ArrayList();
private FallbackFontSet fallbackFontSet = new FallbackFontSet ();
public CSS20FontDatabase () {
this (new PassThroughFamilyNameNormalizer (), true);
}
public CSS20FontDatabase (boolean ignoreVariant) {
this (new PassThroughFamilyNameNormalizer (), ignoreVariant);
}
public CSS20FontDatabase (FamilyNameNormalizer normalizer) {
this (normalizer, true);
}
public CSS20FontDatabase(FamilyNameNormalizer normalizer, boolean ignoreVariant) {
if (normalizer == null)
{
normalizer = new PassThroughFamilyNameNormalizer();
}
this.normalizer = normalizer;
this.ignoreVariant = ignoreVariant;
}
/**
* Copy Constructor.
*/
public CSS20FontDatabase(CSS20FontDatabase original)
{
super(original);
this.normalizer = original.normalizer;
this.ignoreVariant = original.ignoreVariant;
this.resolutionPriority = original.resolutionPriority;
this.serif = (ArrayList) original.serif.clone();
this.sansSerif = (ArrayList) original.sansSerif.clone();
this.monospace = (ArrayList) original.monospace.clone();
this.fantasy = (ArrayList) original.fantasy.clone();
this.cursive = (ArrayList) original.cursive.clone();
this.fallbackFontSet = original.fallbackFontSet;
// Must deep copy the HashMap because the CSSFontsWithSameName's can be modified after this.
Set keySet = original.fontsByFamilyName.keySet();
Iterator iter = keySet.iterator();
while (iter.hasNext())
{
Object key = iter.next();
CSSFontsWithSameName fontsByName = new CSSFontsWithSameName((CSSFontsWithSameName) original.fontsByFamilyName.get(key));
this.fontsByFamilyName.put(key, fontsByName);
}
}
public FontResolutionPriority setResolutionPriority(FontResolutionPriority priority)
{
FontResolutionPriority oldPriority = this.resolutionPriority;
this.resolutionPriority = priority;
return oldPriority;
}
public void addFont(Font font) throws InvalidFontException, UnsupportedFontException, FontLoadingException
{
CSS20FontDescription[] fontDesc = font.getCSS20FontDescription();
if (fontDesc == null)
{
throw new InvalidFontException("Font has no CSS20FontDescription", font);
}
for (int i = 0; i < fontDesc.length; i++)
{
FontProxy fontProxy = new FontProxy(fontDesc[i], font);
addFontProxy(fontProxy);
}
}
public void addFont(CSS20FontDescription fontDesc, Font font)
throws InvalidFontException, UnsupportedFontException, FontLoadingException
{
FontProxy fontProxy = new FontProxy(fontDesc, font);
addFontProxy(fontProxy);
}
private boolean addFontProxy(FontProxy fontProxy)
throws InvalidFontException, UnsupportedFontException, FontLoadingException
{
String familyName = normalizer.normalize(((CSS20FontDescription) fontProxy.getFontDescription()).getFamilyName());
CSSFontsWithSameName fontsWithSameName = (CSSFontsWithSameName) fontsByFamilyName.get(familyName);
if (fontsWithSameName == null)
{
fontsWithSameName = new CSSFontsWithSameName();
fontsByFamilyName.put(familyName, fontsWithSameName);
}
boolean added = fontsWithSameName.addFont(fontProxy);
if (added)
{
super.fontAdded(fontProxy);
}
return added;
}
protected void removeFontProxy(FontProxy fontProxy)
{
String familyName = normalizer.normalize(((CSS20FontDescription) fontProxy.getFontDescription()).getFamilyName());
CSSFontsWithSameName fontsWithSameName = (CSSFontsWithSameName) fontsByFamilyName.get(familyName);
if (fontsWithSameName != null)
{
fontsWithSameName.removeFont(fontProxy);
}
}
public boolean isEmpty()
{
return fontsByFamilyName.isEmpty();
}
public void setGenericFont(CSS20GenericFontFamily genericFamily, String[] replacementFontNames)
{
ArrayList genericFamilyList = null;
if (genericFamily == CSS20GenericFontFamily.SERIF)
{
genericFamilyList = this.serif;
}
else if (genericFamily == CSS20GenericFontFamily.SANS_SERIF)
{
genericFamilyList = this.sansSerif;
}
else if (genericFamily == CSS20GenericFontFamily.CURSIVE)
{
genericFamilyList = this.cursive;
}
else if (genericFamily == CSS20GenericFontFamily.FANTASY)
{
genericFamilyList = this.fantasy;
}
else if (genericFamily == CSS20GenericFontFamily.MONOSPACE)
{
genericFamilyList = this.monospace;
} else {
return;
}
genericFamilyList.clear();
genericFamilyList.ensureCapacity(replacementFontNames.length);
for (int i = 0; i < replacementFontNames.length; i++)
{
genericFamilyList.add(i, replacementFontNames[i]);
}
}
public void setFallbackFonts (FallbackFontSet fallbackFontSet) {
this.fallbackFontSet = fallbackFontSet;
}
protected List getGenericFont(CSS20GenericFontFamily genericFamily)
{
if (genericFamily == CSS20GenericFontFamily.SERIF)
{
return this.serif;
}
else if (genericFamily == CSS20GenericFontFamily.SANS_SERIF)
{
return this.sansSerif;
}
else if (genericFamily == CSS20GenericFontFamily.CURSIVE)
{
return this.cursive;
}
else if (genericFamily == CSS20GenericFontFamily.FANTASY)
{
return this.fantasy;
}
else if (genericFamily == CSS20GenericFontFamily.MONOSPACE)
{
return this.monospace;
}
return null;
}
protected FallbackFontSet getFallbackFontSet () {
return fallbackFontSet;
}
protected boolean replaceGenericFontFamily(List fontFamilyNames)
{
boolean foundGenerics = false;
for (int i = 0; i < fontFamilyNames.size(); i++)
{
String fontName = (String) fontFamilyNames.get(i);
if (fontName.equals("serif"))
{
List serif = getGenericFont(CSS20GenericFontFamily.SERIF);
fontFamilyNames.remove(i);
if (serif != null)
{
fontFamilyNames.addAll(i, serif);
foundGenerics = true;
}
} else if (fontName.equals("sans-serif"))
{
List sansSerif = getGenericFont(CSS20GenericFontFamily.SANS_SERIF);
fontFamilyNames.remove(i);
if (sansSerif != null)
{
fontFamilyNames.addAll(i, sansSerif);
foundGenerics = true;
}
} else if (fontName.equals("cursive"))
{
List cursive = getGenericFont(CSS20GenericFontFamily.CURSIVE);
fontFamilyNames.remove(i);
if (cursive != null)
{
fontFamilyNames.addAll(i, cursive);
foundGenerics = true;
}
} else if (fontName.equals("fantasy"))
{
List fantasy = getGenericFont(CSS20GenericFontFamily.FANTASY);
fontFamilyNames.remove(i);
if (fantasy != null)
{
fontFamilyNames.addAll(i, fantasy);
foundGenerics = true;
}
} else if (fontName.equals("monospace"))
{
List monospace = getGenericFont(CSS20GenericFontFamily.MONOSPACE);
fontFamilyNames.remove(i);
if (monospace != null)
{
fontFamilyNames.addAll(i, monospace);
foundGenerics = true;
}
}
}
return foundGenerics;
}
protected Font[] findFont(String familyName, CSS20Attribute attributes)
{
Font[] foundFonts = null;
CSSFontsWithSameName fontsWithSameName = (CSSFontsWithSameName) fontsByFamilyName.get(normalizer.normalize(familyName));
if (fontsWithSameName != null)
{
foundFonts = fontsWithSameName.findFont(attributes);
} // if (fontsWithSameName != null)
return foundFonts;
}
public Font findFont(CSS20Attribute attributes, ULocale locale)
throws FontException
{
// First - search using the family list
// These are font names and need to be matched
List fontFamilyList = attributes.getFamilyNamesList ();
replaceGenericFontFamily (fontFamilyList);
for (int i = 0; i < fontFamilyList.size(); i++) {
String familyName = (String) fontFamilyList.get (i);
Font[] proposedFonts = findFont(familyName, attributes);
if (proposedFonts != null) {
return proposedFonts[0]; }}
// Second, if no font selected, use fallback fonts
Iterator it = getFallbackFontSet ().getFallbackFonts(locale);
if (it.hasNext ()) {
return (Font) it.next (); }
return null;
}
final class CSSFontsWithSameName implements Serializable
{
/* Serialization signature is explicitly set and should be
* incremented on each release to prevent compatibility.
*/
static final long serialVersionUID = 1;
// Store the fonts in a multi-dimensional array of ArrayLists
// first dimension = Variant
// 0 = NORMAL
// 1 = SMALL-CAPS
// second dimension = Style
// 0 = NORMAL
// 1 = OBLIQUE
// 2 = ITALIC
private ArrayList/**/[][] fonts = new ArrayList[2][3];
private static final int kVariantNormal = 0;
private static final int kVariantSmallCaps = 1;
private static final int kVariantSize = 2;
private static final int kStyleNormal = 0;
private static final int kStyleOblique = 1;
private static final int kStyleItalic = 2;
private static final int kStyleSize = 3;
protected CSSFontsWithSameName()
{
}
protected CSSFontsWithSameName(CSSFontsWithSameName original)
{
// Clone all the contained objects
for (int i = 0; i < kVariantSize; i++)
{
for (int j = 0; j < kStyleSize; j++)
{
if (original.fonts[i][j] != null)
{
this.fonts[i][j] = (ArrayList) original.fonts[i][j].clone();
}
}
}
}
protected boolean addFont(FontProxy fontProxy)
throws InvalidFontException, UnsupportedFontException, FontLoadingException
{
CSS20FontDescription fontDesc = (CSS20FontDescription) fontProxy.getFontDescription();
ArrayList fontList = this.pickStyleVariantList(fontDesc.getVariant(),
fontDesc.getStyle(), true /* create if null */);
return insertFontInList(fontList, fontProxy);
}
protected boolean insertFontInList(ArrayList fontList, FontProxy fontProxy)
throws InvalidFontException, UnsupportedFontException, FontLoadingException
{
boolean wasAdded = true;
// if the list is empty just add it
if (fontList.size() == 0)
{
fontList.add(fontProxy);
}
CSS20FontDescription fontDesc = (CSS20FontDescription) fontProxy.getFontDescription();
int[] bounds = new int[2];
bounds[0] = 0;
bounds[1] = fontList.size();
this.findWeightRange(fontDesc.getWeight(), fontList, bounds);
int foundWeight = ((CSS20FontDescription) ((FontProxy) fontList.get(bounds[0])).getFontDescription()).getWeight();
if (fontDesc.getWeight() < foundWeight)
{
// nothing at the desired weight and the new font weight is lower
fontList.add(bounds[0], fontProxy);
}
else if (fontDesc.getWeight() > foundWeight)
{
// nothing at the desired weight and the new font weight is higher
fontList.add(bounds[1], fontProxy);
}
else
{
// fonts found at the desired weight - now need to find stretch
this.findStretchRange(fontDesc.getStretch(), fontList, bounds);
int foundStretch = ((CSS20FontDescription) ((FontProxy) fontList.get(bounds[0])).getFontDescription()).getStretch().getValue();
if (fontDesc.getStretch().getValue() < foundStretch)
{
// nothing at the desired stretch and the new font stretch is lower
fontList.add(bounds[0], fontProxy);
}
else if (fontDesc.getStretch().getValue() > foundStretch)
{
// nothing at the desired stretch and the new font stretch is higher
fontList.add(bounds[1], fontProxy);
}
else
{
// fonts found at the desired stretch - now need to find point size
if (resolutionPriority == FontResolutionPriority.LAST)
{
// add to the front of the list
fontList.add(bounds[0], fontProxy);
} else if (resolutionPriority == FontResolutionPriority.FIRST)
{
// add to the end of the list.
fontList.add(bounds[1], fontProxy);
} else {
Font fontInList = ((FontProxy) fontList.get(bounds[0])).getFont();
Font preferred =
IntelligentResolver.choosePreferredFont(fontInList, fontProxy.getFont(),
resolutionPriority == FontResolutionPriority.INTELLIGENT_FIRST);
if (preferred == fontInList)
{
fontList.add(bounds[1], fontProxy);
} else {
fontList.add(bounds[0], fontProxy);
}
}
}
}
return wasAdded;
}
/**
* This method implements the weight selection portion of the basic CSS font selection algorithm.
* It operates on a list that is sorted by weight and in which there may be multiple fonts with
* the same weight. It returns the bounds of the fonts that meet the CSS weight selection without
* requiring that the CSS weights be pre-filled and in a single pass. To do this it uses a somewhat
* complex set of conditionals. These statements implement the two tables given below.
*
* Variables/Contants Used in the Tables
*
* boundaryWeight
- the weight above which unresolved weights should move "upwards"
* searchWeight
- the weight value that is specified in the search
* currentWeight
- the weight value of the current entry as the list is iterated over
* bandWeight
- the weight of the potentially matching "band" of values
* lowerBandIndex
- the lower index of the "band"
* upperBandIndex
- the current upper index of the "band"
*
*
*
*
* Main Decision Table Used on Each Iteration through List
*
*
*
*
*
*
* currentWeight == bandWeight
*
*
* currentWeight > bandWeight
*
*
* currentWeight < bandWeight
*
*
*
*
*
* currentWeight == searchWeight
*
*
* upperBandIndex = currentIndex
*
*
* upperBandIndex = currentIndex
*
lowerBandIndex = currentIndex
*
bandWeight = currentWeight
*
*
* ERROR CONDITION
*
shouldn't happen
*
*
*
*
*
* currentWeight < searchWeight
*
*
* upperBandIndex = currentIndex
*
*
* upperBandIndex = currentIndex
*
lowerBandIndex = currentIndex
*
bandWeight = currentWeight
*
*
* ERROR CONDITION
*
shouldn't happen
*
*
*
*
*
* currentWeight > searchWeight
*
*
* upperBandIndex = currentIndex
*
*
* secondary table
*
see below
*
*
* ERROR CONDITION
*
shouldn't happen
*
*
*
*
*
*
*
* Secondary Decision Table Used Only IF Condition Above Met
*
*
*
*
*
*
* bandWeight == 0
*
*
* bandWeight != 0
&& bandWeight < searchWeight
*
*
* bandWeight != 0
&& bandWeight >= searchWeight
*
*
*
*
*
* searchWeight <= boundaryWeight
*
*
* upperBandIndex = currentIndex
*
lowerBandIndex = currentIndex
*
bandWeight = currentWeight
*
*
* break;
*
*
* break;
*
*
*
*
*
* searchWeight > boundaryWeight
*
*
* upperBandIndex = currentIndex
*
lowerBandIndex = currentIndex
*
bandWeight = currentWeight
*
*
* upperBandIndex = currentIndex
*
lowerBandIndex = currentIndex
*
bandWeight = currentWeight
*
*
* break;
*
*
*
*
* @param searchWeight the weight to search for
* @param fontList the list of fonts to search through
* @param bounds the bounds of the search range (low - inclusive, high - exclusive)
* @return the index of the preferred font in the range
*/
protected int findWeightRange (int searchWeight, ArrayList fontList, int[] bounds)
{
int bandWeight = 0;
int[] bandBounds = {bounds[0], bounds[0]};
// First find the weight range
for (int i = bounds[0]; i < bounds[1]; i++)
{
FontProxy currentFontProxy = (FontProxy) fontList.get(i);
CSS20FontDescription currentFontDescription = (CSS20FontDescription) currentFontProxy.getFontDescription();
int currentWeight = currentFontDescription.getWeight();
// See the table above to understand the code below
// This set of nested if's implements the table(s)
if (currentWeight == bandWeight)
{
// still in the same band - raise the upper bound
bandBounds[1] = i;
}
else if (currentWeight > bandWeight)
{
if (currentWeight <= searchWeight)
{
// reset the band bounds
bandBounds[0] = i;
bandBounds[1] = i;
bandWeight = currentWeight;
}
else
{
if (bandWeight == 0)
{
// reset the band bounds
bandBounds[0] = i;
bandBounds[1] = i;
bandWeight = currentWeight;
} else {
if (searchWeight <= CSS20Attribute.CSSWeightValue.W500.getValue())
{
// have our band - no need to keep searching
break;
} else {
if (bandWeight < searchWeight)
{
// reset the band bounds
bandBounds[0] = i;
bandBounds[1] = i;
bandWeight = currentWeight;
} else {
// have our band - no need to keep searching
break;
}
}
}
}
}
// This should never occur
// else if (currentWeight < bandWeight)
// {
// throw new FormattingException("Impossible condition in the matching of font weights");
// }
}
bounds[0] = bandBounds[0];
bounds[1] = bandBounds[1] + 1;
return bounds[0];
}
/**
* This method implements the stretch search portion of the simple CSS font search algorithm.
* It is quite similar to the weight search algorithm and a fuller description of the algorithm is
* available there.
* @param stretch the stretch to search for
* @param fontList the list of fonts to search through
* @param bounds the bounds of the search range (low - inclusive, high - exclusive)
* @return the index of the preferred font in the range
*
* @see com.adobe.fontengine.inlineformatting.css20.CSS20FontDatabase.CSSFontsWithSameName#findWeightRange(int, ArrayList, int[])
*/
protected int findStretchRange (CSSStretchValue stretch, ArrayList fontList, int[] bounds)
{
int bandStretch = 0;
int[] bandBounds = {bounds[0], bounds[0]};
int searchStretch = stretch.getValue();;
// First find the stretch range
for (int i = bounds[0]; i < bounds[1]; i++)
{
FontProxy currentFontProxy = (FontProxy) fontList.get(i);
CSS20FontDescription currentFontDescription = (CSS20FontDescription) currentFontProxy.getFontDescription();
int currentStretch = currentFontDescription.getStretch().getValue();
// See the table above to understand the code below
// This set of nested if's implements the table(s)
if (currentStretch == bandStretch)
{
// still in the same band - raise the upper bound
bandBounds[1] = i;
}
else if (currentStretch > bandStretch)
{
if (currentStretch <= searchStretch)
{
// reset the band bounds
bandBounds[0] = i;
bandBounds[1] = i;
bandStretch = currentStretch;
}
else
{
if (bandStretch == 0)
{
// reset the band bounds
bandBounds[0] = i;
bandBounds[1] = i;
bandStretch = currentStretch;
} else {
if (searchStretch <= CSS20Attribute.CSSStretchValue.NORMAL.getValue())
{
// have our band - no need to keep searching
break;
} else {
if (bandStretch < searchStretch)
{
// reset the band bounds
bandBounds[0] = i;
bandBounds[1] = i;
bandStretch = currentStretch;
} else {
// have our band - no need to keep searching
break;
}
}
}
}
}
// This should never occur
// else if (currentStretch < bandStretch)
// {
// throw new FormattingException("Impossible condition in the matching of font stretches");
// }
}
bounds[0] = bandBounds[0];
bounds[1] = bandBounds[1] + 1;
return bounds[0];
}
protected int findOpticalSize(double pointSize, ArrayList fontList, int[] bounds)
{
for (int i = bounds[0]; i < bounds[1]; i++)
{
FontProxy currentFontProxy = (FontProxy) fontList.get(i);
CSS20FontDescription currentFontDescription = (CSS20FontDescription) currentFontProxy.getFontDescription();
double lowPointSize = currentFontDescription.getLowPointSize();
double highPointSize = currentFontDescription.getHighPointSize();
if (pointSize >= lowPointSize && pointSize < highPointSize)
{
return i;
}
}
return bounds[0];
}
protected Font[] findFont(CSS20Attribute attributes)
{
ArrayList fontList = pickStyleVariantList(attributes.getVariant(),
attributes.getStyle(), false /*dont create*/);
Font[] foundFonts = null;
if (fontList != null)
{
int foundFontIndex = 0;
int[] bounds = { 0, fontList.size() };
this.findWeightRange(attributes.getWeight(), fontList, bounds);
this.findStretchRange(attributes.getStretch(), fontList,bounds);
foundFontIndex = this.findOpticalSize(attributes.getOpticalSize(), fontList, bounds);
foundFonts = new Font[bounds[1] - bounds[0]];
for (int i = 0; i < foundFonts.length; i++)
{
foundFonts[i] = ((FontProxy) fontList.get(foundFontIndex)).getFont();
foundFontIndex = (++foundFontIndex == bounds[1]) ? bounds[0] : foundFontIndex;
}
}
return foundFonts;
}
protected void removeFont(FontProxy fontProxy)
{
CSS20FontDescription fontDesc = (CSS20FontDescription) fontProxy.getFontDescription();
ArrayList fontList = this.pickStyleVariantList(fontDesc.getVariant(),
fontDesc.getStyle(), true /* create if null */);
Iterator iter = fontList.iterator();
while(iter.hasNext())
{
FontProxy currentFontProxy = (FontProxy) iter.next();
if (fontProxy == currentFontProxy)
{
iter.remove();
break;
}
}
}
private ArrayList pickStyleVariantList(CSSVariantValue variant, CSSStyleValue style, boolean createIfNull)
{
int variantIndex, styleIndex;
if (variant == CSSVariantValue.NORMAL || ignoreVariant)
{
variantIndex = kVariantNormal;
} else {
// Must be Small-Caps
variantIndex = kVariantSmallCaps;
}
if (style == CSSStyleValue.NORMAL)
{
styleIndex = kStyleNormal;
}
else if (style == CSSStyleValue.OBLIQUE)
{
styleIndex = kStyleOblique;
} else {
// Must be Italic
styleIndex = kStyleItalic;
}
if (createIfNull && fonts[variantIndex][styleIndex] == null)
{
fonts[variantIndex][styleIndex] = new ArrayList();
}
return fonts[variantIndex][styleIndex];
}
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (this == obj)
{
return true;
}
if (! (obj instanceof CSSFontsWithSameName))
{
return false;
}
CSSFontsWithSameName o = (CSSFontsWithSameName)obj;
for (int i = 0; i < kVariantSize; i++)
{
for (int j = 0; j < kStyleSize; j++)
{
if (this.fonts[i][j] != null)
{
if (!this.fonts[i][j].equals(o.fonts[i][j]))
{
return false;
}
} else {
if (o.fonts[i][j] != null) {
return false;
}
}
}
}
return true;
}
public int hashCode()
{
int hashCode = 0;
for (int i = 0; i < kVariantSize; i++)
{
for (int j = 0; j < kStyleSize; j++)
{
if (fonts[i][j] != null)
{
hashCode ^= fonts[i][j].hashCode();
}
}
}
return hashCode;
}
public String toString()
{
TreeMap tempMap = new TreeMap();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < fonts.length; i++) {
for (int j = 0; j < fonts [i].length; j++) {
if (fonts [i][j] != null) {
for (Iterator it = fonts[i][j].iterator(); it.hasNext(); ) {
String name = it.next().toString();
int count = 0;
if (tempMap.containsKey(name)) {
count = ((Integer)tempMap.get(name)).intValue();
}
tempMap.put(name, new Integer(++count));
}
}
}
}
for (Iterator it = tempMap.keySet().iterator(); it.hasNext(); ) {
String name = (String)it.next();
int count = ((Integer)tempMap.get(name)).intValue();
while (count-- > 0) {
sb.append(name);
sb.append("\n");
}
}
return sb.toString();
}
}
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (obj == this)
{
return true;
}
if (! (obj instanceof CSS20FontDatabase))
{
return false;
}
CSS20FontDatabase o = (CSS20FontDatabase)obj;
return this.fontsByFamilyName.equals (o.fontsByFamilyName)
&& this.serif.equals(o.serif)
&& this.sansSerif.equals(o.sansSerif)
&& this.monospace.equals(o.monospace)
&& this.fantasy.equals(o.fantasy)
&& this.cursive.equals (o.cursive)
&& this.fallbackFontSet.equals (o.fallbackFontSet);
}
public int hashCode()
{
int hashCode = 0;
int hashCode1 = this.fontsByFamilyName.hashCode();
int hashCode2 = this.serif.hashCode();
int hashCode3 = this.sansSerif.hashCode();
int hashCode4 = this.monospace.hashCode();
int hashCode5 = this.fantasy.hashCode();
int hashCode6 = this.cursive.hashCode();
int hashCode7 = this.fallbackFontSet.hashCode();
hashCode = hashCode1 ^ hashCode2 ^ hashCode3 ^ hashCode4 ^ hashCode5 ^ hashCode6 ^ hashCode7;
return hashCode;
}
public String toString()
{
TreeSet tempSet = new TreeSet();
for (Iterator it = fontsByFamilyName.keySet().iterator(); it.hasNext(); ) {
tempSet.add(it.next());
}
StringBuffer sb = new StringBuffer();
sb.append("family names:\n");
for (Iterator it = tempSet.iterator(); it.hasNext(); ) {
String k = (String)it.next();
sb.append(" ");
sb.append(k);
sb.append(" = ");
sb.append(fontsByFamilyName.get(k).toString());
sb.append("\n");
}
sb.append("generic names:\n");
toString(sb, "serif", serif);
toString(sb, "sans", sansSerif);
toString(sb, "mono", monospace);
toString(sb, "fantasy", fantasy);
toString(sb, "cursive", cursive);
sb.append("fallback fonts:\n");
sb.append(fallbackFontSet.toString());
return sb.toString();
}
protected void toString(StringBuffer sb, String key, ArrayList al)
{
TreeMap tempMap = new TreeMap();
for (Iterator it = al.iterator(); it.hasNext(); ) {
String name = (String)it.next();
int count = 0;
if (tempMap.containsKey(name)) {
count = ((Integer)tempMap.get(name)).intValue();
}
tempMap.put(name, new Integer(++count));
}
sb.append(" ");
sb.append(key);
sb.append(" = {");
String prefix = "'";
for (Iterator it = tempMap.keySet().iterator(); it.hasNext(); ) {
String name = (String)it.next();
int count = ((Integer)tempMap.get(name)).intValue();
while (count-- > 0) {
sb.append(prefix);
sb.append("'");
sb.append(name);
sb.append("'");
prefix = ", ";
}
}
sb.append("}\n");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy