/*
* Copyright (c) 2007, 2014, 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.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.lang.ref.WeakReference;
/* This is Freetype based implementation of FontScaler.
*
* Note that in case of runtime error it is expected that
* native code will release all native resources and
* call invalidateScaler() (that will throw FontScalerException).
*
* Note that callee is responsible for releasing native scaler context.
*/
class FreetypeFontScaler extends FontScaler {
/* constants aligned with native code */
private static final int TRUETYPE_FONT = 1;
private static final int TYPE1_FONT = 2;
static {
/* At the moment fontmanager library depends on freetype library
and therefore no need to load it explicitly here */
FontManagerNativeLibrary.load();
initIDs(FreetypeFontScaler.class);
}
private static native void initIDs(Class<?> FFS);
private void invalidateScaler() throws FontScalerException {
nativeScaler = 0;
font = null;
throw new FontScalerException();
}
public FreetypeFontScaler(Font2D font, int indexInCollection,
boolean supportsCJK, int filesize) {
int fonttype = TRUETYPE_FONT;
if (font instanceof Type1Font) {
fonttype = TYPE1_FONT;
}
nativeScaler = initNativeScaler(font,
fonttype,
indexInCollection,
supportsCJK,
filesize);
this.font = new WeakReference<>(font);
}
synchronized StrikeMetrics getFontMetrics(long pScalerContext)
throws FontScalerException {
if (nativeScaler != 0L) {
return getFontMetricsNative(font.get(),
pScalerContext,
nativeScaler);
}
return FontScaler.getNullScaler().getFontMetrics(0L);
}
synchronized float getGlyphAdvance(long pScalerContext, int glyphCode)
throws FontScalerException {
if (nativeScaler != 0L) {
return getGlyphAdvanceNative(font.get(),
pScalerContext,
nativeScaler,
glyphCode);
}
return FontScaler.getNullScaler().
getGlyphAdvance(0L, glyphCode);
}
synchronized void getGlyphMetrics(long pScalerContext,
int glyphCode, Point2D.Float metrics)
throws FontScalerException {
if (nativeScaler != 0L) {
getGlyphMetricsNative(font.get(),
pScalerContext,
nativeScaler,
glyphCode,
metrics);
return;
}
FontScaler.getNullScaler().
getGlyphMetrics(0L, glyphCode, metrics);
}
synchronized long getGlyphImage(long pScalerContext, int glyphCode)
throws FontScalerException {
if (nativeScaler != 0L) {
return getGlyphImageNative(font.get(),
pScalerContext,
nativeScaler,
glyphCode);
}
return FontScaler.getNullScaler().
getGlyphImage(0L, glyphCode);
}
synchronized Rectangle2D.Float getGlyphOutlineBounds(
long pScalerContext, int glyphCode)
throws FontScalerException {
if (nativeScaler != 0L) {
return getGlyphOutlineBoundsNative(font.get(),
pScalerContext,
nativeScaler,
glyphCode);
}
return FontScaler.getNullScaler().
getGlyphOutlineBounds(0L,glyphCode);
}
synchronized GeneralPath getGlyphOutline(
long pScalerContext, int glyphCode, float x, float y)
throws FontScalerException {
if (nativeScaler != 0L) {
return getGlyphOutlineNative(font.get(),
pScalerContext,
nativeScaler,
glyphCode,
x, y);
}
return FontScaler.getNullScaler().
getGlyphOutline(0L, glyphCode, x,y);
}
synchronized GeneralPath getGlyphVectorOutline(
long pScalerContext, int[] glyphs, int numGlyphs,
float x, float y) throws FontScalerException {
if (nativeScaler != 0L) {
return getGlyphVectorOutlineNative(font.get(),
pScalerContext,
nativeScaler,
glyphs,
numGlyphs,
x, y);
}
return FontScaler
.getNullScaler().getGlyphVectorOutline(0L, glyphs, numGlyphs, x, y);
}
/* This method should not be called directly, in case
* it is being invoked from a thread with a native context.
*/
public synchronized void dispose() {
if (nativeScaler != 0L) {
disposeNativeScaler(font.get(), nativeScaler);
nativeScaler = 0L;
}
}
public synchronized void disposeScaler() {
if (nativeScaler != 0L) {
/*
* The current thread may be calling this method from the context
* of a JNI up-call. It will hold the native lock from the
* original down-call so can directly enter dispose and free
* the resources. So we need to schedule the disposal to happen
* only once we've returned from native. So by running the dispose
* on another thread which does nothing except that disposal we
* are sure that this is safe.
*/
new Thread(null, () -> dispose(), "free scaler", 0, false).start();
}
}
synchronized int getNumGlyphs() throws FontScalerException {
if (nativeScaler != 0L) {
return getNumGlyphsNative(nativeScaler);
}
return FontScaler.getNullScaler().getNumGlyphs();
}
synchronized int getMissingGlyphCode() throws FontScalerException {
if (nativeScaler != 0L) {
return getMissingGlyphCodeNative(nativeScaler);
}
return FontScaler.getNullScaler().getMissingGlyphCode();
}
synchronized int getGlyphCode(char charCode) throws FontScalerException {
if (nativeScaler != 0L) {
return getGlyphCodeNative(font.get(), nativeScaler, charCode);
}
return FontScaler.getNullScaler().getGlyphCode(charCode);
}
synchronized Point2D.Float getGlyphPoint(long pScalerContext,
int glyphCode, int ptNumber)
throws FontScalerException {
if (nativeScaler != 0L) {
return getGlyphPointNative(font.get(), pScalerContext,
nativeScaler, glyphCode, ptNumber);
}
return FontScaler.getNullScaler().getGlyphPoint(
pScalerContext, glyphCode, ptNumber);
}
synchronized long getUnitsPerEm() {
return getUnitsPerEMNative(nativeScaler);
}
synchronized long createScalerContext(double[] matrix,
int aa, int fm, float boldness, float italic,
boolean disableHinting) {
if (nativeScaler != 0L) {
return createScalerContextNative(nativeScaler, matrix,
aa, fm, boldness, italic);
}
return NullFontScaler.getNullScalerContext();
}
//Note: native methods can throw RuntimeException if processing fails
private native long initNativeScaler(Font2D font, int type,
int indexInCollection, boolean supportsCJK, int filesize);
private native StrikeMetrics getFontMetricsNative(Font2D font,
long pScalerContext, long pScaler);
private native float getGlyphAdvanceNative(Font2D font,
long pScalerContext, long pScaler, int glyphCode);
private native void getGlyphMetricsNative(Font2D font,
long pScalerContext, long pScaler,
int glyphCode, Point2D.Float metrics);
private native long getGlyphImageNative(Font2D font,
long pScalerContext, long pScaler, int glyphCode);
private native Rectangle2D.Float getGlyphOutlineBoundsNative(Font2D font,
long pScalerContext, long pScaler, int glyphCode);
/**代码未完, 请加载全部代码(NowJava.com).**/