diff options
Diffstat (limited to 'awt/org/apache/harmony/awt/gl/font/CompositeFont.java')
-rw-r--r-- | awt/org/apache/harmony/awt/gl/font/CompositeFont.java | 486 |
1 files changed, 486 insertions, 0 deletions
diff --git a/awt/org/apache/harmony/awt/gl/font/CompositeFont.java b/awt/org/apache/harmony/awt/gl/font/CompositeFont.java new file mode 100644 index 0000000..70cb334 --- /dev/null +++ b/awt/org/apache/harmony/awt/gl/font/CompositeFont.java @@ -0,0 +1,486 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.awt.gl.font.FontPeerImpl; +import org.apache.harmony.awt.gl.font.FontProperty; + +/** + * CompositeFont class is the implementation of logical font classes. + * Every logical font consists of several physical fonts that described + * in font.properties file according to the face name of this logical font. + */ +public class CompositeFont extends FontPeerImpl{ + + // a number of physical fonts that CompositeFont consist of + int numFonts; + + // font family name + String family; + + // font face name + String face; + + String[] fontNames; + + // an array of font properties applicable to this CompositeFont + FontProperty[] fontProperties; + + // an array of font peers applicable to this CompositeFont + public FontPeerImpl[] fPhysicalFonts; + + // missing glyph code field + int missingGlyphCode = -1; + + // line metrics of this font + LineMetricsImpl nlm = null; + + // cached num glyphs parameter of this font that is the sum of num glyphs of + // font peers composing this font + int cachedNumGlyphs = -1; + /** + * Creates CompositeFont object that is corresponding to the specified logical + * family name. + * + * @param familyName logical family name CompositeFont is to be created from + * @param faceName logical face name CompositeFont is to be created from + * @param _style style of the CompositeFont to be created + * @param _size size of the CompositeFont to be created + * @param fProperties an array of FontProperties describing physical fonts - + * parts of logical font + * @param physFonts an array of physical font peers related to the CompositeFont + * to be created + */ + public CompositeFont(String familyName, String faceName, int _style, int _size, FontProperty[] fProperties, FontPeerImpl[] physFonts){ + this.size = _size; + this.name = faceName; + this.family = familyName; + this.style = _style; + this.face = faceName; + this.psName = faceName; + this.fontProperties = fProperties;// !! Supposed that fProperties parameter != null + fPhysicalFonts = physFonts; + numFonts = fPhysicalFonts.length; + setDefaultLineMetrics("", null); //$NON-NLS-1$ + this.uniformLM = false; + } + + /** + * Returns the index of the FontPeer in array of physical fonts that is applicable + * for the given character. This font has to have the highest priority among fonts + * that can display this character and don't have exclusion range covering + * specified character. If there is no desired fonts -1 is returned. + * + * @param chr specified character + * @return index of the font from the array of physical fonts that will be used + * during processing of the specified character. + */ + public int getCharFontIndex(char chr){ + for (int i = 0; i < numFonts; i++){ + if (fontProperties[i].isCharExcluded(chr)){ + continue; + } + if (fPhysicalFonts[i].canDisplay(chr)){ + return i; + } + } + + return -1; + } + + /** + * Returns the index of the FontPeer in array of physical fonts that is applicable + * for the given character. This font has to have the highest priority among fonts + * that can display this character and don't have exclusion range covering + * specified character. If there is no desired fonts default value is returned. + * + * @param chr specified character + * @param defaultValue default index that is returned if the necessary font couldn't be found. + * @return index of the font from the array of physical fonts that will be used + * during processing of the specified character. + */ + public int getCharFontIndex(char chr, int defaultValue){ + for (int i = 0; i < numFonts; i++){ + if (fontProperties[i].isCharExcluded(chr)){ + continue; + } + if (fPhysicalFonts[i].canDisplay(chr)){ + return i; + } + } + + return defaultValue; + } + + /** + * Returns true if one of the physical fonts composing this font CompositeFont + * can display specified character. + * + * @param chr specified character + */ + @Override + public boolean canDisplay(char chr){ + return (getCharFontIndex(chr) != -1); + } + + /** + * Returns logical ascent (in pixels) + */ + @Override + public int getAscent(){ + return nlm.getLogicalAscent(); + } + + /** + * Returns LineMetrics instance scaled according to the specified transform. + * + * @param str specified String + * @param frc specified FontRenderContext + * @param at specified AffineTransform + */ + @Override + public LineMetrics getLineMetrics(String str, FontRenderContext frc , AffineTransform at){ + LineMetricsImpl lm = (LineMetricsImpl)(this.nlm.clone()); + lm.setNumChars(str.length()); + + if ((at != null) && (!at.isIdentity())){ + lm.scale((float)at.getScaleX(), (float)at.getScaleY()); + } + + return lm; + } + + /** + * Returns cached LineMetrics instance for the null string or creates it if + * it wasn't cached yet. + */ + @Override + public LineMetrics getLineMetrics(){ + if (nlm == null){ + setDefaultLineMetrics("", null); //$NON-NLS-1$ + } + + return this.nlm; + } + + /** + * Creates LineMetrics instance and set cached LineMetrics field to it. + * Created LineMetrics has maximum values of the idividual metrics of all + * composing physical fonts. If there is only one physical font - it's + * LineMetrics object is returned. + * + * @param str specified String + * @param frc specified FontRenderContext + */ + private void setDefaultLineMetrics(String str, FontRenderContext frc){ + LineMetrics lm = fPhysicalFonts[0].getLineMetrics(str, frc, null); + float maxCharWidth = (float)fPhysicalFonts[0].getMaxCharBounds(frc).getWidth(); + + if (numFonts == 1) { + this.nlm = (LineMetricsImpl)lm; + return; + } + + float[] baselineOffsets = lm.getBaselineOffsets(); + int numChars = str.length(); + + // XXX: default value - common for all Fonts + int baseLineIndex = lm.getBaselineIndex(); + + float maxUnderlineThickness = lm.getUnderlineThickness(); + float maxUnderlineOffset = lm.getUnderlineOffset(); + float maxStrikethroughThickness = lm.getStrikethroughThickness(); + float minStrikethroughOffset = lm.getStrikethroughOffset(); + float maxLeading = lm.getLeading(); // External leading + float maxHeight = lm.getHeight(); // Height of the font ( == (ascent + descent + leading)) + float maxAscent = lm.getAscent(); // Ascent of the font + float maxDescent = lm.getDescent(); // Descent of the font + + for (int i = 1; i < numFonts; i++){ + lm = fPhysicalFonts[i].getLineMetrics(str, frc, null); + if (maxUnderlineThickness < lm.getUnderlineThickness()){ + maxUnderlineThickness = lm.getUnderlineThickness(); + } + + if (maxUnderlineOffset < lm.getUnderlineOffset()){ + maxUnderlineOffset = lm.getUnderlineOffset(); + } + + if (maxStrikethroughThickness < lm.getStrikethroughThickness()){ + maxStrikethroughThickness = lm.getStrikethroughThickness(); + } + + if (minStrikethroughOffset > lm.getStrikethroughOffset()){ + minStrikethroughOffset = lm.getStrikethroughOffset(); + } + + if (maxLeading < lm.getLeading()){ + maxLeading = lm.getLeading(); + } + + if (maxAscent < lm.getAscent()){ + maxAscent = lm.getAscent(); + } + + if (maxDescent < lm.getDescent()){ + maxDescent = lm.getDescent(); + } + + float width = (float)fPhysicalFonts[i].getMaxCharBounds(frc).getWidth(); + if(maxCharWidth < width){ + maxCharWidth = width; + } + for (int j =0; j < baselineOffsets.length; j++){ + float[] offsets = lm.getBaselineOffsets(); + if (baselineOffsets[j] > offsets[j]){ + baselineOffsets[j] = offsets[j]; + } + } + + } + maxHeight = maxAscent + maxDescent + maxLeading; + + this.nlm = new LineMetricsImpl( + numChars, + baseLineIndex, + baselineOffsets, + maxUnderlineThickness, + maxUnderlineOffset, + maxStrikethroughThickness, + minStrikethroughOffset, + maxLeading, + maxHeight, + maxAscent, + maxDescent, + maxCharWidth); + + } + + /** + * Returns the number of glyphs in this CompositeFont object. + */ + @Override + public int getNumGlyphs(){ + if (this.cachedNumGlyphs == -1){ + + this.cachedNumGlyphs = 0; + + for (int i = 0; i < numFonts; i++){ + this.cachedNumGlyphs += fPhysicalFonts[i].getNumGlyphs(); + } + } + + return this.cachedNumGlyphs; + } + + /** + * Returns the italic angle of this object. + */ + @Override + public float getItalicAngle(){ + // !! only first physical font used to get this value + return fPhysicalFonts[0].getItalicAngle(); + } + + /** + * Returns rectangle that bounds the specified string in terms of composite line metrics. + * + * @param chars an array of chars + * @param start the initial offset in array of chars + * @param end the end offset in array of chars + * @param frc specified FontRenderContext + */ + public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc){ + + LineMetrics lm = getLineMetrics(); + float minY = -lm.getAscent(); + float minX = 0; + float height = lm.getHeight(); + float width = 0; + + for (int i = start; i < end; i++){ + width += charWidth(chars[i]); + } + + Rectangle2D rect2D = new Rectangle2D.Float(minX, minY, width, height); + return rect2D; + + } + + /** + * Returns maximum rectangle that encloses all maximum char bounds of + * physical fonts composing this CompositeFont. + * + * @param frc specified FontRenderContext + */ + @Override + public Rectangle2D getMaxCharBounds(FontRenderContext frc){ + + Rectangle2D rect2D = fPhysicalFonts[0].getMaxCharBounds(frc); + float minY = (float)rect2D.getY(); + float maxWidth = (float)rect2D.getWidth(); + float maxHeight = (float)rect2D.getHeight(); + if (numFonts == 1){ + return rect2D; + } + + for (int i = 1; i < numFonts; i++){ + if (fPhysicalFonts[i] != null){ + rect2D = fPhysicalFonts[i].getMaxCharBounds(frc); + float y = (float)rect2D.getY(); + float mWidth = (float)rect2D.getWidth(); + float mHeight = (float)rect2D.getHeight(); + if (y < minY){ + minY = y; + } + if (mWidth > maxWidth){ + maxHeight = mWidth; + } + + if (mHeight > maxHeight){ + maxHeight = mHeight; + } + } + } + + rect2D = new Rectangle2D.Float(0, minY, maxWidth, maxHeight); + + return rect2D; + } + + /** + * Returns font name. + */ + @Override + public String getFontName(){ + return face; + } + + /** + * Returns font postscript name. + */ + @Override + public String getPSName(){ + return psName; + } + + /** + * Returns font family name. + */ + @Override + public String getFamily(){ + return family; + } + + /** + * Returns the code of the missing glyph. + */ + @Override + public int getMissingGlyphCode(){ + // !! only first physical font used to get this value + return fPhysicalFonts[0].getMissingGlyphCode(); + } + + /** + * Returns Glyph object corresponding to the specified character. + * + * @param ch specified char + */ + @Override + public Glyph getGlyph(char ch){ + for (int i = 0; i < numFonts; i++){ + if (fontProperties[i].isCharExcluded(ch)){ + continue; + } + + /* Control symbols considered to be supported by the font peer */ + if ((ch < 0x20) || fPhysicalFonts[i].canDisplay(ch)){ + return fPhysicalFonts[i].getGlyph(ch); + } + } + return getDefaultGlyph(); + } + + /** + * Returns width of the char with specified index. + * + * @param ind specified index of the character + */ + @Override + public int charWidth(int ind){ + return charWidth((char)ind); + } + + /** + * Returns width of the specified char. + * + * @param c specified character + */ + @Override + public int charWidth(char c){ + Glyph gl = this.getGlyph(c); + return (int)gl.getGlyphPointMetrics().getAdvanceX(); + } + + /** + * Returns debug information about this class. + */ + @Override + public String toString(){ + return new String(this.getClass().getName() + + "[name=" + this.name + //$NON-NLS-1$ + ",style="+ this.style + //$NON-NLS-1$ + ",fps=" + this.fontProperties + "]"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Returns Glyph object corresponding to the default glyph. + */ + @Override + public Glyph getDefaultGlyph(){ + // !! only first physical font used to get this value + return fPhysicalFonts[0].getDefaultGlyph(); + } + + /** + * Returns FontExtraMetrics object with extra metrics + * related to this CompositeFont. + */ + @Override + public FontExtraMetrics getExtraMetrics(){ + // Returns FontExtraMetrics instanse of the first physical + // Font from the array of fonts. + return fPhysicalFonts[0].getExtraMetrics(); + } + + /** + * Disposes CompositeFont object's resources. + */ + @Override + public void dispose() { + // Nothing to dispose + } +} |