blob: e62f77ddd42386ff8e9e2b3e59c9d71c1489c00e [file] [log] [blame]
/*
* 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
*
*/
#include <Windows.h>
#include <WinGDI.h>
#include <Winnls.h>
#include <Winreg.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include "winFont.h"
#include "org_apache_harmony_awt_gl_font_NativeFont.h"
#include "org_apache_harmony_awt_gl_font_WinGlyph.h"
#include "exceptions.h"
#include <FontLibExports.h> // Font file tables parsing routines for embedFontNative method
static LCIDS lcidTable;
static FontRecords fonts; /* Cached system fonts data */
static int famSize = 256; /* Size of families array */
static TCHAR** families = NULL; /* Cached set of system families set */
static int famCount = 0; /* Number of families */
static int counter = 0; /* static counter for call back access functions */
/* Reverses DWORD bytes order */
unsigned long dwReverse(DWORD data)
{
unsigned char *dataElems = (unsigned char *) &data;
return (unsigned long)((dataElems[0]<<24) | (dataElems[1]<<16) | (dataElems[2]<<8) | dataElems[3]);
}
/* Reverses WORD bytes order */
unsigned short wReverse(WORD data)
{
return (unsigned short)(((data<<8) & 0xFF00) | ((data>>8) & 0x00FF));
}
/* Converts point size to logical coordinate space size */
int PointSizetoLogical(HDC hDC, int points, int divisor)
{
POINT P[2] = // two POINTs in device space whose distance is the needed height
{
{ 0, 0 },
{ 0, GetDeviceCaps(hDC, LOGPIXELSY) * points }
};
DPtoLP(hDC, P, 2); // map device coordinate to logical size
return labs(P[1].y - P[0].y) / 72 / divisor;
}
/* Returns font style of the LOGFONT structure */
int getFontStyle(LOGFONT lf){
int ret = FONT_PLAIN;
if (lf.lfItalic){
ret |= FONT_ITALIC;
}
if (lf.lfWeight > 500){
ret |= FONT_BOLD;
}
return ret;
}
/* Get array of Unicode Ranges [start1,end1,start2,end2...]
Description: if parameter (ranges == NULL) then function returns ranges array size equal to
number of ranges multiplied by 2 */
int GetUnicodeRanges (HFONT hFont, int **ranges){
HDC hDC = CreateCompatibleDC(NULL);
HGDIOBJ hOld = SelectObject(hDC, hFont);
int i, rangesCount, index;
int arrSize;
DWORD size;
GLYPHSET * pGlyphSet = NULL;
size = GetFontUnicodeRanges(hDC, NULL);
pGlyphSet = (GLYPHSET *) malloc(size);
if (pGlyphSet == NULL){
SelectObject(hDC, hOld);
DeleteDC(hDC);
return -1;
}
pGlyphSet->cbThis = size;
size = GetFontUnicodeRanges(hDC, pGlyphSet);
if (size == 0){
free(pGlyphSet);
SelectObject(hDC, hOld);
DeleteDC(hDC);
return -1;
}
rangesCount = pGlyphSet->cRanges;
arrSize = rangesCount << 1;
if (*ranges == NULL){
*ranges = (int *)malloc (arrSize * sizeof(int)); // number of int elements
} else {
*ranges = (int *)realloc (*ranges, arrSize * sizeof(int)); // number of int elements
}
if (*ranges == NULL){
free(pGlyphSet);
SelectObject(hDC, hOld);
DeleteDC(hDC);
return arrSize;
}
for (i=0; i < rangesCount; i++){
index = i << 1;
(*ranges)[index] = pGlyphSet->ranges[i].wcLow;
(*ranges)[index + 1] = pGlyphSet->ranges[i].wcLow + pGlyphSet->ranges[i].cGlyphs -1;
}
free(pGlyphSet);
SelectObject(hDC, hOld);
DeleteDC(hDC);
return arrSize;
}
/* Adds FontRecord to the list, returns 1 if success, returns 0 if malloc failed */
int addFontRecord(int index, int style, int type, TCHAR *faceName){
int i;
// If the number of records exceeds the size of structure
// we double the size of families array.
if ( fonts.count == fonts.size) {
fonts.size = fonts.size << 1;
fonts.indices = (int *)realloc(fonts.indices, fonts.size * sizeof(int));
if (fonts.indices == NULL){
return FONTLIB_ERROR;
}
fonts.types = (int *)realloc(fonts.types, fonts.size * sizeof(int));
if (fonts.types == NULL){
return FONTLIB_ERROR;
}
fonts.styles = (int *)realloc(fonts.styles, fonts.size * sizeof(int));
if (fonts.styles == NULL){
return FONTLIB_ERROR;
}
fonts.faceNames = (TCHAR **)realloc(fonts.faceNames, fonts.size * sizeof(TCHAR *));
if (fonts.faceNames == NULL){
return FONTLIB_ERROR;
}
}
fonts.indices[fonts.count] = index;
fonts.styles[fonts.count] = style;
fonts.types[fonts.count] = type;
fonts.faceNames[fonts.count] = faceName;
for (i = 0; ((fonts.indices[i] != index) || (fonts.styles[i] != style)); i ++);
if(i == fonts.count){
fonts.count++;
}
return FONTLIB_SUCCESS;
}
/* Adds family name to the list, returns 1 if success, returns 0 if malloc failed */
int addFamily(TCHAR *fam){
int i;
// If the number of records exceeds the size of structure
// we double the size of families array.
if ( famCount == famSize) {
famSize = famSize << 1;
families = (TCHAR **)realloc(families, famSize*sizeof(TCHAR *));
if (families == NULL){
return FONTLIB_ERROR;
}
}
families[famCount] = (TCHAR *)malloc((_tcslen(fam)+1) * sizeof(TCHAR));
_tcscpy( families[famCount], fam);
for (i = 0; (_tcscmp(families[i], fam) != 0); i++);
if(i == famCount){
famCount++;
}
return FONTLIB_SUCCESS;
}
/* Callback processing function for families enumeration */
int static CALLBACK EnumFontFamProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme,
int FontType, LPARAM lParam)
{
if (FontType & (TRUETYPE_FONTTYPE | DEVICE_FONTTYPE)){
return addFamily((TCHAR *)(lpelfe->elfLogFont.lfFaceName));
}
return FONTLIB_SUCCESS;
}
/* Callback processing function for EnumFontFamEx */
int static CALLBACK EnumFontProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme,
int FontType, LPARAM lParam)
{
int style;
int index;
const int FACE_SIZE = 2*LF_FACESIZE+1; // family count + style size + 1 (space char)
TCHAR *face = (TCHAR *)malloc(FACE_SIZE*sizeof(TCHAR));
if (FontType & (TRUETYPE_FONTTYPE | DEVICE_FONTTYPE)){
index = (int)lParam;
style = getFontStyle(lpelfe->elfLogFont);
// XXX: if style = plain, lpelfe->elfStyle == "Regular" in user's locale
// we use simply family name
face[FACE_SIZE-1] = 0;
if (style != FONT_PLAIN){
_sntprintf(face, FACE_SIZE, L"%s %s", lpelfe->elfLogFont.lfFaceName, lpelfe->elfStyle);
}else
_tcsncpy( face, lpelfe->elfLogFont.lfFaceName, FACE_SIZE);
return addFontRecord(index, style, FontType, face);
}
return FONTLIB_SUCCESS;
}
/* Enumerates font families, returns 0 if there is error */
int enumFamilies(){
HDC hDC = CreateCompatibleDC(NULL);
LOGFONT lf;
int res;
memset(& lf, 0, sizeof(lf));
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfFaceName[0] = '\0';
if (families == NULL){
families = (TCHAR **)malloc(famSize * sizeof(TCHAR *));
if (families == 0){
DeleteDC(hDC);
// Not enough memory to load font family names list
return FONTLIB_ERROR;
}
} else {
famCount = 0;
}
res = EnumFontFamiliesEx(hDC, & lf, (FONTENUMPROC) EnumFontFamProc, 0, 0);
DeleteDC(hDC);
if (res == FONTLIB_ERROR){
// Not enough memory to enumerate font family names list.
return FONTLIB_ERROR;
}
return FONTLIB_SUCCESS;
}
/* Enumerates font face names, returns 0 if there is error */
int enumFonts(){
HDC hDC = CreateCompatibleDC(NULL);
int i;
int res;
LOGFONT lf;
memset(& lf, 0, sizeof(lf));
lf.lfCharSet = DEFAULT_CHARSET;
// !! All font face and font family names cached only once.
// In some cases when application is active new fonts can be
// installed(removed) into the system and it isn't taken into account.
// From the other hand it is too expencive in terms of performance re-cache
// names lists each time font to be created or removed from system this
// action must be performed every time new Font object in Java is being
// created.
// If system fonts changed current font enumeration implementation might
// rise an exception.
if (families == NULL){
enumFamilies();
}
if (fonts.indices == NULL){
fonts.size = 256;
fonts.indices = (int *)realloc(fonts.indices, fonts.size * sizeof(int));
if (fonts.indices == NULL){
DeleteDC(hDC);
return FONTLIB_ERROR;
}
fonts.types = (int *)realloc(fonts.types, fonts.size * sizeof(int));
if (fonts.types == NULL){
DeleteDC(hDC);
return FONTLIB_ERROR;
}
fonts.styles = (int *)realloc(fonts.styles, fonts.size * sizeof(int));
if (fonts.styles == NULL){
DeleteDC(hDC);
return FONTLIB_ERROR;
}
fonts.faceNames = (TCHAR **)realloc(fonts.faceNames, fonts.size * sizeof(TCHAR *));
if (fonts.faceNames == NULL){
DeleteDC(hDC);
return FONTLIB_ERROR;
}
}
fonts.count = 0;
for (i = 0; i < famCount; i++){
_tcsncpy(lf.lfFaceName, families[i], LF_FACESIZE);
res = EnumFontFamiliesEx(hDC, & lf, (FONTENUMPROC) EnumFontProc, i, 0);
if (res == FONTLIB_ERROR){
DeleteDC(hDC);
// Not enough memory to enumerate fonts list.
return FONTLIB_ERROR;
}
}
DeleteDC(hDC);
return FONTLIB_SUCCESS;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getFontFamiliesNames
* Signature: ()[Ljava/lang/String;
* Description: Returns array of all families installed onto the system.
*/
JNIEXPORT jobjectArray JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getFontFamiliesNames(JNIEnv *env, jclass obj) {
int i = 0;
int res;
jobjectArray ret;
jstring initStr ;
jclass strClass;
res = enumFamilies();
if (res == FONTLIB_ERROR){
throwNPException(env, "Not enough memory to enumerate font family names list.");
return NULL;
}
strClass = env->FindClass("java/lang/String");
initStr = env->NewStringUTF("");
ret = (jobjectArray)env->NewObjectArray(famCount,
strClass,
initStr);
for (;i < famCount;i++){
env->SetObjectArrayElement(ret,i,env->NewString((const jchar *)families[i], (jsize)_tcslen(families[i]))); // number of chars == length of string -1
}
return ret;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: enumSystemFonts
* Signature: ()V;
* Description: Sets arrays of available Font data in Java.
*/
JNIEXPORT void JNICALL Java_org_apache_harmony_awt_gl_font_NativeFont_enumSystemFonts(JNIEnv *env, jclass obj) {
int i = 0;
int res;
jintArray indArr;
jintArray typesArr;
jintArray stylesArr;
jclass cls;
jmethodID mid;
jclass strClass;
jstring initStr;
jobjectArray faces;
res = enumFonts();
if (res == FONTLIB_ERROR){
throwNPException(env, "Not enough memory to enumerate font names list.");
return;
}
cls= env->FindClass("org/apache/harmony/awt/gl/font/NativeFont");
if (cls == 0) {
throwNPException(env, "Can't find class NativeFont");
return;
}
mid=env->GetStaticMethodID(cls, "setArrays", "([I[I[I[Ljava/lang/String;)V");
if (mid == 0) {
throwNPException(env, "Can't find method sendArrayResults");
return;
}
typesArr = env->NewIntArray(fonts.count);
stylesArr = env->NewIntArray(fonts.count);
indArr = env->NewIntArray(fonts.count);
strClass = env->FindClass("java/lang/String");
initStr = env->NewStringUTF("");
faces = (jobjectArray)env->NewObjectArray(fonts.count,
strClass,
initStr);
for (;i < fonts.count; i++){
env->SetObjectArrayElement(faces,i,env->NewString((const jchar *)fonts.faceNames[i], (jsize)_tcslen(fonts.faceNames[i]))); // number of chars == length of string -1
}
if ((indArr == NULL) || (typesArr == NULL) || (stylesArr == NULL)){
throwNPException(env, "Not enough memory to create font data arrays.");
return;
}
env->SetIntArrayRegion(typesArr, 0, fonts.count, (jint *)fonts.types);
env->SetIntArrayRegion(stylesArr, 0, fonts.count, (jint *)fonts.styles);
env->SetIntArrayRegion(indArr, 0, fonts.count, (jint *)fonts.indices);
env->ExceptionClear();
env->MonitorEnter(obj);
env->CallStaticVoidMethod(cls, mid, typesArr, stylesArr, indArr, faces);
env->MonitorExit(obj);
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: embedFontNative
* Signature: (Ljava/lang/String;)Z
* Description: Returns TRUE if Font resource from font file added successfully to a system.
*/
JNIEXPORT jstring JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_embedFontNative(JNIEnv *env, jclass obj, jstring absPath) {
jboolean iscopy;
int fontAdded = 0;
const TCHAR * path;
path = (TCHAR *)(env->GetStringCritical(absPath, &iscopy));
fontAdded = AddFontResourceEx(path, FR_PRIVATE, 0);
fwchar_t *familyName = 0;
if (fontAdded) {
getFontFamilyName((fwchar_t *)path, &familyName);
}
env->ReleaseStringCritical(absPath, (const jchar *)path);
jstring res = 0;
if (fontAdded && familyName) {
int len = wcslen((wchar_t*)familyName);
res = env->NewString((jchar *)familyName, len);
delete familyName;
}
return res;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: initializeFont
* Signature: (Lorg/apache/harmony/awt/gl/Font;)J
* Description: Returns pointer to Font object created with given parameters.
*/
JNIEXPORT jlong JNICALL Java_org_apache_harmony_awt_gl_font_NativeFont_initializeFont(JNIEnv *env,
jclass obj, jobject winFont, jstring jFace, jint style, jint size) {
jclass cls;
jmethodID mid;
jboolean iscopy;
jintArray ranges;
int arrSize;
jsize length;
int * pRanges = NULL;
const TCHAR * fontName;
HFONT res;
LOGFONT lf; // LOGFONT structure for given Font's parameters
memset(& lf, 0, sizeof(lf));
cls = env->GetObjectClass(winFont);
lf.lfHeight = - size;
lf.lfWidth = 0; // need to be defined
lf.lfEscapement = 0; // need to be defined
lf.lfOrientation = 0; // need to be defined
if (style & FONT_BOLD) {
lf.lfWeight = FW_BOLD; // need to be defined from TextAttributes
} else {
lf.lfWeight = FW_REGULAR; // need to be defined from TextAttributes
}
lf.lfItalic = (BYTE)(style & FONT_ITALIC);
lf.lfStrikeOut = FALSE;
lf.lfUnderline = FALSE;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = NONANTIALIASED_QUALITY;//DEFAULT_QUALITY; // Rendering hints ?
lf.lfPitchAndFamily = DEFAULT_PITCH;
length = env->GetStringLength(jFace);
fontName = (const TCHAR *)env->GetStringCritical(jFace, &iscopy);
lf.lfFaceName[0] = 0;
if ( fontName ) {
// Due to MSDN length of FaceName parameter
if (length < 32){
_tcsncpy(lf.lfFaceName, fontName, length);
}
}
env->ReleaseStringCritical(jFace, (const jchar *)fontName);
res = CreateFontIndirect(& lf);
GetObject(res, sizeof(lf), &lf);
mid=env->GetMethodID(cls, "setLogicalHeight","(I)V");
if (mid == 0) {
// "Can't find method setUnicodeRanges"
env->ExceptionDescribe();
env->ExceptionClear();
return (jlong)NULL;
}
env->CallVoidMethod(winFont, mid, lf.lfHeight);
if(env->ExceptionOccurred()) {
env->ExceptionDescribe();
env->ExceptionClear();
return (jlong)NULL;
}
mid=env->GetMethodID(cls, "setUnicodeRanges","([I)V");
if (mid == 0) {
// "Can't find method setUnicodeRanges"
env->ExceptionDescribe();
env->ExceptionClear();
return (jlong)NULL;
}
// Get number of unicode range pairs' bounds values
arrSize = GetUnicodeRanges(res, &pRanges);
if (arrSize == -1){
throwNPException(env, "Error occured during getting an array of unicode ranges");
return (jlong)NULL;
}
ranges =(jintArray)env->NewIntArray(arrSize);
env->SetIntArrayRegion(ranges, 0, arrSize,(jint *)pRanges);
free(pRanges);
env->ExceptionClear();
env->CallVoidMethod(winFont, mid, ranges);
if(env->ExceptionOccurred()) {
// "error occured copying array up to Java"
env->ExceptionDescribe();
env->ExceptionClear();
return (jlong)NULL;
}
return (jlong)res;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: canDisplayCharNative
* Signature: (JC)Z
* Description: Returns TRUE if given char has glyph index in Font object.
*/
JNIEXPORT jboolean JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_canDisplayCharNative(JNIEnv *env, jclass obj, jlong fnt, jchar c) {
DWORD size;
WORD gi[1];
HFONT hFont = (HFONT)fnt; // Handle to Font object
HGDIOBJ hOld;
TCHAR sample[1];
sample[0] = (TCHAR)c;
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
size = GetGlyphIndices(hDC, sample, 1, gi, GGI_MARK_NONEXISTING_GLYPHS);
if (size == GDI_ERROR){
throwNPException(env, "Error occured during getting char data in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return FALSE;
}
SelectObject(hDC, hOld);
DeleteDC(hDC);
return ((size != 0) && (gi[0] != 0xFFFF));
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getFamilyNative
* Signature: (J)Ljava/lang/String;
* Description: Returns Family Name of the given Font object.
*/
JNIEXPORT jstring JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getFamilyNative(JNIEnv *env, jclass obj, jlong fnt) {
DWORD size;
HFONT hFont = (HFONT)fnt;
HGDIOBJ hOld;
jstring res;
TCHAR name[LF_FULLFACESIZE];
OUTLINETEXTMETRIC outm[3];
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
size = GetOutlineTextMetrics(hDC, sizeof(outm), outm);
if (size == 0 ){
throwNPException(env, "Error occured during getting text metrics in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
memset(& name, 0, sizeof(name));
_tcscpy(name, (TCHAR *)((char *) outm + (int) outm[0].otmpFamilyName));
res = env->NewString((const jchar *)name, (int)_tcslen(name));
SelectObject(hDC, hOld);
DeleteDC(hDC);
return res;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getFontNameNative
* Signature: (J)Ljava/lang/String;
* Description: Returns Font Face Name of given Font object
*/
JNIEXPORT jstring JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getFontNameNative(JNIEnv *env, jclass obj, jlong fnt) {
DWORD size;
HFONT hFont = (HFONT)fnt;
HGDIOBJ hOld;
jstring res;
TCHAR name[64];
OUTLINETEXTMETRIC outm[3];
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
size = GetOutlineTextMetrics(hDC, sizeof(outm), outm);
if (size == 0 ){
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
memset(& name, 0, sizeof(name));
_tcscpy(name, (TCHAR *)((char *) outm + (int) outm[0].otmpFaceName));
res = env->NewString((const jchar *)name, (jsize)_tcslen(name));
SelectObject(hDC, hOld);
DeleteDC(hDC);
return res;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: pFontFree
* Signature: (J)I
* Description: Frees given Font object.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_pFontFree(JNIEnv *env, jclass obj, jlong fnt) {
HFONT hFont = (HFONT)fnt;
return DeleteObject(hFont);
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: RemoveFontResource
* Signature: (Ljava/lang/String;)Z
* Description: Removes font resourse corresponding to the given Font object.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_RemoveFontResource(JNIEnv *env, jclass obj, jstring absPath) {
jboolean iscopy;
int fontRemoved = 0;
const TCHAR * path;
path = (TCHAR *)(env->GetStringCritical(absPath, &iscopy));
fontRemoved = RemoveFontResource(path);
env->ReleaseStringCritical(absPath, (const jchar *)path);
return fontRemoved;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getItalicAngleNative
* Signature: (J)F
* Description: Returns tangent of Italic angle of given Font.
*/
JNIEXPORT jfloat JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getItalicAngleNative(JNIEnv *env, jclass obj, jlong fnt) {
DWORD size;
HFONT hFont = (HFONT)fnt; // Handle to Font object
HGDIOBJ hOld;
jfloat res;
OUTLINETEXTMETRIC outm[3];
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
size = GetOutlineTextMetrics(hDC, sizeof(outm), outm);
if (size == 0 ){
throwNPException(env, "Error occured during getting text outline metrics in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return 0;
}
res = ((float)outm[0].otmsCharSlopeRun) / ((float)outm[0].otmsCharSlopeRise);
SelectObject(hDC, hOld);
DeleteDC(hDC);
return res;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getDefaultChar
* Signature: (J)F
* Description: Returns default char value of given Font.
*/
JNIEXPORT jchar JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getDefaultCharNative(JNIEnv *env, jclass obj, jlong fnt) {
DWORD size;
HFONT hFont = (HFONT)fnt; // Handle to Font object
HGDIOBJ hOld;
jchar res;
TEXTMETRIC tm;
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
size = GetTextMetrics(hDC, &tm);
if (size == 0 ){
throwNPException(env, "Error occured during getting text metrics in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return 0;
}
res = (jchar)(tm.tmDefaultChar);
SelectObject(hDC, hOld);
DeleteDC(hDC);
return res;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getFonts
* Signature: ()[Ljava/lang/String;
* Description: Returns array of available Font Names.
* !! Doesn't enumerate Type1 fonts !!
*/
JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_awt_gl_font_NativeFont_getFonts(JNIEnv *env, jclass obj) {
int i = 0;
jobjectArray ret;
jclass strClass;
jstring initStr;
const TCHAR * fontName;
TCHAR * pdest;
TCHAR ** fontNames; // list of font names
int * fontSizes; // list of sizes of font names
int size = 256;
int counter = 0;
const TCHAR Key_Fonts[] = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
const TCHAR TrueType[] = _T(" (TrueType)");
HKEY hKey;
if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, Key_Fonts, 0, KEY_READ, & hKey)==ERROR_SUCCESS )
{
fontNames = (TCHAR **)malloc(sizeof(TCHAR *) * size);
fontSizes = (int *)malloc(sizeof(int) * size);
for (i=0; ; i++)
{
TCHAR szValueName[MAX_PATH];
BYTE szValueData[MAX_PATH];
DWORD nValueNameLen = MAX_PATH;
DWORD nValueDataLen = MAX_PATH;
DWORD dwType;
if ( RegEnumValue(hKey, i, szValueName, & nValueNameLen, NULL,
& dwType, szValueData, & nValueDataLen) != ERROR_SUCCESS )
break;
fontName = (const TCHAR *) szValueName;
pdest = (TCHAR *)_tcsstr( fontName, TrueType );
if (pdest !=NULL ){
if (counter == (size - 1)) {
size = size << 1;
fontNames = (TCHAR **)realloc(fontNames, sizeof(TCHAR *) * size);
fontSizes = (int *)realloc(fontSizes, sizeof(int) * size);
}
fontSizes[counter] = (int)(pdest - fontName);
fontNames[counter] = (TCHAR*)calloc(fontSizes[counter], sizeof(TCHAR));
_tcsncpy(fontNames[counter], fontName, fontSizes[counter]);
counter++;
}
}
RegCloseKey(hKey);
strClass = env->FindClass("java/lang/String");
initStr = env->NewStringUTF("");
ret = (jobjectArray)env->NewObjectArray(counter,
strClass,
initStr);
for (i = 0;i < counter;i++){
env->SetObjectArrayElement(ret,i,env->NewString((const jchar *)fontNames[i], fontSizes[i]));
free(fontNames[i]);
}
free(fontNames);
free(fontSizes);
return ret;
} else {
return NULL;
}
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getNativeLineMetrics
* Signature: (JIZZI)[F
* Description: Returns common text metrics of the specified Font.
*/
JNIEXPORT jfloatArray JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getNativeLineMetrics(JNIEnv *env, jclass obj, jlong fnt, jint fontHeight, jboolean isAntialiased, jboolean usesFractionalMetrics, jint fontType) {
DWORD size;
HFONT hFont = (HFONT)fnt;
HGDIOBJ hOld;
HGDIOBJ hFontEM;
OUTLINETEXTMETRIC outm[3];
TEXTMETRIC tm;
jfloat result[16];
jfloatArray flArray;
LOGFONT lf;
int emsquare;
int height;
height = fontHeight;
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
// Getting current size of Font
size = GetOutlineTextMetrics(hDC, sizeof(outm), outm);
if (size == 0 ){
throwNPException(env, "Error occured during getting text outline metrics in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
tm = outm[0].otmTextMetrics;
/* logical TEXTMETRICS */
result[8] = (float)tm.tmAscent; // Precise Ascent value
result[9] = (float)tm.tmDescent; // Precise Descent value
if (fontType == FONT_TYPE_TT){
result[10] = (float)tm.tmExternalLeading; // Precise Leading value
} else {
// Type1 has null tmExternalLeading, using tmInternalLeading value
result[10] = (float)tm.tmInternalLeading;
}
result[11] = (float)outm[0].otmsUnderscoreSize; // Precise Underline size value
result[12] = (float)outm[0].otmsUnderscorePosition; // Precise Underline position value
result[13] = (float)outm[0].otmsStrikeoutSize; // Precise Strikeout line size value
result[14] = (float)outm[0].otmsStrikeoutPosition; // Precise Strikeout line position value
result[15] = (float)tm.tmMaxCharWidth; // Precise Max char width
emsquare = outm[0].otmEMSquare; // EM Square size
// Create font with height == "EM Square size" in device units to
// get multyply factor
GetObject(hFont, sizeof(lf), &lf);
lf.lfHeight = -emsquare;
lf.lfWidth = 0;
hFontEM = CreateFontIndirect(&lf);
SelectObject(hDC, hFontEM);
size = GetOutlineTextMetrics(hDC, sizeof(outm), outm);
if (size == 0 ){
throwNPException(env, "Error occured during getting text outline metrics in native code.");
SelectObject(hDC, hOld);
DeleteObject(hFontEM);
DeleteDC(hDC);
return NULL;
}
tm = outm[0].otmTextMetrics;
result[0] = (float)(tm.tmAscent * height)/emsquare; // Precise Ascent value
result[1] = (float)(tm.tmDescent * height)/emsquare; // Precise Descent value
if (fontType == FONT_TYPE_TT){
result[2] = (float)(tm.tmExternalLeading * height)/emsquare; // Precise Leading value
} else {
// Type1 has null tmExternalLeading, using tmInternalLeading value
result[2] = (float)(tm.tmInternalLeading * height)/emsquare;
}
result[3] = (float)(outm[0].otmsUnderscoreSize * height)/emsquare; // Precise Underline size value
result[4] = (float)(outm[0].otmsUnderscorePosition * height)/emsquare; // Precise Underline position value
result[5] = (float)(outm[0].otmsStrikeoutSize * height)/emsquare; // Precise Strikeout line size value
result[6] = (float)(outm[0].otmsStrikeoutPosition * height)/emsquare; // Precise Strikeout line position value
result[7] = (float)(tm.tmMaxCharWidth * height)/emsquare; // Precise Max char width
flArray=env->NewFloatArray(16);
env->SetFloatArrayRegion(flArray, 0, 16, result);
SelectObject(hDC, hOld);
DeleteObject(hFontEM);
DeleteDC(hDC);
return flArray;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getGlyphInfoNative
* Signature: (JCI)[F
* DEscription: Returns metrics of glyph of the specified character.
*/
JNIEXPORT jfloatArray JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getGlyphInfoNative(JNIEnv *env, jclass obj, jlong fnt, jchar chr, jint fontHeight) {
DWORD size;
HFONT hFont = (HFONT)fnt;
HFONT hFontEM;
HGDIOBJ hOld;
ABC abcWidth[1];
jfloatArray metrics;
GLYPHMETRICS g_metrics;
MAT2 mat2;
OUTLINETEXTMETRIC outm[3];
float arr[11];
int height; // height of given Font
LOGFONT lf;
int emsquare;
int res;
height = fontHeight;
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
// Getting current height of given Font
size = GetOutlineTextMetrics(hDC, sizeof(outm), outm);
if (size == 0 ){
throwNPException(env, "Error occured during getting text outline metrics in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
// Set transform matrix values to identity matrix values
ZeroMemory(&mat2, sizeof(MAT2));
mat2.eM11.value = 1;
mat2.eM12.value = 0;
mat2.eM21.value = 0;
mat2.eM22.value = 1;
res = GetCharABCWidths(hDC, chr, chr, abcWidth);
if (res == 0 ){
throwNPException(env, "Error occured during getting char widths in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
arr[6] = (float) abcWidth[0].abcA; // Left glyph spacing
arr[7] = (float) abcWidth[0].abcB; // Width of glyph
arr[8] = (float) abcWidth[0].abcC; // Right glyph spacing
res = GetGlyphOutline(hDC, chr, GGO_METRICS, & g_metrics, 0, NULL, & mat2);
if (res == GDI_ERROR ){
throwNPException(env, "Error occured during getting glyph outline in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
arr[9] = (float)g_metrics.gmBlackBoxX; // Glyph Bounds : width
arr[10] = (float)g_metrics.gmBlackBoxY; // Glyph Bounds : height
emsquare = outm[0].otmEMSquare; // EM Square size
GetObject(hFont, sizeof(lf), &lf);
lf.lfHeight = -emsquare;
lf.lfWidth = 0;
hFontEM = CreateFontIndirect(&lf);
SelectObject(hDC, hFontEM);
size = GetGlyphOutline(hDC, chr, GGO_METRICS, & g_metrics, 0, NULL, & mat2);
if (size==GDI_ERROR){
throwNPException(env, "Error occured during getting glyph outline metrics in native code.");
SelectObject(hDC, hOld);
DeleteObject(hFontEM);
DeleteDC(hDC);
return NULL;
}
arr[0] = (float)(g_metrics.gmptGlyphOrigin.x * height)/emsquare; // Precise Glyph Bounds : X
arr[1] = (float)(g_metrics.gmptGlyphOrigin.y * height)/emsquare; // Precise Glyph Bounds : Y
arr[2] = (float)(g_metrics.gmCellIncX * height)/emsquare; // Precise AdvanceX
arr[3] = (float)(g_metrics.gmCellIncY * height)/emsquare; // Precise AdvanceY ?= Ascent+Descent
arr[4] = (float)(g_metrics.gmBlackBoxX * height)/emsquare; // Precise Glyph Bounds : width
arr[5] = (float)(g_metrics.gmBlackBoxY * height)/emsquare; // Precise Glyph Bounds : height
metrics = env->NewFloatArray(11);
env->SetFloatArrayRegion(metrics, 0, 11, arr);
SelectObject(hDC, hOld);
DeleteObject(hFontEM);
DeleteDC(hDC);
return metrics;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getGlyphPxlInfoNative
* Signature: (JCI)[F
* DEscription: Returns metrics of glyph of the specified character.
*/
JNIEXPORT jintArray JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getGlyphPxlInfoNative(JNIEnv *env, jclass obj, jlong fnt, jchar chr) {
DWORD size;
HFONT hFont = (HFONT)fnt;
HGDIOBJ hOld;
jintArray metrics;
GLYPHMETRICS g_metrics;
MAT2 mat2;
int arr[6];
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
// Set transform matrix values to identity matrix values
ZeroMemory(&mat2, sizeof(MAT2));
mat2.eM11.value = 1;
mat2.eM12.value = 0;
mat2.eM21.value = 0;
mat2.eM22.value = 1;
size = GetGlyphOutline(hDC, chr, GGO_METRICS, & g_metrics, 0, NULL, & mat2);
if (size==GDI_ERROR){
throwNPException(env, "Error occured during getting glyph outline in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
arr[0] = g_metrics.gmptGlyphOrigin.x ; // Glyph Pixels Bounds : X
arr[1] = g_metrics.gmptGlyphOrigin.y ; // Glyph Pixels Bounds : Y
arr[2] = g_metrics.gmCellIncX; // Pixels AdvanceX
arr[3] = g_metrics.gmCellIncY ; // Pixels AdvanceY ?= Ascent+Descent
arr[4] = g_metrics.gmBlackBoxX ; // Glyph Pixels Bounds : width
arr[5] = g_metrics.gmBlackBoxY ; // Glyph Pixels Bounds : height
metrics = env->NewIntArray(6);
env->SetIntArrayRegion(metrics, 0, 6, (jint *)arr);
SelectObject(hDC, hOld);
DeleteDC(hDC);
return metrics;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getGlyphCodesNative
* Signature: (JLjava/lang/String;I)[I
* Description: Returns an array of Glyph codes corresponding to the specified string.
*/
JNIEXPORT jintArray JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getGlyphCodesNative(JNIEnv *env, jclass obj, jlong fnt, jstring str, jint len) {
DWORD size;
HFONT hFont = (HFONT)fnt; // Font object handle
HGDIOBJ hOld;
jboolean isCopy;
jintArray intArray;
int leng = len;
int i;
TCHAR * chars; // Char vector
WORD * gi; // Vector of indices
int * arr;
HDC hDC = CreateCompatibleDC(NULL);
gi = (WORD *)malloc(len*sizeof(WORD));
hOld = SelectObject(hDC, hFont);
chars = (TCHAR *)env->GetStringCritical(str, &isCopy);
size = GetGlyphIndices(hDC, chars, leng, gi, 0);//GGI_MARK_NONEXISTING_GLYPHS);
if (size == GDI_ERROR){
throwNPException(env, "Error occured during getting glyph indices in native code.");
free(gi);
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
arr = (int *)malloc(len*sizeof(int));
for (i = 0; i < leng; i++ ){
arr[i] = (int)gi[i];
}
intArray=env->NewIntArray(leng);
env->SetIntArrayRegion(intArray, 0, leng, (jint *)arr);
free(gi);
free(arr);
SelectObject(hDC, hOld);
DeleteDC(hDC);
env->ReleaseStringCritical(str, (const jchar *)chars);
return intArray;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: NativeInitGlyphImage
* Signature: (Lorg/apache/harmony/awt/gl/font/Glyph;)[B
* Description: Getting glyph raster using GetGlyphOutline - faster method
* We obtain only glyph representation in the "black box" the smallest box, surrounding glyph.
*/
JNIEXPORT jbyteArray JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_NativeInitGlyphImage(JNIEnv *env, jclass jobj, jobject glyph){
jclass cls;
jmethodID mid;
jbyteArray bmp;
HFONT hFont;
HGDIOBJ hOld;
MAT2 mat2;
GLYPHMETRICS gMetrics;
int bitsSize, size;
DWORD * pBits; // glyph bits array pointer
jchar uChar;
HDC hDC = CreateCompatibleDC(NULL);
// cls - instance of Glyph class
cls = env->GetObjectClass(glyph);
// Get "Glyph.pFont" value
mid=env->GetMethodID(cls,
"getPFont",
"()J");
if (mid == 0) {
// "Can't find method getChar"
env->ExceptionDescribe();
env->ExceptionClear();
DeleteDC(hDC);
return NULL;
}
hFont = (HFONT)env->CallLongMethod(glyph, mid);
// Get "Glyph.getChar()" value
mid=env->GetMethodID(cls,
"getChar",
"()C");
if (mid == 0) {
// "Can't find method getChar"
env->ExceptionDescribe();
env->ExceptionClear();
DeleteDC(hDC);
return NULL;
}
uChar = env->CallCharMethod(glyph, mid);
ZeroMemory(&mat2, sizeof(MAT2));
mat2.eM11.value = 1;
mat2.eM22.value = 1;
hOld = SelectObject(hDC, hFont);
bitsSize = GetGlyphOutline(hDC, uChar, GGO_BITMAP, & gMetrics, 0, NULL, &mat2);
if (bitsSize==GDI_ERROR){
throwNPException(env, "Error occured during getting glyph outline in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
size = bitsSize;
pBits = (DWORD *)malloc(size); // memory allocation for bits data
bmp = env->NewByteArray(size); // resulting Int Array ;
bitsSize = GetGlyphOutline(hDC, uChar, GGO_BITMAP, & gMetrics, bitsSize, pBits, &mat2);
if ( bitsSize==GDI_ERROR){
throwNPException(env, "Error occured during getting glyph outline in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
free(pBits);
return NULL;
}
if ( bitsSize== 0){
// Empty glyph like SPACE
SelectObject(hDC, hOld);
DeleteDC(hDC);
free(pBits);
return NULL;
}
env->SetByteArrayRegion(bmp, 0, size, (jbyte *)pBits);
SelectObject(hDC, hOld);
DeleteDC(hDC);
free(pBits);
return bmp;
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getGlyphCodeNative
* Signature: (JLjava/lang/String;I)[I
* Description: Returns Glyph code corresponding to the specified character.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getGlyphCodeNative(JNIEnv *env, jclass obj, jlong fnt, jchar chr) {
HFONT hFont = (HFONT)fnt; // Font object handle
HGDIOBJ hOld;
WORD gi[1]; // Vector of indices
int size;
TCHAR uChr[1];
HDC hDC = CreateCompatibleDC(NULL);
uChr[0] = (TCHAR)chr;
hOld = SelectObject(hDC, hFont);
size = GetGlyphIndices(hDC, uChr, 1, gi, 0);//GGI_MARK_NONEXISTING_GLYPHS);
if (size==GDI_ERROR){
throwNPException(env, "Error occured during getting glyph indices in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return 0;
}
SelectObject(hDC, hOld);
DeleteDC(hDC);
return (size == 0)?0:gi[0];
}
/*
* Class: org_apache_harmony_awt_gl_font_NativeFont
* Method: getGlyphOutline
* Signature: (JCJ)I
* Description: Sets Glyph outline corresponding to the specified character to
* the buffer parameter.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getGlyphOutline
(JNIEnv *env, jclass obj, jlong fnt, jchar uChar, jlong buffer, jint size){
HFONT hFont = (HFONT)fnt; // Font object handle
HGDIOBJ hOld;
MAT2 mat2;
GLYPHMETRICS g_metrics;
HDC hDC = CreateCompatibleDC(NULL);
hOld = SelectObject(hDC, hFont);
// Set transform matrix values to identity matrix values
ZeroMemory(&mat2, sizeof(MAT2));
mat2.eM11.value = 1;
mat2.eM12.value = 0;
mat2.eM21.value = 0;
mat2.eM22.value = 1;
size = GetGlyphOutline(hDC, uChar, GGO_NATIVE, &g_metrics, size, (LPVOID)buffer, &mat2);
SelectObject(hDC, hOld);
DeleteDC(hDC);
if (size==GDI_ERROR){
throwNPException(env, "GDI :: GetGlyphOutline Error.");
return 0;
}
return size;
}
/* Call back function that enumerates system locales */
BOOL CALLBACK EnumLocalesProc(LPTSTR lpLocaleString){
LCID localeID = 0;
TCHAR countryName[5] = {0};
TCHAR langName[5] = {0};
localeID = (LCID)_tcstoi64(lpLocaleString, NULL, 16 );
if (GetLocaleInfo ( localeID, LOCALE_SISO639LANGNAME , langName, sizeof(langName))){
lcidTable.lcids[lcidTable.count] = LANGIDFROMLCID(localeID);
_tcscat(lcidTable.names[lcidTable.count], langName);
if(GetLocaleInfo ( localeID, LOCALE_SISO3166CTRYNAME, countryName, sizeof(countryName))){
_tcscat(lcidTable.names[lcidTable.count], L"_");
_tcscat(lcidTable.names[lcidTable.count], countryName);
}
lcidTable.count++;
}
return TRUE;
}
/* Initialize arrays of short LCID strings and LCID values arrays.
Returns size of arrays if success, otherwise returns 0.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_nativeInitLCIDsTable
(JNIEnv *env, jclass obj, jobjectArray shortStrings, jshortArray LCIDs){
int size;
int i;
if ((shortStrings == NULL) || (LCIDs == NULL)){
EnumSystemLocales(EnumLocalesProc, // callback function
LCID_SUPPORTED // locales
);
return lcidTable.count;
}
size = lcidTable.count;
env->SetShortArrayRegion(LCIDs, 0, size, lcidTable.lcids);
for (i = 0; i < size; i++){
env->SetObjectArrayElement(shortStrings, i, env->NewString((const jchar *)(TCHAR *)lcidTable.names[i], (jsize)_tcslen(lcidTable.names[i])));
}
return size;
}
/*
* Returns desired tag index from the list.
*/
int getTagIndex(Tag* tagList, int count, Tag value){
int result = -1;
int i;
for (i = 0; i < count; i++){
if (strncmp((char *)&tagList[i], (char *)value, 4) == 0){
return result = i;
}
}
return result;
}
/*
* Sets antialiasing mode using GDI+ objects defined in graphics info.
*/
JNIEXPORT void JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_setAntialiasing(JNIEnv *env, jclass obj,
jlong gfxInfo, jboolean isAntialiasing){
GraphicsInfo *gi = (GraphicsInfo *)gfxInfo;
Graphics *graphics = (Graphics *)gi->graphics;
if(isAntialiasing)
graphics->SetTextRenderingHint(TextRenderingHintAntiAlias);
else
graphics->SetTextRenderingHint(TextRenderingHintSingleBitPerPixel);
}
/*
* Draws string at the specified coordinates using GDI+ objects defined in graphics info.
* This method is applicable for drawing without affine transformes.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_gdiPlusDrawText
(JNIEnv *env, jclass obj, jlong gfxInfo, jstring jText, jint length,
jlong font, jfloat xOffset, jfloat yOffset){
int result = 0;
GraphicsInfo *gi = (GraphicsInfo *)gfxInfo;
HFONT hFont = (HFONT)font;
HDC giHDC = (HDC)gi->hdc;
Graphics *graphics = (Graphics *)gi->graphics;
Brush *brush = (Brush *)gi->brush;
const TCHAR *text;
jboolean iscopy;
Font *gdipFont = new Font(giHDC, hFont);
PointF *origin = new PointF(xOffset, yOffset);
text = (const TCHAR *)env->GetStringCritical( jText, &iscopy);
result = graphics->DrawString(text,
length,
gdipFont,
*origin,
brush);
env->ReleaseStringCritical(jText, (const jchar *)text);
delete origin;
delete gdipFont;
return result;
}
/*
* Draws transformed char according to the matrix at the specified position.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_gdiPlusDrawDriverChar
(JNIEnv *env, jclass obj, jlong gfxInfo, jchar chr, jlong font, jfloat x, jfloat y, jint flags, jdoubleArray jAT){
int result;
const UINT16 *text = &((UINT16)chr);
HFONT hFont = (HFONT)font;
GraphicsInfo *gi = (GraphicsInfo *)gfxInfo;
HDC giHDC = (HDC)gi->hdc;
Graphics *graphics = (Graphics *)gi->graphics;
Brush *brush = (Brush *)gi->brush;
Font *gdipFont = new Font(giHDC, hFont);
PointF *origin = new PointF(x, y);
double *at = env->GetDoubleArrayElements(jAT, NULL);
Matrix *matrix = new Matrix((REAL)at[0],(REAL)at[1],(REAL)at[2],(REAL)at[3],(REAL)at[4],(REAL)at[5]);
env->ReleaseDoubleArrayElements(jAT, at, JNI_ABORT);
// save original transform
Matrix *matrixOld = new Matrix();
graphics->GetTransform(matrixOld);
graphics->SetTransform(gi->matrix);
result = graphics->DrawDriverString(text,
1,
gdipFont,
brush,
origin,
flags,
matrix);
graphics->SetTransform(matrixOld);
delete matrixOld;
delete origin;
delete matrix;
delete gdipFont;
return result;
}
/*
* Draws string transformed according to the matrix, each character is drawn at
* the specified positions.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_gdiPlusDrawDriverString
(JNIEnv *env, jclass obj, jlong gfxInfo, jstring jText, jint length, jlong font, jfloat x, jfloat y, jdoubleArray jPosArray, jint flags, jdoubleArray jAT){
int result;
HFONT hFont = (HFONT)font;
GraphicsInfo *gi = (GraphicsInfo *)gfxInfo;
HDC giHDC = (HDC)gi->hdc;
Graphics *graphics = (Graphics *)gi->graphics;
Brush *brush = (Brush *)gi->brush;
Font *gdipFont = new Font(giHDC, hFont);
PointF *origin = new PointF(x, y);
double *at = env->GetDoubleArrayElements(jAT, NULL);
Matrix *matrix = new Matrix((REAL)at[0],(REAL)at[1],(REAL)at[2],(REAL)at[3],(REAL)at[4],(REAL)at[5]);
env->ReleaseDoubleArrayElements(jAT, at, JNI_ABORT);
// save original transform
Matrix *matrixOld = new Matrix();
graphics->GetTransform(matrixOld);
graphics->SetTransform(gi->matrix);
double *posArray = env->GetDoubleArrayElements(jPosArray, NULL);
PointF *positions = new PointF[length];
for(int i=0; i< length; i ++){
positions[i].X = (REAL)(posArray[2*i] + x);
positions[i].Y = (REAL)(posArray[2*i+1] + y);
}
env->ReleaseDoubleArrayElements(jPosArray, posArray, JNI_ABORT);
const UINT16 *text = env->GetStringCritical( jText, NULL);
result = graphics->DrawDriverString(text,
length,
gdipFont,
brush,
positions,
flags,
matrix);
env->ReleaseStringCritical(jText, text);
graphics->SetTransform(matrixOld);
delete matrixOld;
delete gdipFont;
delete origin;
delete matrix;
delete[] positions;
return result;
}
/*
* Draws string transformed according to the matrix, each character is drawn at
* the specified positions.
*/
JNIEXPORT jint JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_gdiPlusDrawDriverChars
(JNIEnv *env, jclass obj, jlong gfxInfo, jcharArray jText, jint length, jlong font, jdoubleArray jPosArray, jint flags, jdoubleArray jAT){
int result;
HFONT hFont = (HFONT)font;
GraphicsInfo *gi = (GraphicsInfo *)gfxInfo;
HDC giHDC = (HDC)gi->hdc;
Graphics *graphics = (Graphics *)gi->graphics;
Brush *brush = (Brush *)gi->brush;
Font *gdipFont = new Font(giHDC, hFont);
double *at = env->GetDoubleArrayElements(jAT, NULL);
Matrix *matrix = new Matrix((REAL)at[0],(REAL)at[1],(REAL)at[2],(REAL)at[3],(REAL)at[4],(REAL)at[5]);
env->ReleaseDoubleArrayElements(jAT, at, JNI_ABORT);
double *posArray = (double *)malloc(length*2 * sizeof(double));
env->GetDoubleArrayRegion(jPosArray, 0, length*2, posArray);
PointF *positions = new PointF[length];
for(int i=0; i< length; i ++){
positions[i].X = (REAL)(posArray[2*i]);
positions[i].Y = (REAL)(posArray[2*i+1]);
}
free(posArray);
jchar *text = (jchar *)malloc(length * sizeof(jchar));
env->GetCharArrayRegion(jText, 0, length, text);
graphics->SetTransform(gi->matrix);
result = graphics->DrawDriverString((const UINT16 *)text,
length,
gdipFont,
brush,
positions,
flags,
matrix);
free(text);
graphics->ResetTransform();
delete gdipFont;
delete matrix;
delete[] positions;
return result;
}
/* Returns float array of x and y values from array of POINTFX elements. */
JNIEXPORT jfloatArray JNICALL Java_org_apache_harmony_awt_gl_font_WinGlyph_getPoints
(JNIEnv *env, jclass obj, jlong points, jint size){
jfloatArray flArray;
float * fpPoints = (float *)malloc(sizeof(float) * size * 2);
int i;
POINTFX *pointfx = (POINTFX *)points;
for(i = 0; i < size; i++){
fpPoints[i*2] = pointfx[i].x.value + pointfx[i].x.fract /65536.0f + 0.5f;
fpPoints[i*2 + 1] = -pointfx[i].y.value - pointfx[i].y.fract /65536.0f + 0.5f;
}
flArray=env->NewFloatArray(size*2);
env->SetFloatArrayRegion(flArray, 0, size*2, fpPoints);
free(fpPoints);
return flArray;
}
/* Releases hdc object in GDI+ Graphics object from the GraphicsInfo. */
JNIEXPORT void JNICALL Java_org_apache_harmony_awt_gl_font_NativeFont_gdiPlusReleaseHDC
(JNIEnv *env, jclass obj, jlong gfxInfo, jlong hdc){
GraphicsInfo *gi = (GraphicsInfo *)gfxInfo;
Graphics *graphics = (Graphics *)gi->graphics;
graphics->ReleaseHDC((HDC)hdc);
}
/* Returns hdc object of the GDI+ Graphics object from the GraphicsInfo. */
JNIEXPORT jlong JNICALL Java_org_apache_harmony_awt_gl_font_NativeFont_gdiPlusGetHDC
(JNIEnv *env, jclass obj, jlong gfxInfo){
GraphicsInfo *gi = (GraphicsInfo *)gfxInfo;
Graphics *graphics = (Graphics *)gi->graphics;
return (jlong)graphics->GetHDC();
}
/*
* Returns an array of extra font metrics result[]:
* result[0] - average width of characters in the font
* result[1] - horizontal size for subscripts
* result[2] - vertical size for subscripts
* result[3] - horizontal offset for subscripts
* result[4] - vertical offset value for subscripts
* result[5] - horizontal size for superscripts
* result[6] - vertical size for superscripts
* result[7] - horizontal offset for superscripts
* result[8] - vertical offset for superscripts
*/
JNIEXPORT jfloatArray JNICALL
Java_org_apache_harmony_awt_gl_font_NativeFont_getExtraMetricsNative(JNIEnv *env, jclass obj, jlong fnt, jint fontSize, jint fontType) {
// XXX: Subscript/superscript metrics are undefined for Type1. As a possible
// solution for Type1 we can use coefficients obtained from the TrueType values
// (e.g. for the type1 font size 12 SubscriptSizeX coefficient equals
// to the truetype font size 12 SubscriptSizeX value / size of the font):
// SubscriptSizeX == 0.7 * fontSize
// SubscriptSizeY == 0.65 * fontSize
// SubscriptOffsetX == 0
// SubscriptOffsetY == 0.15 * fontSize
// SuperscriptSizeX == 0.7 * fontSize
// SuperscriptSizeY == 0.65 * fontSize
// SuperscriptOffsetX == 0
// SuperscriptOffsetY == 0.45 * fontSize
HFONT hFont = (HFONT)fnt;
HGDIOBJ hOld;
OUTLINETEXTMETRIC outm[3];
jfloat result[9];
jfloatArray floatArray;
HDC hDC = CreateCompatibleDC(NULL);
DWORD size;
TEXTMETRIC tm;
HGDIOBJ hFontEM;
LOGFONT lf;
int emsquare;
float mltpl;
hOld = SelectObject(hDC, hFont);
// Getting current size of Font
size = GetOutlineTextMetrics(hDC, sizeof(outm), outm);
if (size == 0 ){
throwNPException(env, "Error occured during getting text outline metrics in native code.");
SelectObject(hDC, hOld);
DeleteDC(hDC);
return NULL;
}
if (fontType == FONT_TYPE_TT) {
emsquare = outm[0].otmEMSquare; // EM Square size
// Create font with height == "EM Square size" in device units to
// get multyply factor
GetObject(hFont, sizeof(lf), &lf);
lf.lfHeight = -emsquare;
lf.lfWidth = 0;
hFontEM = CreateFontIndirect(&lf);
SelectObject(hDC, hFontEM);
size = GetOutlineTextMetrics(hDC, sizeof(outm), outm);
if (size == 0 ){
throwNPException(env, "Error occured during getting text outline metrics in native code.");
SelectObject(hDC, hOld);
DeleteObject(hFontEM);
DeleteDC(hDC);
return NULL;
}
tm = outm[0].otmTextMetrics;
// Multiplier for the precise values
mltpl = (float)fontSize/emsquare;
result[0] = tm.tmAveCharWidth * mltpl; // the average width of characters in the font
result[1] = outm[0].otmptSubscriptSize.x * mltpl; // horizontal size for subscripts
result[2] = outm[0].otmptSubscriptSize.y * mltpl; // vertical size for subscripts
result[3] = outm[0].otmptSubscriptOffset.x * mltpl; // horizontal offset for subscripts
result[4] = outm[0].otmptSubscriptOffset.y * mltpl; // vertical offset value for subscripts
result[5] = outm[0].otmptSuperscriptSize.x * mltpl; // horizontal size for superscripts
result[6] = outm[0].otmptSuperscriptSize.y * mltpl; // vertical size for superscripts
result[7] = outm[0].otmptSuperscriptOffset.x * mltpl; // horizontal offset for superscripts
result[8] = outm[0].otmptSuperscriptOffset.y * mltpl; // vertical offset for superscripts
} else {
result[1] = 0.7f * fontSize;
result[2] = 0.65f * fontSize;
result[3] = 0.0f;
result[4] = 0.15f * fontSize;
result[5] = 0.7f * fontSize;
result[6] = 0.65f * fontSize;
result[7] = 0.0f;
result[8] = 0.45f * fontSize;
}
SelectObject(hDC, hOld);
DeleteDC(hDC);
floatArray=env->NewFloatArray(9);
env->SetFloatArrayRegion(floatArray, 0, 9, result);
return floatArray;
}