blob: 5d169eb71a89b1e45d04a3e434d1ec51e0285ecf [file] [log] [blame]
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.font;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.security.AccessController;
import java.security.PrivilegedAction;
// Right now this class is final to avoid a problem with native code.
// For some reason the JNI IsInstanceOf was not working correctly
// so we are checking the class specifically. If we subclass this
// we need to modify the native code in CFontWrapper.m
public final class CFont extends PhysicalFont implements FontSubstitution {
private static final boolean useCoreTextLayout;
static {
useCoreTextLayout = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
Boolean.getBoolean("sun.font.use.coretext.layout"));
}
/* CFontStrike doesn't call these methods so they are unimplemented.
* They are here to meet the requirements of PhysicalFont, needed
* because a CFont can sometimes be returned where a PhysicalFont
* is expected.
*/
StrikeMetrics getFontMetrics(long pScalerContext) {
throw new InternalError("Not implemented");
}
float getGlyphAdvance(long pScalerContext, int glyphCode) {
throw new InternalError("Not implemented");
}
void getGlyphMetrics(long pScalerContext, int glyphCode,
Point2D.Float metrics) {
throw new InternalError("Not implemented");
}
long getGlyphImage(long pScalerContext, int glyphCode) {
throw new InternalError("Not implemented");
}
Rectangle2D.Float getGlyphOutlineBounds(long pScalerContext,
int glyphCode) {
throw new InternalError("Not implemented");
}
GeneralPath getGlyphOutline(long pScalerContext, int glyphCode,
float x, float y) {
throw new InternalError("Not implemented");
}
GeneralPath getGlyphVectorOutline(long pScalerContext,
int[] glyphs, int numGlyphs,
float x, float y) {
throw new InternalError("Not implemented");
}
@Override
protected long getLayoutTableCache() {
return getLayoutTableCacheNative(getNativeFontPtr());
}
@Override
protected byte[] getTableBytes(int tag) {
return getTableBytesNative(getNativeFontPtr(), tag);
}
private native synchronized long getLayoutTableCacheNative(long nativeFontPtr);
private native byte[] getTableBytesNative(long nativeFontPtr, int tag);
private static native long createNativeFont(final String nativeFontName,
final int style);
private static native void disposeNativeFont(final long nativeFontPtr);
private boolean isFakeItalic;
private String nativeFontName;
private long nativeFontPtr;
private native float getWidthNative(final long nativeFontPtr);
private native float getWeightNative(final long nativeFontPtr);
private int fontWidth = -1;
private int fontWeight = -1;
@Override
public int getWidth() {
if (fontWidth == -1) {
// Apple use a range of -1 -> +1, where 0.0 is normal
// OpenType uses a % range from 50% -> 200% where 100% is normal
// and maps these onto the integer values 1->9.
// Since that is what Font2D.getWidth() expects, remap to that.
float fw = getWidthNative(getNativeFontPtr());
if (fw == 0.0) { // short cut the common case
fontWidth = Font2D.FWIDTH_NORMAL;
return fontWidth;
}
fw += 1.0; fw *= 100.0;
if (fw <= 50.0) {
fontWidth = 1;
} else if (fw <= 62.5) {
fontWidth = 2;
} else if (fw <= 75.0) {
fontWidth = 3;
} else if (fw <= 87.5) {
fontWidth = 4;
} else if (fw <= 100.0) {
fontWidth = 5;
} else if (fw <= 112.5) {
fontWidth = 6;
} else if (fw <= 125.0) {
fontWidth = 7;
} else if (fw <= 150.0) {
fontWidth = 8;
} else {
fontWidth = 9;
}
}
return fontWidth;
}
@Override
public int getWeight() {
if (fontWeight == -1) {
// Apple use a range of -1 -> +1, where 0 is medium/regular
// Map this on to the OpenType range of 100->900 where
// 500 is medium/regular.
// We'll actually map to 0->1000 but that's close enough.
float fw = getWeightNative(getNativeFontPtr());
if (fw == 0) {
return Font2D.FWEIGHT_NORMAL;
}
fw += 1.0; fw *= 500;
fontWeight = (int)fw;
}
return fontWeight;
}
// this constructor is called from CFontWrapper.m
public CFont(String name) {
this(name, name);
}
public CFont(String name, String inFamilyName) {
handle = new Font2DHandle(this);
fullName = name;
familyName = inFamilyName;
nativeFontName = fullName;
setStyle();
}
/* Called from CFontManager too */
public CFont(CFont other, String logicalFamilyName) {
handle = new Font2DHandle(this);
fullName = logicalFamilyName;
familyName = logicalFamilyName;
nativeFontName = other.nativeFontName;
style = other.style;
isFakeItalic = other.isFakeItalic;
}
public CFont createItalicVariant(boolean updateStyle) {
CFont font = new CFont(this, familyName);
font.nativeFontName = fullName;
font.fullName =
fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived";
if (updateStyle) {
font.style |= Font.ITALIC;
}
font.isFakeItalic = true;
return font;
}
protected synchronized long getNativeFontPtr() {
if (nativeFontPtr == 0L) {
nativeFontPtr = createNativeFont(nativeFontName, style);
}
return nativeFontPtr;
}
private native long getCGFontPtrNative(long ptr);
// This digs the CGFont out of the AWTFont.
protected synchronized long getPlatformNativeFontPtr() {
return getCGFontPtrNative(getNativeFontPtr());
}
private CompositeFont compFont;
public CompositeFont getCompositeFont2D() {
if (compFont == null) {
compFont = new CCompositeFont(this);
}
return compFont;
}
protected synchronized void finalize() {
if (nativeFontPtr != 0) {
disposeNativeFont(nativeFontPtr);
}
nativeFontPtr = 0;
}
protected CharToGlyphMapper getMapper() {
if (mapper == null) {
mapper = new CCharToGlyphMapper(this);
}
return mapper;
}
protected FontStrike createStrike(FontStrikeDesc desc) {
if (isFakeItalic) {
desc = new FontStrikeDesc(desc);
desc.glyphTx.concatenate(AffineTransform.getShearInstance(-0.2, 0));
}
return new CStrike(this, desc);
}
boolean isFakeItalic() {
return isFakeItalic;
}
String getNativeFontName() {
return nativeFontName;
}
@Override
protected boolean isAAT() {
// CoreText layout code ignores fractional metrics font attribute
// also, using CoreText layout in Harfbuzz code leads to wrong advances for emoji glyphs
return useCoreTextLayout && !"AppleColorEmoji".equals(nativeFontName) && super.isAAT();
}
// <rdar://problem/5321707> sun.font.Font2D caches the last used strike,
// but does not check if the properties of the strike match the properties
// of the incoming java.awt.Font object (size, style, etc).
// Simple answer: don't cache.
private static FontRenderContext DEFAULT_FRC =
new FontRenderContext(null, false, false);
public FontStrike getStrike(final Font font) {
return getStrike(font, DEFAULT_FRC);
}
public boolean equals(Object o) {
if (!super.equals(o)) {
return false;
}
return ((Font2D)o).getStyle() == this.getStyle();
}
public int hashCode() {
return super.hashCode() ^ this.getStyle();
}
public String toString() {
return "CFont { fullName: " + fullName +
", familyName: " + familyName + ", style: " + style +
" } aka: " + super.toString();
}
}