/*
* 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 java.util.Arrays;
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;
/**
* 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;
}
}