/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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 Lesser General Public License for more details.
*
* Copyright (c) 2006 - 2013 Pentaho Corporation and Contributors. All rights reserved.
*/
package org.pentaho.reporting.libraries.fonts.itext;
import com.lowagie.text.pdf.BaseFont;
import org.pentaho.reporting.libraries.fonts.LibFontsDefaults;
import org.pentaho.reporting.libraries.fonts.encoding.CodePointUtilities;
import org.pentaho.reporting.libraries.fonts.registry.BaselineInfo;
import org.pentaho.reporting.libraries.fonts.registry.FontMetrics;
import org.pentaho.reporting.libraries.fonts.registry.FontNativeContext;
import org.pentaho.reporting.libraries.fonts.tools.FontStrictGeomUtility;
import java.util.Arrays;
/**
* Creation-Date: 22.07.2007, 19:04:00
*
* @author Thomas Morgner
*/
public class BaseFontFontMetrics implements FontMetrics {
private BaseFont baseFont;
private float size;
private long xHeight;
private char[] cpBuffer;
private long[] cachedWidths;
private long ascent;
private long descent;
private long leading;
private long sizeScaled;
private long italicsAngle;
private long maxAscent;
private long maxDescent;
private long maxCharAdvance;
private boolean trueTypeFont;
private transient BaselineInfo cachedBaselineInfo;
private FontNativeContext record;
public BaseFontFontMetrics( final FontNativeContext record, final BaseFont baseFont, final float size ) {
if ( baseFont == null ) {
throw new NullPointerException( "BaseFont is invalid." );
}
this.record = record;
this.baseFont = baseFont;
this.size = size;
this.cpBuffer = new char[ 4 ];
this.cachedWidths = new long[ 256 - 32 ];
Arrays.fill( cachedWidths, -1 );
sizeScaled = FontStrictGeomUtility.toInternalValue( size );
this.ascent = (long) baseFont.getFontDescriptor( BaseFont.AWT_ASCENT, sizeScaled );
this.descent = (long) -baseFont.getFontDescriptor( BaseFont.AWT_DESCENT, sizeScaled );
this.leading = (long) baseFont.getFontDescriptor( BaseFont.AWT_LEADING, sizeScaled );
italicsAngle = FontStrictGeomUtility.toInternalValue( baseFont.getFontDescriptor( BaseFont.ITALICANGLE, size ) );
maxAscent = (long) baseFont.getFontDescriptor( BaseFont.BBOXURY, sizeScaled );
maxDescent = (long) -baseFont.getFontDescriptor( BaseFont.BBOXLLY, sizeScaled );
maxCharAdvance = (long) baseFont.getFontDescriptor( BaseFont.AWT_MAXADVANCE, sizeScaled );
final int[] charBBox = this.baseFont.getCharBBox( 'x' );
if ( charBBox != null ) {
this.xHeight = (long) ( charBBox[ 3 ] * size );
}
if ( this.xHeight == 0 ) {
this.xHeight = getAscent() / 2;
}
this.trueTypeFont = baseFont.getFontType() == BaseFont.FONT_TYPE_TT ||
baseFont.getFontType() == BaseFont.FONT_TYPE_TTUNI;
}
public boolean isTrueTypeFont() {
return trueTypeFont;
}
public long getAscent() {
return ascent;
}
public long getDescent() {
return descent;
}
public long getLeading() {
return leading;
}
public long getXHeight() {
return xHeight;
}
public long getOverlinePosition() {
return getLeading() - Math.max( 1000, sizeScaled / 20 );
}
public long getUnderlinePosition() {
return ( getLeading() + getMaxAscent() ) + Math.max( 1000, sizeScaled / 20 );
}
public long getStrikeThroughPosition() {
return getMaxAscent() - (long) ( LibFontsDefaults.DEFAULT_STRIKETHROUGH_POSITION * getXHeight() );
}
public long getItalicAngle() {
return italicsAngle;
}
public long getMaxAscent() {
return maxAscent;
}
public long getMaxDescent() {
return maxDescent;
}
public long getMaxHeight() {
return getMaxAscent() + getMaxDescent() + getLeading();
}
public long getMaxCharAdvance() {
return maxCharAdvance;
}
public long getCharWidth( final int character ) {
if ( character >= 32 && character < 256 ) {
// can be cached ..
final int index = character - 32;
final long cachedWidth = cachedWidths[ index ];
if ( cachedWidth >= 0 ) {
return cachedWidth;
}
final int retval = CodePointUtilities.toChars( character, cpBuffer, 0 );
if ( retval == 1 ) {
final char char1 = cpBuffer[ 0 ];
if ( char1 < 128 || ( char1 >= 160 && char1 <= 255 ) ) {
final long width = (long) ( baseFont.getWidth( char1 ) * size );
cachedWidths[ index ] = width;
return width;
}
} else if ( retval < 1 ) {
cachedWidths[ index ] = 0;
return 0;
}
final long width = (long) ( baseFont.getWidth( new String( cpBuffer, 0, retval ) ) * size );
cachedWidths[ index ] = width;
return width;
}
final int retval = CodePointUtilities.toChars( character, cpBuffer, 0 );
if ( retval == 1 ) {
final char char1 = cpBuffer[ 0 ];
if ( char1 < 128 || ( char1 >= 160 && char1 <= 255 ) ) {
return (long) ( baseFont.getWidth( char1 ) * size );
}
} else if ( retval < 1 ) {
return 0;
}
return (long) ( baseFont.getWidth( new String( cpBuffer, 0, retval ) ) * size );
}
public long getKerning( final int previous, final int codePoint ) {
return (long) ( size * baseFont.getKerning( (char) previous, (char) codePoint ) );
}
/**
* Is it guaranteed that the font always returns the same baseline info objct?
*
* @return true, if the baseline info in question is always the same, false otherwise.
*/
public boolean isUniformFontMetrics() {
return true;
}
public BaselineInfo getBaselines( final int c, BaselineInfo info ) {
if ( cachedBaselineInfo != null ) {
if ( info == null ) {
info = new BaselineInfo();
}
info.update( cachedBaselineInfo );
return info;
}
if ( info == null ) {
info = new BaselineInfo();
}
// If we had more data, we could surely create something better. Well, this has to be enough ..
final long maxAscent = getMaxAscent();
info.setBaseline( BaselineInfo.MATHEMATICAL, maxAscent - getXHeight() );
info.setBaseline( BaselineInfo.IDEOGRAPHIC, getMaxHeight() );
info.setBaseline( BaselineInfo.MIDDLE, maxAscent / 2 );
info.setBaseline( BaselineInfo.ALPHABETIC, maxAscent );
info.setBaseline( BaselineInfo.CENTRAL, maxAscent / 2 );
info.setBaseline( BaselineInfo.HANGING, maxAscent - getXHeight() );
info.setDominantBaseline( BaselineInfo.ALPHABETIC );
final BaselineInfo cached = new BaselineInfo();
cached.update( info );
cachedBaselineInfo = cached;
return info;
}
public BaseFont getBaseFont() {
return baseFont;
}
public FontNativeContext getNativeContext() {
return record;
}
}