#include "awt_font.h"
#ifdef INTLUNICODE
#include "awt_vf.h"
#endif
#include "prprf.h" // PR_snprintf(...)
// All java header files are extern "C"
extern "C" {
#include "java_awt_Font.h"
#include "sun_awt_windows_WFontMetrics.h"
};
#define FONT_PTR(_qp) ((AwtFont*) ((char*)(_qp) - offsetof(AwtFont,m_link)))
//#define DEBUG_GDI
AwtCList AwtFont::m_fontList;
AwtMutex AwtFont::m_fontMutex;
//-------------------------------------------------------------------------
//
// The AwtFaceMap is a mapping between a platform-independent Awt
// font family and the Windows font used to represent it...
//
//
// Table of font mappings...
//
// m_faceNameMap[0] contains the default font used when a match is not
// found...
//
//-------------------------------------------------------------------------
AwtFont::AwtFaceMap AwtFont::m_faceNameMap[] = {
{ 0 , "Arial" }, // Default font
{ "Helvetica" , "Arial" },
{ "TimesRoman" , "Times New Roman" },
{ "Courier" , "Courier New" },
{ "Dialog" , "MS Sans Serif" },
{ "DialogInput" , "MS Sans Serif" },
{ "ZapfDingbats", "WingDings" },
{ 0 , 0 }
};
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
AwtFont::AwtFont(Hjava_awt_Font *peer) : AwtObject((JHandle *)peer)
{
m_refCount = 1;
m_lockCount = 0;;
*m_fontKey = '\0';
//
// Initialize the font to the System font. This insures that
// the m_hFont member is ALWAYS valid...
//
m_hFont = (HFONT)::GetStockObject(SYSTEM_FONT);
#ifdef INTLUNICODE
m_vFontList = NULL;
#endif
HDC hDC;
VERIFY( hDC = ::GetDC(::GetDesktopWindow()) );
if (hDC)
{
//
// Get the text metrics information about the requested font
//
::SelectObject(hDC, (HGDIOBJ)m_hFont);
TEXTMETRIC metrics;
VERIFY( ::GetTextMetrics(hDC, &metrics) );
m_nAscent = metrics.tmAscent;
VERIFY( ::ReleaseDC(::GetDesktopWindow(), hDC) );
}
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
AwtFont::~AwtFont()
{
// Delete the font resource
if (m_hFont) {
VERIFY( ::DeleteObject(m_hFont) );
#ifdef DEBUG_GDI
char buf[100];
wsprintf(buf, "Delete Font = 0x%x, thrid=%d\n",m_hFont, PR_GetCurrentThreadID() );
OutputDebugString(buf);
#endif
m_hFont = 0;
}
#ifdef INTLUNICODE
if(m_vFontList)
{
delete m_vFontList;
m_vFontList = NULL;
}
#endif
//
// Remove the object from the cache...
//
m_fontMutex.Lock();
m_link.Remove();
m_fontMutex.Unlock();
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtFont::Dispose(void)
{
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
BOOL AwtFont::CallMethod(AwtMethodInfo *info)
{
return FALSE;
}
//-------------------------------------------------------------------------
//
// Return an AwtFont object which corresponds to a java.awt.Font object.
//
// The AwtFont is reference counted. So, Release() must be called on
// EVERY object returned by FindFont!!
//
//-------------------------------------------------------------------------
AwtFont *AwtFont::FindFont(Hjava_awt_Font *font)
{
AwtCList *qp;
AwtFont *pFont;
AwtFont *pNewFont = NULL;
char fontKey[ AWT_FONT_KEY_SIZE ];
m_fontMutex.Lock();
//
// Check if the java_awt_Font object already has an AwtFont
// associated with it...
//
if (unhand(font)->pData) {
pNewFont = (AwtFont *)unhand(font)->pData;
pNewFont->m_refCount++;
}
else {
//
// Create the font key...
//
AwtFont::GetFontKey(font, fontKey, sizeof(fontKey));
ASSERT( *fontKey != '\0' );
//
// Scan the list of allocated fonts to see if the requested font
// has already been created...
//
qp = m_fontList.next;
while (qp != &m_fontList) {
pFont = FONT_PTR(qp);
if (strcmp(pFont->m_fontKey, fontKey) == 0) {
unhand(font)->pData = (long)pFont;
pNewFont = pFont;
pNewFont->m_refCount++;
break;
}
qp = qp->next;
}
//
// Allocate a new font...
//
// Because a single AwtFont can be associated with many java fonts
// NULL is passed into the constructor since no back pointer is
// possible.
//
if (pNewFont == NULL) {
pNewFont = new AwtFont(NULL);
pNewFont->Initialize(font);
unhand(font)->pData = (long)pNewFont;
m_fontList.Append(pNewFont->m_link);
}
}
m_fontMutex.Unlock();
return pNewFont;
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtFont::GetFontKey(Hjava_awt_Font *pJavaObject, char *fontKey, int len)
{
const char *lpszFaceName;
ASSERT( (fontKey != NULL) && len );
lpszFaceName = AwtFont::MapFamilyToFont(pJavaObject);
PR_snprintf(fontKey, len, "%s-%d-%d", lpszFaceName,
unhand(pJavaObject)->style, unhand(pJavaObject)->size);
}
//-------------------------------------------------------------------------
//
// Convert an Awt font family into a Windows font face name
//
//-------------------------------------------------------------------------
const char *AwtFont::MapFamilyToFont(Hjava_awt_Font *pJavaObject)
{
Classjava_awt_Font *pFontObject;
char buffer[ 256 ];
const char *lpszFaceName;
AwtFaceMap *pEntry;
//
// Get the name of the Awt font family
//
pFontObject = unhand(pJavaObject);
javaString2CString(pFontObject->family, buffer, sizeof(buffer));
//
// Locate the Windows font which maps to the requested font family
//
lpszFaceName = AwtFont::m_faceNameMap[0].faceName;
pEntry = AwtFont::m_faceNameMap + 1;
while (pEntry->family) {
if( strcmp(pEntry->family, buffer) == 0 ) {
lpszFaceName = pEntry->faceName;
break;
}
pEntry++;
}
return lpszFaceName;
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtFont::Initialize(Hjava_awt_Font *peer)
{
LOGFONT logFont;
Classjava_awt_Font *pFontObject;
pFontObject = unhand(peer);
//
// Set up the LOGFONT structure
//
logFont.lfWidth = 0;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfCharSet = ANSI_CHARSET;
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = DEFAULT_QUALITY;
logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
//
// Set the font style...
// Java supports 3 different styles: Plain, Bold, and Italic
//
logFont.lfWeight = (pFontObject->style & java_awt_Font_BOLD)
? FW_BOLD : FW_NORMAL;
logFont.lfItalic = (pFontObject->style & java_awt_Font_ITALIC)
? TRUE : FALSE;
// Set the point size...
logFont.lfHeight = -pFontObject->size;
// Set the face name
strncpy(logFont.lfFaceName,
AwtFont::MapFamilyToFont(peer),
LF_FACESIZE);
//
// Create the windows font
//
VERIFY( m_hFont = ::CreateFontIndirect(&logFont) );
#ifdef DEBUG_GDI
char buf[100];
wsprintf(buf, "Create Font = 0x%x, thrid=%d\n",m_hFont, PR_GetCurrentThreadID() );
OutputDebugString(buf);
#endif
#ifdef INTLUNICODE
VERIFY( m_vFontList = new AwtVFontList(logFont.lfHeight,
logFont.lfWeight,
logFont.lfItalic,
AwtVFontList::MapFamilyToVFontID(peer)
));
#endif
HDC hDC;
VERIFY( hDC = ::GetDC(::GetDesktopWindow()) );
if (hDC)
{
//
// Get the text metrics information about the requested font
//
::SelectObject(hDC, (HGDIOBJ)m_hFont);
TEXTMETRIC metrics;
VERIFY( ::GetTextMetrics(hDC, &metrics) );
m_nAscent = metrics.tmAscent;
VERIFY( ::ReleaseDC(::GetDesktopWindow(), hDC) );
}
//
// Initialize the font key so subsequent requests will return the
// same AwtFont instance
//
AwtFont::GetFontKey(peer, m_fontKey,
sizeof(m_fontKey));
}
//-------------------------------------------------------------------------
//
// Select or remove a font in a GDI DC
//
//-------------------------------------------------------------------------
void AwtFont::Select( HDC hDC, BOOL bFlag )
{
if (bFlag) {
VERIFY( ::SelectObject(hDC, m_hFont) );
m_lockCount++;
}
else {
--m_lockCount;
}
}
//-------------------------------------------------------------------------
// The following function is needed when making a copy of this font.
// The only other way to increment this counter is via FindFont. But
// FindFont needs 3 parameters which cannot be queried back from AwtFont.
// REMIND: I think we should be able to query back this stuff.
//-------------------------------------------------------------------------
void AwtFont::AddRef()
{
m_fontMutex.Lock();
m_refCount++;
m_fontMutex.Unlock();
}
//-------------------------------------------------------------------------
//
// Release an AwtFont object. If this is the last reference to the
// object, then delete it !!
//
//-------------------------------------------------------------------------
void AwtFont::Release( void )
{
m_fontMutex.Lock();
if (--m_refCount == 0) {
m_fontMutex.Unlock();
delete this;
} else {
m_fontMutex.Unlock();
}
}
//-------------------------------------------------------------------------
//
// This method DOES NOT increment the reference count on the AwtFont
// which is returned!
//
//-------------------------------------------------------------------------
AwtFont * AwtFont::GetFontFromObject(Hjava_awt_Font *peer)
{
AwtFont *obj;
obj = GET_OBJ_FROM_FONT(peer);
if (obj == NULL) {
obj = AwtFont::FindFont(peer);
ASSERT(obj);
}
return obj;
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
void AwtFont::LoadFontMetrics(HWFontMetrics *self)
{
WFontMetrics *pMetrics = unhand(self);
HDC hDC;
TEXTMETRIC metrics;
int i;
SIZE size;
char character;
long *pCharWidths;
//
// Allocate a java array to store the width of each character in
// the requested font...
//
pMetrics->widths = (HArrayOfInt *)ArrayAlloc(T_INT, 256);
CHECK_ALLOCATION( pMetrics->widths );
pCharWidths = unhand(pMetrics->widths)->body;
CHECK_ALLOCATION( pCharWidths );
//
// Zero out the entire array of character widths...
//
pCharWidths = unhand(pMetrics->widths)->body;
memset(pCharWidths, 0, 256 * sizeof(long));
//
// Get a display DC to calculate the necessary font information...
//
VERIFY( hDC = ::GetDC(::GetDesktopWindow()) );
if (hDC) {
//
// Get the text metrics information about the requested font
//
::SelectObject(hDC, (HGDIOBJ)m_hFont);
VERIFY(::GetTextMetrics(hDC, &metrics));
//
// Initialize the font metric information stored in the
// WFontMetrics object...
//
m_nAscent = pMetrics->ascent = metrics.tmAscent;
pMetrics->descent = metrics.tmDescent;
pMetrics->leading = metrics.tmExternalLeading;
pMetrics->height = metrics.tmExternalLeading + metrics.tmHeight;
pMetrics->maxAdvance = metrics.tmMaxCharWidth;
pMetrics->maxAscent = pMetrics->ascent;
pMetrics->maxDescent = pMetrics->descent;
pMetrics->maxHeight = pMetrics->height;
//
// Fill in the widths of each character in the font
//
pCharWidths += metrics.tmFirstChar;
for (i=metrics.tmFirstChar; i<=metrics.tmLastChar; ++i) {
character = (char)i;
#if defined(_WIN32)
VERIFY( ::GetTextExtentPoint32(hDC, &character, 1, &size) );
#else
VERIFY( ::GetTextExtentPoint(hDC, &character, 1, &size) );
#endif
*pCharWidths++ = size.cx;
}
#ifdef INTLUNICODE
if(m_vFontList)
{
m_vFontList->LoadFontMetrics(hDC, pMetrics);
m_nAscent = pMetrics->ascent ;
}
#endif
VERIFY( ::ReleaseDC(::GetDesktopWindow(), hDC) );
}
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
long AwtFont::StringWidth(HWFontMetrics *self, Hjava_lang_String *string)
{
HArrayOfChar * data;
int32_t len;
int32_t offset;
data = unhand(string)->value;
offset = unhand(string)->offset;
// "count - offset" seems to be really wrong. In fact offset represents the
// value inside the array from which the string starts, count is the
// length of the string. The idea is to have a single long buffer it can
// be used for multiple strings. It is clear so that count and offset have no
// reletionship at all in order to make the string length.
//len = unhand(string)->count - offset;
len = unhand(string)->count;
return StringWidth(self, data, offset, len);
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
long AwtFont::StringWidth(HWFontMetrics *self, HArrayOfChar *string,
long offset, long len)
{
unicode *s;
long w;
int32_t ch;
int32_t *widths;
int widlen;
WFontMetrics * fm;
w = 0;
fm = (WFontMetrics *)unhand(self);
if ((len < 0) || (offset < 0) ||
(len + offset > (long)obj_length(string))) {
SignalError(0, JAVAPKG "ArrayIndexOutOfBoundsException", 0);
return 0;
}
// Load the width table if necessary
if (fm->widths == NULL) {
LoadFontMetrics(self);
}
if (fm->widths) {
widths = unhand(fm->widths)->body;
widlen = obj_length(fm->widths);
s = unhand(string)->body + offset;
//
// Compute the total width by accumulating the width of each
// character in the array.
//
// If a character's width is unknown (ie. not in widths array)
// then assume the maximum width and continue...
//
while (--len >= 0) {
ch = *s++;
if (ch < widlen) {
w += widths[ch];
} else {
w += fm->maxAdvance;
}
}
} else {
//
// If no widths array is available, then assume every character
// is of maximum width...
//
w = fm->maxAdvance * len;
}
return w;
}
//-------------------------------------------------------------------------
//
//
//-------------------------------------------------------------------------
long AwtFont::StringWidth(HWFontMetrics *self, HArrayOfByte *buffer,
long offset, long len)
{
long w;
unsigned char * s;
int32 ch;
int32_t * widths;
int widlen;
WFontMetrics * fm;
w = 0;
fm = (WFontMetrics *)unhand(self);
if ((len < 0) || (offset < 0) ||
(len + offset > (long)obj_length(buffer))) {
SignalError(0, JAVAPKG "ArrayIndexOutOfBoundsException", 0);
return 0;
}
// Load the width table if necessary
if (fm->widths == NULL) {
LoadFontMetrics(self);
}
if (fm->widths) {
widths = unhand(fm->widths)->body;
widlen = obj_length(fm->widths);
s = (unsigned char *)unhand(buffer)->body + offset;
//
// Compute the total width by accumulating the width of each
// character in the array.
//
// If a character's width is unknown (ie. not in widths array)
// then assume the maximum width and continue...
//
while (--len >= 0) {
ch = *s++;
if (ch < widlen) {
w += widths[ch];
} else {
w += fm->maxAdvance;
}
}
} else {
//
// If no widths array is available, then assume every character
// is of maximum width...
//
w = fm->maxAdvance * len;
}
return w;
}
#ifdef INTLUNICODE
HGDIOBJ AwtFont::GetFontForEncoding(int16 encoding)
{
// For Latin 1, we also use the m_hFont in AwtFont;
if((encoding != CS_LATIN1) && (m_vFontList))
return m_vFontList->GetVFont(encoding);
else
return m_hFont;
}
#endif
//-------------------------------------------------------------------------
//
// Native methods for sun.awt.windows.WFontMetrics
//
//-------------------------------------------------------------------------
extern "C" {
void
sun_awt_windows_WFontMetrics_loadFontMetrics(HWFontMetrics *self)
{
AwtFont *obj;
CHECK_NULL( self, "WFontMetrics is NULL" );
CHECK_NULL( unhand(self)->font, "The FontMetrics has no font" );
if ((obj = AwtFont::GetFontFromObject(unhand(self)->font)) != NULL) {
obj->LoadFontMetrics(self);
}
}
long
sun_awt_windows_WFontMetrics_stringWidth(HWFontMetrics *self,
Hjava_lang_String *str)
{
AwtFont *obj;
long width = 0;
CHECK_NULL_AND_RETURN( self, "WFontMetrics is NULL", 0 );
CHECK_NULL_AND_RETURN( str, "java_lang_String is NULL", 0 );
CHECK_NULL_AND_RETURN( unhand(self)->font, "The FontMetrics has no font", 0 );
if ((obj = AwtFont::GetFontFromObject(unhand(self)->font)) != NULL) {
width = obj->StringWidth(self, str);
}
return width;
}
long
sun_awt_windows_WFontMetrics_charsWidth(HWFontMetrics *self,
HArrayOfChar *str, long off, long len)
{
AwtFont *obj;
long width = 0;
CHECK_NULL_AND_RETURN( self, "WFontMetrics is NULL", 0 );
CHECK_NULL_AND_RETURN( str, "HArrayOfChar is NULL", 0 );
CHECK_NULL_AND_RETURN( unhand(self)->font, "The FontMetrics has no font", 0 );
if ((obj = AwtFont::GetFontFromObject(unhand(self)->font)) != NULL) {
width = obj->StringWidth(self, str, off, len);
}
return width;
}
long
sun_awt_windows_WFontMetrics_bytesWidth(HWFontMetrics *self,
HArrayOfByte *buf, long off, long len)
{
AwtFont *obj;
long width = 0;
CHECK_NULL_AND_RETURN( self, "WFontMetrics is NULL", 0 );
CHECK_NULL_AND_RETURN( buf, "HArrayOfByte is NULL", 0 );
CHECK_NULL_AND_RETURN( unhand(self)->font, "The FontMetrics has no font", 0 );
if ((obj = AwtFont::GetFontFromObject(unhand(self)->font)) != NULL) {
width = obj->StringWidth(self, buf, off, len);
}
return width;
}
void
java_awt_Font_dispose(Hjava_awt_Font *self)
{
AwtFont *obj = (AwtFont *)(unhand(self)->pData);
if (obj) {
obj->Release();
unhand(self)->pData = 0;
}
}
}; // end of extern "C"