1 /*
   2  * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <math.h>
  27 #include "jlong.h"
  28 #include "awt_Font.h"
  29 #include "awt_Toolkit.h"
  30 
  31 #include "java_awt_Font.h"
  32 #include "java_awt_FontMetrics.h"
  33 #include "java_awt_Dimension.h"
  34 
  35 #include "sun_awt_FontDescriptor.h"
  36 #include "sun_awt_windows_WDefaultFontCharset.h"
  37 #include "sun_awt_windows_WFontPeer.h"
  38 #include "awt_Component.h"
  39 #include "Disposer.h"
  40 
  41 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
  42  */
  43 
  44 AwtFontCache fontCache;
  45 
  46 extern jboolean IsMultiFont(JNIEnv *env, jobject obj)
  47 {
  48     if (obj == NULL) {
  49         return JNI_FALSE;
  50     }
  51     if (env->EnsureLocalCapacity(2))
  52         return JNI_FALSE;
  53     jobject peer = env->CallObjectMethod(obj, AwtFont::peerMID);
  54     if (peer == NULL) {
  55         return JNI_FALSE;
  56     }
  57     jobject fontConfig = env->GetObjectField(peer, AwtFont::fontConfigID);
  58     jboolean result = fontConfig != NULL;
  59     env->DeleteLocalRef(peer);
  60     env->DeleteLocalRef(fontConfig);
  61     return result;
  62 }
  63 
  64 extern jstring GetTextComponentFontName(JNIEnv *env, jobject font)
  65 {
  66     DASSERT(font != NULL);
  67     if (env->EnsureLocalCapacity(2)) {
  68         return NULL;
  69     }
  70     jobject peer = env->CallObjectMethod(font, AwtFont::peerMID);
  71     DASSERT(peer != NULL);
  72     jstring textComponentFontName =
  73             (jstring) env->GetObjectField(peer, AwtFont::textComponentFontNameID);
  74     env->DeleteLocalRef(peer);
  75     return textComponentFontName;
  76 }
  77 
  78 /************************************************************************
  79  * AwtFont fields
  80  */
  81 
  82 /* sun.awt.windows.WFontMetrics fields */
  83 jfieldID AwtFont::widthsID;
  84 jfieldID AwtFont::ascentID;
  85 jfieldID AwtFont::descentID;
  86 jfieldID AwtFont::leadingID;
  87 jfieldID AwtFont::heightID;
  88 jfieldID AwtFont::maxAscentID;
  89 jfieldID AwtFont::maxDescentID;
  90 jfieldID AwtFont::maxHeightID;
  91 jfieldID AwtFont::maxAdvanceID;
  92 
  93 /* java.awt.FontDescriptor fields */
  94 jfieldID AwtFont::nativeNameID;
  95 jfieldID AwtFont::useUnicodeID;
  96 
  97 /* java.awt.Font fields */
  98 jfieldID AwtFont::pDataID;
  99 jfieldID AwtFont::nameID;
 100 jfieldID AwtFont::sizeID;
 101 jfieldID AwtFont::styleID;
 102 
 103 /* java.awt.FontMetrics fields */
 104 jfieldID AwtFont::fontID;
 105 
 106 /* sun.awt.PlatformFont fields */
 107 jfieldID AwtFont::fontConfigID;
 108 jfieldID AwtFont::componentFontsID;
 109 
 110 /* sun.awt.windows.WFontPeer fields */
 111 jfieldID AwtFont::textComponentFontNameID;
 112 
 113 /* sun.awt.windows.WDefaultFontCharset fields */
 114 jfieldID AwtFont::fontNameID;
 115 
 116 /* java.awt.Font methods */
 117 jmethodID AwtFont::peerMID;
 118 
 119 /* sun.awt.PlatformFont methods */
 120 jmethodID AwtFont::makeConvertedMultiFontStringMID;
 121 
 122 /* sun.awt.PlatformFont methods */
 123 jmethodID AwtFont::getFontMID;
 124 
 125 /* java.awt.FontMetrics methods */
 126 jmethodID AwtFont::getHeightMID;
 127 
 128 
 129 /************************************************************************
 130  * AwtFont methods
 131  */
 132 AwtFont::AwtFont(int num, JNIEnv *env, jobject javaFont)
 133 {
 134     if (num == 0) {  // not multi-font
 135         num = 1;
 136     }
 137 
 138     m_hFontNum = num;
 139     m_hFont = new HFONT[num];
 140 
 141     for (int i = 0; i < num; i++) {
 142         m_hFont[i] = NULL;
 143     }
 144 
 145     m_textInput = -1;
 146     m_ascent = -1;
 147     m_overhang = 0;
 148 }
 149 
 150 AwtFont::~AwtFont()
 151 {
 152 }
 153 
 154 void AwtFont::Dispose() {
 155     for (int i = 0; i < m_hFontNum; i++) {
 156         HFONT font = m_hFont[i];
 157         if (font != NULL && fontCache.Search(font)) {
 158             fontCache.Remove(font);
 159             /*  NOTE: delete of windows HFONT happens in FontCache::Remove
 160                       only when the final reference to the font is disposed */
 161         } else if (font != NULL) {
 162          // if font was not in cache, its not shared and we delete it now
 163            VERIFY(::DeleteObject(font));
 164         }
 165     }
 166     delete[] m_hFont;
 167 
 168     AwtObject::Dispose();
 169 }
 170 
 171 static void pDataDisposeMethod(JNIEnv *env, jlong pData)
 172 {
 173     TRY_NO_VERIFY;
 174 
 175     AwtObject::_Dispose((PDATA)pData);
 176 
 177     CATCH_BAD_ALLOC;
 178 }
 179 
 180 AwtFont* AwtFont::GetFont(JNIEnv *env, jobject font,
 181                           jint angle, jfloat awScale)
 182 {
 183     jlong pData = env->GetLongField(font, AwtFont::pDataID);
 184     AwtFont* awtFont = (AwtFont*)jlong_to_ptr(pData);
 185 
 186     if (awtFont != NULL) {
 187         return awtFont;
 188     }
 189 
 190     awtFont = Create(env, font, angle, awScale);
 191 
 192     env->SetLongField(font, AwtFont::pDataID,
 193         reinterpret_cast<jlong>(awtFont));
 194     return awtFont;
 195 }
 196 
 197 // Get suitable CHARSET from charset string provided by font configuration.
 198 static int GetNativeCharset(WCHAR* name)
 199 {
 200     if (wcsstr(name, L"ANSI_CHARSET"))
 201         return ANSI_CHARSET;
 202     if (wcsstr(name, L"DEFAULT_CHARSET"))
 203         return DEFAULT_CHARSET;
 204     if (wcsstr(name, L"SYMBOL_CHARSET") || wcsstr(name, L"WingDings"))
 205         return SYMBOL_CHARSET;
 206     if (wcsstr(name, L"SHIFTJIS_CHARSET"))
 207         return SHIFTJIS_CHARSET;
 208     if (wcsstr(name, L"GB2312_CHARSET"))
 209         return GB2312_CHARSET;
 210     if (wcsstr(name, L"HANGEUL_CHARSET"))
 211         return HANGEUL_CHARSET;
 212     if (wcsstr(name, L"CHINESEBIG5_CHARSET"))
 213         return CHINESEBIG5_CHARSET;
 214     if (wcsstr(name, L"OEM_CHARSET"))
 215         return OEM_CHARSET;
 216     if (wcsstr(name, L"JOHAB_CHARSET"))
 217         return JOHAB_CHARSET;
 218     if (wcsstr(name, L"HEBREW_CHARSET"))
 219         return HEBREW_CHARSET;
 220     if (wcsstr(name, L"ARABIC_CHARSET"))
 221         return ARABIC_CHARSET;
 222     if (wcsstr(name, L"GREEK_CHARSET"))
 223         return GREEK_CHARSET;
 224     if (wcsstr(name, L"TURKISH_CHARSET"))
 225         return TURKISH_CHARSET;
 226     if (wcsstr(name, L"VIETNAMESE_CHARSET"))
 227         return VIETNAMESE_CHARSET;
 228     if (wcsstr(name, L"THAI_CHARSET"))
 229         return THAI_CHARSET;
 230     if (wcsstr(name, L"EASTEUROPE_CHARSET"))
 231         return EASTEUROPE_CHARSET;
 232     if (wcsstr(name, L"RUSSIAN_CHARSET"))
 233         return RUSSIAN_CHARSET;
 234     if (wcsstr(name, L"MAC_CHARSET"))
 235         return MAC_CHARSET;
 236     if (wcsstr(name, L"BALTIC_CHARSET"))
 237         return BALTIC_CHARSET;
 238     return ANSI_CHARSET;
 239 }
 240 
 241 AwtFont* AwtFont::Create(JNIEnv *env, jobject font, jint angle, jfloat awScale)
 242 {
 243     int fontSize = env->GetIntField(font, AwtFont::sizeID);
 244     int fontStyle = env->GetIntField(font, AwtFont::styleID);
 245 
 246     AwtFont* awtFont = NULL;
 247     jobjectArray compFont = NULL;
 248     int cfnum = 0;
 249 
 250     try {
 251         if (env->EnsureLocalCapacity(3) < 0)
 252             return 0;
 253 
 254         if (IsMultiFont(env, font)) {
 255             compFont = GetComponentFonts(env, font);
 256             if (compFont != NULL) {
 257                 cfnum = env->GetArrayLength(compFont);
 258             }
 259         } else {
 260             compFont = NULL;
 261             cfnum = 0;
 262         }
 263 
 264         WCHAR* wName;
 265 
 266         awtFont = new AwtFont(cfnum, env, font);
 267 
 268         awtFont->textAngle = angle;
 269         awtFont->awScale = awScale;
 270 
 271         if (cfnum > 0) {
 272             // Ask peer class for the text component font name
 273             jstring jTextComponentFontName = GetTextComponentFontName(env, font);
 274             WCHAR* textComponentFontName = TO_WSTRING(jTextComponentFontName);
 275 
 276             env->DeleteLocalRef(jTextComponentFontName);
 277 
 278             awtFont->m_textInput = -1;
 279             for (int i = 0; i < cfnum; i++) {
 280                 // nativeName is a pair of platform fontname and its charset
 281                 // tied with a comma; "Times New Roman,ANSI_CHARSET".
 282                 jobject fontDescriptor = env->GetObjectArrayElement(compFont,
 283                                                                     i);
 284                 jstring nativeName =
 285                     (jstring)env->GetObjectField(fontDescriptor,
 286                                                  AwtFont::nativeNameID);
 287                 wName = TO_WSTRING(nativeName);
 288                 DASSERT(wName);
 289 
 290                 //On NT platforms, if the font is not Symbol or Dingbats
 291                 //use "W" version of Win32 APIs directly, info the FontDescription
 292                 //no need to convert characters from Unicode to locale encodings.
 293                 if (IS_NT && GetNativeCharset(wName) != SYMBOL_CHARSET) {
 294                     env->SetBooleanField(fontDescriptor, AwtFont::useUnicodeID, TRUE);
 295                 }
 296 
 297                 // Check to see if this font is suitable for input
 298                 // on AWT TextComponent
 299                 if ((awtFont->m_textInput == -1) &&
 300                         (textComponentFontName != NULL) &&
 301                         (wcscmp(wName, textComponentFontName) == 0)) {
 302                     awtFont->m_textInput = i;
 303                 }
 304                 HFONT hfonttmp = CreateHFont(wName, fontStyle, fontSize,
 305                                              angle, awScale);
 306                 awtFont->m_hFont[i] = hfonttmp;
 307 
 308                 env->DeleteLocalRef(fontDescriptor);
 309                 env->DeleteLocalRef(nativeName);
 310             }
 311             if (awtFont->m_textInput == -1) {
 312                 // no text component font was identified, so default
 313                 // to first component
 314                 awtFont->m_textInput = 0;
 315             }
 316         } else {
 317             // Instantiation for English version.
 318             jstring fontName = (jstring)env->GetObjectField(font,
 319                                                             AwtFont::nameID);
 320             wName = TO_WSTRING(fontName);
 321 
 322             WCHAR* wEName;
 323             if (!wcscmp(wName, L"Helvetica") || !wcscmp(wName, L"SansSerif")) {
 324                 wEName = L"Arial";
 325             } else if (!wcscmp(wName, L"TimesRoman") ||
 326                        !wcscmp(wName, L"Serif")) {
 327                 wEName = L"Times New Roman";
 328             } else if (!wcscmp(wName, L"Courier") ||
 329                        !wcscmp(wName, L"Monospaced")) {
 330                 wEName = L"Courier New";
 331             } else if (!wcscmp(wName, L"Dialog")) {
 332                 wEName = L"MS Sans Serif";
 333             } else if (!wcscmp(wName, L"DialogInput")) {
 334                 wEName = L"MS Sans Serif";
 335             } else if (!wcscmp(wName, L"ZapfDingbats")) {
 336                 wEName = L"WingDings";
 337             } else
 338                 wEName = L"Arial";
 339 
 340             awtFont->m_textInput = 0;
 341             awtFont->m_hFont[0] = CreateHFont(wEName, fontStyle, fontSize,
 342                                               angle, awScale);
 343             env->DeleteLocalRef(fontName);
 344         }
 345         /* The several callers of this method also set the pData field.
 346          * That's unnecessary but harmless duplication. However we definitely
 347          * want only one disposer record.
 348          */
 349         env->SetLongField(font, AwtFont::pDataID,
 350         reinterpret_cast<jlong>(awtFont));
 351         Disposer_AddRecord(env, font, pDataDisposeMethod,
 352                        reinterpret_cast<jlong>(awtFont));
 353     } catch (...) {
 354         env->DeleteLocalRef(compFont);
 355         throw;
 356     }
 357 
 358     env->DeleteLocalRef(compFont);
 359     return awtFont;
 360 }
 361 
 362 int CALLBACK FindFamilyName (ENUMLOGFONTEX *lpelfe,
 363           NEWTEXTMETRICEX *lpntme, int FontType, LPARAM lParam)
 364 {
 365     if(_tcsstr((LPTSTR)lParam, lpelfe->elfLogFont.lfFaceName)) {
 366         _tcscpy((LPTSTR)lParam, lpelfe->elfLogFont.lfFaceName);
 367         return 0;
 368     } else {
 369         return 1;
 370     }
 371 }
 372 
 373 static void strip_tail(wchar_t* text, wchar_t* tail) { // strips tail and any possible whitespace before it from the end of text
 374     if (wcslen(text)<=wcslen(tail)) {
 375         return;
 376     }
 377     wchar_t* p = text+wcslen(text)-wcslen(tail);
 378     if (!wcscmp(p, tail)) {
 379         while(p>text && iswspace(*(p-1)))
 380             p--;
 381         *p = 0;
 382     }
 383 
 384 }
 385 
 386 static HFONT CreateHFont_sub(WCHAR* name, int style, int height,
 387                              int angle=0, float awScale=1.0f)
 388 {
 389     LOGFONTW logFont;
 390 
 391     logFont.lfWidth = 0;
 392     logFont.lfEscapement = angle;
 393     logFont.lfOrientation = angle;
 394     logFont.lfUnderline = FALSE;
 395     logFont.lfStrikeOut = FALSE;
 396     logFont.lfCharSet = GetNativeCharset(name);
 397     if (angle == 0 && awScale == 1.0f) {
 398         logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
 399     } else {
 400         logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
 401     }
 402     logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
 403     logFont.lfQuality = DEFAULT_QUALITY;
 404     logFont.lfPitchAndFamily = DEFAULT_PITCH;
 405 
 406     // Set style
 407     logFont.lfWeight = (style & java_awt_Font_BOLD) ? FW_BOLD : FW_NORMAL;
 408     logFont.lfItalic = (style & java_awt_Font_ITALIC) != 0;
 409     logFont.lfUnderline = 0;//(style & java_awt_Font_UNDERLINE) != 0;
 410 
 411     // Get point size
 412     logFont.lfHeight = -height;
 413 
 414     // Set font name
 415     WCHAR tmpname[80];
 416     wcscpy(tmpname, name);
 417     WCHAR* delimit = wcschr(tmpname, L',');
 418     if (delimit != NULL)
 419         *delimit = L'\0';  // terminate the string after the font name.
 420     // strip "Bold" and "Italic" from the end of the name
 421     strip_tail(tmpname,L""); //strip possible trailing whitespace
 422     strip_tail(tmpname,L"Italic");
 423     strip_tail(tmpname,L"Bold");
 424     wcscpy(&(logFont.lfFaceName[0]), tmpname);
 425     HFONT hFont;
 426     if (IS_WIN95) {
 427 #ifdef WIN32
 428         DASSERT(IS_WIN95);
 429 #endif
 430         HDC hdc = ::GetDC(NULL);
 431         ::EnumFontFamiliesEx(hdc, &logFont, (FONTENUMPROC)FindFamilyName,
 432                              (LPARAM)tmpname, 0L);
 433         ::ReleaseDC(NULL, hdc);
 434         wcscpy(&logFont.lfFaceName[0], tmpname);
 435     }
 436     hFont = ::CreateFontIndirectW(&logFont);
 437     DASSERT(hFont != NULL);
 438     // get a expanded or condensed version if its specified.
 439     if (awScale != 1.0f) {
 440         HDC hDC = ::GetDC(0);
 441         HFONT oldFont = (HFONT)::SelectObject(hDC, hFont);
 442         TEXTMETRIC tm;
 443         DWORD avgWidth;
 444         GetTextMetrics(hDC, &tm);
 445         oldFont = (HFONT)::SelectObject(hDC, oldFont);
 446         if (oldFont != NULL) { // should be the same as hFont
 447             VERIFY(::DeleteObject(oldFont));
 448         }
 449         avgWidth = tm.tmAveCharWidth;
 450         logFont.lfWidth = (LONG)((fabs)(avgWidth*awScale));
 451         hFont = CreateFontIndirectW(&logFont);
 452         DASSERT(hFont != NULL);
 453         VERIFY(::ReleaseDC(0, hDC));
 454     }
 455 
 456     return hFont;
 457 }
 458 
 459 HFONT AwtFont::CreateHFont(WCHAR* name, int style, int height,
 460                            int angle, float awScale)
 461 {
 462     WCHAR longName[80];
 463     // 80 > (max face name(=30) + strlen("CHINESEBIG5_CHARSET"))
 464     // longName doesn't have to be printable.  So, it is OK not to convert.
 465     if (IS_NT) {
 466         //wsprintfW only works on NT.  See bugid 4123362
 467         wsprintfW(longName, L"%ls-%d-%d", name, style, height);
 468     } else {
 469 #ifdef WIN32
 470         DASSERT(IS_WIN95);
 471 #endif
 472         swprintf(longName, L"%ls-%d-%d", name, style, height);
 473     }
 474 
 475     HFONT hFont = NULL;
 476 
 477     // only cache & share unrotated, unexpanded/uncondensed fonts
 478     if (angle == 0 && awScale == 1.0f) {
 479         hFont = fontCache.Lookup(longName);
 480         if (hFont != NULL) {
 481             fontCache.IncRefCount(hFont);
 482             return hFont;
 483         }
 484     }
 485 
 486     hFont = CreateHFont_sub(name, style, height, angle, awScale);
 487     if (angle == 0 && awScale == 1.0f) {
 488         fontCache.Add(longName, hFont);
 489     }
 490     return hFont;
 491 }
 492 
 493 void AwtFont::Cleanup()
 494 {
 495     fontCache.Clear();
 496 }
 497 
 498 void AwtFont::SetupAscent(AwtFont* font)
 499 {
 500     HDC hDC = ::GetDC(0);
 501     DASSERT(hDC != NULL);
 502     HGDIOBJ oldFont = ::SelectObject(hDC, font->GetHFont());
 503 
 504     TEXTMETRIC metrics;
 505     VERIFY(::GetTextMetrics(hDC, &metrics));
 506     font->SetAscent(metrics.tmAscent);
 507 
 508     ::SelectObject(hDC, oldFont);
 509     VERIFY(::ReleaseDC(0, hDC));
 510 }
 511 
 512 void AwtFont::LoadMetrics(JNIEnv *env, jobject fontMetrics)
 513 {
 514     if (env->EnsureLocalCapacity(3) < 0)
 515         return;
 516     jintArray widths = env->NewIntArray(256);
 517     if (widths == NULL) {
 518         /* no local refs to delete yet. */
 519         return;
 520     }
 521     jobject font = env->GetObjectField(fontMetrics, AwtFont::fontID);
 522     AwtFont* awtFont = AwtFont::GetFont(env, font);
 523 
 524     HDC hDC = ::GetDC(0);
 525     DASSERT(hDC != NULL);
 526 
 527     HGDIOBJ oldFont = ::SelectObject(hDC, awtFont->GetHFont());
 528     TEXTMETRIC metrics;
 529     VERIFY(::GetTextMetrics(hDC, &metrics));
 530 
 531     awtFont->m_ascent = metrics.tmAscent;
 532 
 533     int ascent = metrics.tmAscent;
 534     int descent = metrics.tmDescent;
 535     int leading = metrics.tmExternalLeading;
 536     env->SetIntField(fontMetrics, AwtFont::ascentID, ascent);
 537     env->SetIntField(fontMetrics, AwtFont::descentID, descent);
 538     env->SetIntField(fontMetrics, AwtFont::leadingID, leading);
 539     env->SetIntField(fontMetrics, AwtFont::heightID, metrics.tmAscent +
 540                      metrics.tmDescent + leading);
 541     env->SetIntField(fontMetrics, AwtFont::maxAscentID, ascent);
 542     env->SetIntField(fontMetrics, AwtFont::maxDescentID, descent);
 543 
 544     int maxHeight =  ascent + descent + leading;
 545     env->SetIntField(fontMetrics, AwtFont::maxHeightID, maxHeight);
 546 
 547     int maxAdvance = metrics.tmMaxCharWidth;
 548     env->SetIntField(fontMetrics, AwtFont::maxAdvanceID, maxAdvance);
 549 
 550     awtFont->m_overhang = metrics.tmOverhang;
 551 
 552     jint intWidths[256];
 553     memset(intWidths, 0, 256 * sizeof(int));
 554     VERIFY(::GetCharWidth(hDC, metrics.tmFirstChar,
 555                           min(metrics.tmLastChar, 255),
 556                           (int *)&intWidths[metrics.tmFirstChar]));
 557     env->SetIntArrayRegion(widths, 0, 256, intWidths);
 558     env->SetObjectField(fontMetrics, AwtFont::widthsID, widths);
 559 
 560     // Get font metrics on remaining fonts (if multifont).
 561     for (int j = 1; j < awtFont->GetHFontNum(); j++) {
 562         ::SelectObject(hDC, awtFont->GetHFont(j));
 563         VERIFY(::GetTextMetrics(hDC, &metrics));
 564         env->SetIntField(fontMetrics, AwtFont::maxAscentID,
 565                          ascent = max(ascent, metrics.tmAscent));
 566         env->SetIntField(fontMetrics, AwtFont::maxDescentID,
 567                          descent = max(descent, metrics.tmDescent));
 568         env->SetIntField(fontMetrics, AwtFont::maxHeightID,
 569                          maxHeight = max(maxHeight,
 570                                          metrics.tmAscent +
 571                                          metrics.tmDescent +
 572                                          metrics.tmExternalLeading));
 573         env->SetIntField(fontMetrics, AwtFont::maxAdvanceID,
 574                          maxAdvance = max(maxAdvance, metrics.tmMaxCharWidth));
 575     }
 576 
 577     VERIFY(::SelectObject(hDC, oldFont));
 578     VERIFY(::ReleaseDC(0, hDC));
 579     env->DeleteLocalRef(font);
 580     env->DeleteLocalRef(widths);
 581 }
 582 
 583 SIZE AwtFont::TextSize(AwtFont* font, int columns, int rows)
 584 {
 585     HDC hDC = ::GetDC(0);
 586     DASSERT(hDC != NULL);
 587     HGDIOBJ oldFont = ::SelectObject(hDC, (font == NULL)
 588                                            ? ::GetStockObject(SYSTEM_FONT)
 589                                            : font->GetHFont());
 590 
 591     SIZE size;
 592     VERIFY(::GetTextExtentPoint(hDC,
 593         TEXT("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 52, &size));
 594 
 595     VERIFY(::SelectObject(hDC, oldFont));
 596     VERIFY(::ReleaseDC(0, hDC));
 597 
 598     size.cx = size.cx * columns / 52;
 599     size.cy = size.cy * rows;
 600     return size;
 601 }
 602 
 603 int AwtFont::getFontDescriptorNumber(JNIEnv *env, jobject font,
 604                                      jobject fontDescriptor)
 605 {
 606     int i, num = 0;
 607     jobject refFontDescriptor;
 608     jobjectArray array;
 609 
 610     if (env->EnsureLocalCapacity(2) < 0)
 611         return 0;
 612 
 613     if (IsMultiFont(env, font)) {
 614         array = GetComponentFonts(env, font);
 615         if (array != NULL) {
 616             num = env->GetArrayLength(array);
 617         }
 618     } else {
 619         array = NULL;
 620         num = 0;
 621     }
 622 
 623     for (i = 0; i < num; i++){
 624         // Trying to identify the same FontDescriptor by comparing the
 625         // pointers.
 626         refFontDescriptor = env->GetObjectArrayElement(array, i);
 627         if (env->IsSameObject(refFontDescriptor, fontDescriptor)) {
 628             env->DeleteLocalRef(refFontDescriptor);
 629             env->DeleteLocalRef(array);
 630             return i;
 631         }
 632         env->DeleteLocalRef(refFontDescriptor);
 633     }
 634     env->DeleteLocalRef(array);
 635     return 0;   // Not found.  Use default.
 636 }
 637 
 638 /*
 639  * This is a faster version of the same function, which does most of
 640  * the work in Java.
 641  */
 642 SIZE  AwtFont::DrawStringSize_sub(jstring str, HDC hDC,
 643                                   jobject font, long x, long y, BOOL draw,
 644                                   UINT codePage)
 645 {
 646     SIZE size, temp;
 647     size.cx = size.cy = 0;
 648 
 649     if (str == NULL) {
 650         return size;
 651     }
 652 
 653     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 654     if (env->EnsureLocalCapacity(3) < 0)
 655         return size;
 656     jobjectArray array = 0;
 657 
 658     int arrayLength = 0;
 659 
 660     if (env->GetStringLength(str) == 0) {
 661         return size;
 662     }
 663 
 664     //Init AwtFont object, which will "create" a AwtFont object if necessry,
 665     //before calling makeconvertedMultiFontString(), otherwise, the FontDescriptor's
 666     //"useUnicode" field might not be initialized correctly (font in Menu Component,
 667     //for example").
 668     AwtFont* awtFont = AwtFont::GetFont(env, font);
 669 
 670     if (IsMultiFont(env, font)) {
 671         jobject peer = env->CallObjectMethod(font, AwtFont::peerMID);
 672         if (peer != NULL) {
 673             array = (jobjectArray)(env->CallObjectMethod(
 674             peer, AwtFont::makeConvertedMultiFontStringMID, str));
 675             DASSERT(!safe_ExceptionOccurred(env));
 676 
 677             if (array != NULL) {
 678                 arrayLength = env->GetArrayLength(array);
 679             }
 680             env->DeleteLocalRef(peer);
 681         }
 682     } else {
 683         array = NULL;
 684         arrayLength = 0;
 685     }
 686 
 687     HFONT oldFont = (HFONT)::SelectObject(hDC, awtFont->GetHFont());
 688 
 689     if (arrayLength == 0) {
 690         int length = env->GetStringLength(str);
 691         WCHAR* string = TO_WSTRING(str);
 692         VERIFY(::SelectObject(hDC, awtFont->GetHFont()));
 693         if (AwtComponent::GetRTLReadingOrder()){
 694             if (IS_WIN95) {
 695                 // Start of conversion Code to fix arabic shaping problems
 696                 // with unicode support in win 95
 697                 LPSTR buffer =  (LPSTR) alloca((wcslen(string) + 1) * 2);
 698                 int count = ::WideCharToMultiByte(codePage, 0, string, length,
 699                                                   buffer,
 700                                                   static_cast<int>((wcslen(string) + 1) * 2),
 701                                                   NULL, NULL);
 702                 VERIFY(!draw || ::ExtTextOutA(hDC, x, y,  ETO_RTLREADING, NULL,
 703                                               buffer, count, NULL));
 704                 // End Of Conversion Code
 705             } else {
 706                 VERIFY(!draw || ::ExtTextOutW(hDC, x, y, ETO_RTLREADING, NULL,
 707                                               string, length, NULL));
 708             }
 709         } else {
 710             VERIFY(!draw || ::TextOutW(hDC, x, y, string, length));
 711         }
 712         VERIFY(::GetTextExtentPoint32W(hDC, string, length, &size));
 713     } else {
 714         for (int i = 0; i < arrayLength; i = i + 2) {
 715             jobject fontDescriptor = env->GetObjectArrayElement(array, i);
 716             if (fontDescriptor == NULL) {
 717                 break;
 718             }
 719 
 720             jbyteArray convertedBytes =
 721                 (jbyteArray)env->GetObjectArrayElement(array, i + 1);
 722             if (convertedBytes == NULL) {
 723                 env->DeleteLocalRef(fontDescriptor);
 724                 break;
 725             }
 726 
 727             int fdIndex = getFontDescriptorNumber(env, font, fontDescriptor);
 728             VERIFY(::SelectObject(hDC, awtFont->GetHFont(fdIndex)));
 729 
 730             /*
 731              * The strange-looking code that follows this comment is
 732              * the result of upstream optimizations. In the array of
 733              * alternating font descriptor and buffers, the buffers
 734              * contain their length in the first four bytes, a la
 735              * Pascal arrays.
 736              *
 737              * Note: the buffer MUST be unsigned, or VC++ will sign
 738              * extend buflen and bad things will happen.
 739              */
 740             unsigned char* buffer = NULL;
 741             jboolean unicodeUsed = env->GetBooleanField(fontDescriptor,AwtFont::useUnicodeID);
 742             try {
 743                 buffer = (unsigned char *)
 744                     env->GetPrimitiveArrayCritical(convertedBytes, 0);
 745                 int buflen = (buffer[0] << 24) | (buffer[1] << 16) |
 746                     (buffer[2] << 8) | buffer[3];
 747 
 748                 DASSERT(buflen >= 0);
 749 
 750                 /*
 751                  * the offsetBuffer, on the other hand, must be signed because
 752                  * TextOutA and GetTextExtentPoint32A expect it.
 753                  */
 754                 char* offsetBuffer = (char *)(buffer + 4);
 755 
 756                 if (unicodeUsed) {
 757                     VERIFY(!draw || ::TextOutW(hDC, x, y, (LPCWSTR)offsetBuffer, buflen / 2));
 758                     VERIFY(::GetTextExtentPoint32W(hDC, (LPCWSTR)offsetBuffer, buflen / 2, &temp));
 759                 }
 760                 else {
 761                     VERIFY(!draw || ::TextOutA(hDC, x, y, offsetBuffer, buflen));
 762                     VERIFY(::GetTextExtentPoint32A(hDC, offsetBuffer, buflen, &temp));
 763                 }
 764             } catch (...) {
 765                 if (buffer != NULL) {
 766                     env->ReleasePrimitiveArrayCritical(convertedBytes, buffer,
 767                                                        0);
 768                 }
 769                 throw;
 770             }
 771             env->ReleasePrimitiveArrayCritical(convertedBytes, buffer, 0);
 772 
 773             if (awtFont->textAngle == 0) {
 774                 x += temp.cx;
 775             } else {
 776                // account for rotation of the text used in 2D printing.
 777                double degrees = 360.0 - (awtFont->textAngle/10.0);
 778                double rads = degrees/(180.0/3.1415926535);
 779                double dx = temp.cx * cos(rads);
 780                double dy = temp.cx * sin(rads);
 781                x += (long)floor(dx+0.5);
 782                y += (long)floor(dy+0.5);
 783             }
 784             size.cx += temp.cx;
 785             size.cy = (size.cy < temp.cy) ? temp.cy : size.cy;
 786             env->DeleteLocalRef(fontDescriptor);
 787             env->DeleteLocalRef(convertedBytes);
 788         }
 789     }
 790     env->DeleteLocalRef(array);
 791 
 792     VERIFY(::SelectObject(hDC, oldFont));
 793     return size;
 794 }
 795 
 796 /************************************************************************
 797  * WFontMetrics native methods
 798  */
 799 
 800 extern "C" {
 801 
 802 /*
 803  * Class:     sun_awt_windows_WFontMetrics
 804  * Method:    stringWidth
 805  * Signature: (Ljava/lang/String;)I
 806  */
 807 JNIEXPORT jint JNICALL
 808 Java_sun_awt_windows_WFontMetrics_stringWidth(JNIEnv *env, jobject self,
 809                                               jstring str)
 810 {
 811     TRY;
 812 
 813     if (str == NULL) {
 814         JNU_ThrowNullPointerException(env, "str argument");
 815         return NULL;
 816     }
 817     HDC hDC = ::GetDC(0);    DASSERT(hDC != NULL);
 818 
 819     jobject font = env->GetObjectField(self, AwtFont::fontID);
 820 
 821     long ret = AwtFont::getMFStringWidth(hDC, font, str);
 822     VERIFY(::ReleaseDC(0, hDC));
 823     return ret;
 824 
 825     CATCH_BAD_ALLOC_RET(0);
 826 }
 827 
 828 /*
 829  * Class:     sun_awt_windows_WFontMetrics
 830  * Method:    charsWidth
 831  * Signature: ([CII)I
 832  */
 833 JNIEXPORT jint JNICALL
 834 Java_sun_awt_windows_WFontMetrics_charsWidth(JNIEnv *env, jobject self,
 835                                              jcharArray str,
 836                                              jint off, jint len)
 837 {
 838     TRY;
 839 
 840     if (str == NULL) {
 841         JNU_ThrowNullPointerException(env, "str argument");
 842         return NULL;
 843     }
 844     if ((len < 0) || (off < 0) || (len + off > (env->GetArrayLength(str)))) {
 845         JNU_ThrowArrayIndexOutOfBoundsException(env, "off/len argument");
 846         return NULL;
 847     }
 848 
 849     jchar *strp = new jchar[len];
 850     env->GetCharArrayRegion(str, off, len, strp);
 851     jstring jstr = env->NewString(strp, len);
 852     jint result = Java_sun_awt_windows_WFontMetrics_stringWidth(env, self,
 853                                                                 jstr);
 854     delete [] strp;
 855     return result;
 856 
 857     CATCH_BAD_ALLOC_RET(0);
 858 }
 859 
 860 
 861 /*
 862  * Class:     sun_awt_windows_WFontMetrics
 863  * Method:    bytesWidth
 864  * Signature: ([BII)I
 865  */
 866 JNIEXPORT jint JNICALL
 867 Java_sun_awt_windows_WFontMetrics_bytesWidth(JNIEnv *env, jobject self,
 868                                              jbyteArray str,
 869                                              jint off, jint len)
 870 {
 871     TRY;
 872 
 873     if (str == NULL) {
 874         JNU_ThrowNullPointerException(env, "bytes argument");
 875         return NULL;
 876     }
 877     if ((len < 0) || (off < 0) || (len + off > (env->GetArrayLength(str)))) {
 878         JNU_ThrowArrayIndexOutOfBoundsException(env, "off or len argument");
 879         return NULL;
 880     }
 881     char *pStrBody = NULL;
 882     jint result = 0;
 883     try {
 884         jintArray array = (jintArray)env->GetObjectField(self,
 885                                                          AwtFont::widthsID);
 886         pStrBody = (char *)env->GetPrimitiveArrayCritical(str, 0);
 887         char *pStr = pStrBody + off;
 888 
 889         jint *widths = NULL;
 890         try {
 891             widths = (jint *)env->GetPrimitiveArrayCritical(array, 0);
 892 
 893             for (; len; len--) {
 894                 result += widths[*pStr++];
 895             }
 896         } catch (...) {
 897             if (widths != NULL) {
 898                 env->ReleasePrimitiveArrayCritical(array, widths, 0);
 899             }
 900             throw;
 901         }
 902 
 903         env->ReleasePrimitiveArrayCritical(array, widths, 0);
 904 
 905     } catch (...) {
 906         if (pStrBody != NULL) {
 907             env->ReleasePrimitiveArrayCritical(str, pStrBody, 0);
 908         }
 909         throw;
 910     }
 911 
 912     env->ReleasePrimitiveArrayCritical(str, pStrBody, 0);
 913     return result;
 914 
 915     CATCH_BAD_ALLOC_RET(0);
 916 }
 917 
 918 
 919 /*
 920  * Class:     sun_awt_windows_WFontMetrics
 921  * Method:    init
 922  * Signature: ()V
 923  */
 924 JNIEXPORT void JNICALL
 925 Java_sun_awt_windows_WFontMetrics_init(JNIEnv *env, jobject self)
 926 {
 927     TRY;
 928 
 929     jobject font = env->GetObjectField(self, AwtFont::fontID);
 930     if (font == NULL) {
 931         JNU_ThrowNullPointerException(env, "fontMetrics' font");
 932         return;
 933     }
 934     // This local variable is unused. Is there some subtle side-effect here?
 935     jlong pData = env->GetLongField(font, AwtFont::pDataID);
 936 
 937     AwtFont::LoadMetrics(env, self);
 938 
 939     CATCH_BAD_ALLOC;
 940 }
 941 
 942 
 943 /*
 944  * Class:     sun_awt_windows_WFontMetrics
 945  * Method:    initIDs
 946  * Signature: ()V
 947  */
 948 JNIEXPORT void JNICALL
 949 Java_sun_awt_windows_WFontMetrics_initIDs(JNIEnv *env, jclass cls)
 950 {
 951     TRY;
 952 
 953     AwtFont::widthsID = env->GetFieldID(cls, "widths", "[I");
 954     AwtFont::ascentID = env->GetFieldID(cls, "ascent", "I");
 955     AwtFont::descentID = env->GetFieldID(cls, "descent", "I");
 956     AwtFont::leadingID = env->GetFieldID(cls, "leading", "I");
 957     AwtFont::heightID = env->GetFieldID(cls, "height", "I");
 958     AwtFont::maxAscentID = env->GetFieldID(cls, "maxAscent", "I");
 959     AwtFont::maxDescentID = env->GetFieldID(cls, "maxDescent", "I");
 960     AwtFont::maxHeightID = env->GetFieldID(cls, "maxHeight", "I");
 961     AwtFont::maxAdvanceID = env->GetFieldID(cls, "maxAdvance", "I");
 962 
 963     DASSERT(AwtFont::widthsID != NULL);
 964     DASSERT(AwtFont::ascentID != NULL);
 965     DASSERT(AwtFont::descentID != NULL);
 966     DASSERT(AwtFont::leadingID != NULL);
 967     DASSERT(AwtFont::heightID != NULL);
 968     DASSERT(AwtFont::maxAscentID != NULL);
 969     DASSERT(AwtFont::maxDescentID != NULL);
 970     DASSERT(AwtFont::maxHeightID != NULL);
 971     DASSERT(AwtFont::maxAdvanceID != NULL);
 972 
 973     CATCH_BAD_ALLOC;
 974 }
 975 
 976 } /* extern "C" */
 977 
 978 
 979 /************************************************************************
 980  * java.awt.Font native methods
 981  */
 982 
 983 extern "C" {
 984 
 985 JNIEXPORT void JNICALL
 986 Java_java_awt_Font_initIDs(JNIEnv *env, jclass cls)
 987 {
 988     TRY;
 989 
 990     AwtFont::peerMID = env->GetMethodID(cls, "getPeer",
 991                                         "()Ljava/awt/peer/FontPeer;");
 992     AwtFont::pDataID = env->GetFieldID(cls, "pData", "J");
 993     AwtFont::nameID = env->GetFieldID(cls, "name", "Ljava/lang/String;");
 994     AwtFont::sizeID = env->GetFieldID(cls, "size", "I");
 995     AwtFont::styleID = env->GetFieldID(cls, "style", "I");
 996 
 997     AwtFont::getFontMID =
 998       env->GetStaticMethodID(cls, "getFont",
 999                              "(Ljava/lang/String;)Ljava/awt/Font;");
1000 
1001     DASSERT(AwtFont::peerMID != NULL);
1002     DASSERT(AwtFont::pDataID != NULL);
1003     DASSERT(AwtFont::nameID != NULL);
1004     DASSERT(AwtFont::sizeID != NULL);
1005     DASSERT(AwtFont::styleID != NULL);
1006 
1007     DASSERT(AwtFont::getFontMID != NULL);
1008 
1009     CATCH_BAD_ALLOC;
1010 }
1011 
1012 } /* extern "C" */
1013 
1014 
1015 /************************************************************************
1016  * java.awt.FontMetric native methods
1017  */
1018 
1019 extern "C" {
1020 
1021 JNIEXPORT void JNICALL
1022 Java_java_awt_FontMetrics_initIDs(JNIEnv *env, jclass cls)
1023 {
1024     TRY;
1025 
1026     AwtFont::fontID = env->GetFieldID(cls, "font", "Ljava/awt/Font;");
1027     AwtFont::getHeightMID = env->GetMethodID(cls, "getHeight", "()I");
1028 
1029     DASSERT(AwtFont::fontID);
1030     DASSERT(AwtFont::getHeightMID);
1031 
1032     CATCH_BAD_ALLOC;
1033 }
1034 
1035 } /* extern "C" */
1036 
1037 /************************************************************************
1038  * sun.awt.FontDescriptor native methods
1039  */
1040 
1041 extern "C" {
1042 
1043 JNIEXPORT void JNICALL
1044 Java_sun_awt_FontDescriptor_initIDs(JNIEnv *env, jclass cls)
1045 {
1046     TRY;
1047 
1048     AwtFont::nativeNameID = env->GetFieldID(cls, "nativeName",
1049                                             "Ljava/lang/String;");
1050     AwtFont::useUnicodeID = env->GetFieldID(cls, "useUnicode", "Z");
1051 
1052     DASSERT(AwtFont::nativeNameID != NULL);
1053     DASSERT(AwtFont::useUnicodeID != NULL);
1054 
1055     CATCH_BAD_ALLOC;
1056 }
1057 
1058 } /* extern "C" */
1059 
1060 
1061 /************************************************************************
1062  * sun.awt.PlatformFont native methods
1063  */
1064 
1065 extern "C" {
1066 
1067 JNIEXPORT void JNICALL
1068 Java_sun_awt_PlatformFont_initIDs(JNIEnv *env, jclass cls)
1069 {
1070     TRY;
1071 
1072     AwtFont::fontConfigID = env->GetFieldID(cls, "fontConfig", "Lsun/awt/FontConfiguration;");
1073     AwtFont::componentFontsID =
1074         env->GetFieldID(cls, "componentFonts", "[Lsun/awt/FontDescriptor;");
1075     AwtFont::makeConvertedMultiFontStringMID =
1076         env->GetMethodID(cls, "makeConvertedMultiFontString",
1077                          "(Ljava/lang/String;)[Ljava/lang/Object;");
1078 
1079     DASSERT(AwtFont::makeConvertedMultiFontStringMID != NULL);
1080     DASSERT(AwtFont::componentFontsID != NULL);
1081     DASSERT(AwtFont::fontConfigID != NULL);
1082 
1083     CATCH_BAD_ALLOC;
1084 }
1085 
1086 } /* extern "C" */
1087 
1088 
1089 /************************************************************************
1090  * sun.awt.windows.WFontPeer native methods
1091  */
1092 
1093 extern "C" {
1094 
1095 JNIEXPORT void JNICALL
1096 Java_sun_awt_windows_WFontPeer_initIDs(JNIEnv *env, jclass cls)
1097 {
1098     TRY;
1099 
1100     AwtFont::textComponentFontNameID = env->GetFieldID(cls, "textComponentFontName", "Ljava/lang/String;");
1101 
1102     DASSERT(AwtFont::textComponentFontNameID != NULL);
1103 
1104     CATCH_BAD_ALLOC;
1105 }
1106 
1107 } /* extern "C" */
1108 
1109 
1110 /************************************************************************
1111  * FontCache methods
1112  */
1113 
1114 void AwtFontCache::Add(WCHAR* name, HFONT font)
1115 {
1116     fontCache.m_head = new Item(name, font, fontCache.m_head);
1117 }
1118 
1119 HFONT AwtFontCache::Lookup(WCHAR* name)
1120 {
1121     Item* item = fontCache.m_head;
1122     Item* lastItem = NULL;
1123 
1124     while (item != NULL) {
1125         if (wcscmp(item->name, name) == 0) {
1126             return item->font;
1127         }
1128         lastItem = item;
1129         item = item->next;
1130     }
1131     return NULL;
1132 }
1133 
1134 BOOL AwtFontCache::Search(HFONT font)
1135 {
1136     Item* item = fontCache.m_head;
1137 
1138     while (item != NULL) {
1139         if (item->font == font) {
1140             return TRUE;
1141         }
1142         item = item->next;
1143     }
1144     return FALSE;
1145 }
1146 
1147 void AwtFontCache::Remove(HFONT font)
1148 {
1149     Item* item = fontCache.m_head;
1150     Item* lastItem = NULL;
1151 
1152     while (item != NULL) {
1153         if (item->font == font) {
1154             if (DecRefCount(item) <= 0){
1155                 if (lastItem == NULL) {
1156                     fontCache.m_head = item->next;
1157                 } else {
1158                 lastItem->next = item->next;
1159                 }
1160              delete item;
1161              }
1162              return;
1163         }
1164         lastItem = item;
1165         item = item->next;
1166     }
1167 }
1168 
1169 void AwtFontCache::Clear()
1170 {
1171     Item* item = m_head;
1172     Item* next;
1173 
1174     while (item != NULL) {
1175         next = item->next;
1176         delete item;
1177         item = next;
1178     }
1179 
1180     m_head = NULL;
1181 }
1182 
1183 /* NOTE: In the interlock calls below the return value is different
1184          depending on which version of windows. However, all versions
1185          return a 0 or less than value when the count gets there. Only
1186          under NT 4.0 & 98 does the value actaully represent the new value. */
1187 
1188 void AwtFontCache::IncRefCount(HFONT hFont){
1189     Item* item = fontCache.m_head;
1190 
1191     while (item != NULL){
1192 
1193         if (item->font == hFont){
1194             IncRefCount(item);
1195             return;
1196         }
1197         item = item->next;
1198     }
1199 }
1200 
1201 LONG AwtFontCache::IncRefCount(Item* item){
1202     LONG    newVal;
1203 
1204     if(NULL != item){
1205         newVal = InterlockedIncrement((long*)&item->refCount);
1206     }
1207     return(newVal);
1208 }
1209 
1210 LONG AwtFontCache::DecRefCount(Item* item){
1211     LONG    newVal;
1212 
1213     if(NULL != item){
1214         newVal = InterlockedDecrement((long*)&item->refCount);
1215     }
1216     return(newVal);
1217 }
1218 
1219 AwtFontCache::Item::Item(const WCHAR* s, HFONT f, AwtFontCache::Item* n )
1220 {
1221     name = _wcsdup(s);
1222     font = f;
1223     next = n;
1224     refCount = 1;
1225 }
1226 
1227 AwtFontCache::Item::~Item() {
1228   VERIFY(::DeleteObject(font));
1229   free(name);
1230 }
1231 
1232 /////////////////////////////////////////////////////////////////////////////
1233 // for canConvert native method of WDefaultFontCharset
1234 
1235 class CSegTableComponent
1236 {
1237 public:
1238     CSegTableComponent();
1239     virtual ~CSegTableComponent();
1240     virtual void Create(LPWSTR name);
1241     virtual BOOL In(USHORT iChar) { DASSERT(FALSE); return FALSE; };
1242     LPWSTR GetFontName(){
1243         DASSERT(m_lpszFontName != NULL); return m_lpszFontName;
1244     };
1245 
1246 private:
1247     LPWSTR m_lpszFontName;
1248 };
1249 
1250 CSegTableComponent::CSegTableComponent()
1251 {
1252     m_lpszFontName = NULL;
1253 }
1254 
1255 CSegTableComponent::~CSegTableComponent()
1256 {
1257     if (m_lpszFontName != NULL) {
1258         free(m_lpszFontName);
1259         m_lpszFontName = NULL;
1260     }
1261 }
1262 
1263 void CSegTableComponent::Create(LPWSTR name)
1264 {
1265     if (m_lpszFontName != NULL) {
1266         free(m_lpszFontName);
1267         m_lpszFontName = NULL;
1268     }
1269     m_lpszFontName = _wcsdup(name);
1270     DASSERT(m_lpszFontName);
1271 }
1272 
1273 #define CMAPHEX 0x70616d63 // = "cmap" (reversed)
1274 
1275 // CSegTable: Segment table describing character coverage for a font
1276 class CSegTable : public CSegTableComponent
1277 {
1278 public:
1279     CSegTable();
1280     virtual ~CSegTable();
1281     virtual BOOL In(USHORT iChar);
1282     BOOL HasCmap();
1283     virtual BOOL IsEUDC() { DASSERT(FALSE); return FALSE; };
1284 
1285 protected:
1286     virtual void GetData(DWORD dwOffset, LPVOID lpData, DWORD cbData) {
1287         DASSERT(FALSE); };
1288     void MakeTable();
1289     static void SwapShort(USHORT& p);
1290     static void SwapULong(ULONG& p);
1291 
1292 private:
1293     USHORT m_cSegCount;     // number of segments
1294     PUSHORT m_piStart;      // pointer to array of starting values
1295     PUSHORT m_piEnd;        // pointer to array of ending values (inclusive)
1296     USHORT m_cSeg;          // current segment (cache)
1297 };
1298 
1299 CSegTable::CSegTable()
1300 {
1301     m_cSegCount = 0;
1302     m_piStart = NULL;
1303     m_piEnd = NULL;
1304     m_cSeg = 0;
1305 }
1306 
1307 CSegTable::~CSegTable()
1308 {
1309     if (m_piStart != NULL)
1310         delete[] m_piStart;
1311     if (m_piEnd != NULL)
1312         delete[] m_piEnd;
1313 }
1314 
1315 #define OFFSETERROR 0
1316 
1317 void CSegTable::MakeTable()
1318 {
1319 typedef struct tagTABLE{
1320     USHORT  platformID;
1321     USHORT  encodingID;
1322     ULONG   offset;
1323 } TABLE, *PTABLE;
1324 
1325 typedef struct tagSUBTABLE{
1326     USHORT  format;
1327     USHORT  length;
1328     USHORT  version;
1329     USHORT  segCountX2;
1330     USHORT  searchRange;
1331     USHORT  entrySelector;
1332     USHORT  rangeShift;
1333 } SUBTABLE, *PSUBTABLE;
1334 
1335     USHORT aShort[2];
1336     (void) GetData(0, aShort, sizeof(aShort));
1337     USHORT nTables = aShort[1];
1338     SwapShort(nTables);
1339 
1340     // allocate buffer to hold encoding tables
1341     DWORD cbData = nTables * sizeof(TABLE);
1342     PTABLE pTables = new TABLE[nTables];
1343     PTABLE pTable = pTables;
1344 
1345     // get array of encoding tables.
1346     (void) GetData(4, (PBYTE) pTable, cbData);
1347 
1348     ULONG offsetFormat4 = OFFSETERROR;
1349     USHORT i;
1350     for (i = 0; i < nTables; i++) {
1351         SwapShort(pTable->encodingID);
1352         SwapShort(pTable->platformID);
1353         //for a Unicode font for Windows, platformID == 3, encodingID == 1
1354         if ((pTable->platformID == 3)&&(pTable->encodingID == 1)) {
1355             offsetFormat4 = pTable->offset;
1356             SwapULong(offsetFormat4);
1357             break;
1358         }
1359         pTable++;
1360     }
1361     delete[] pTables;
1362     if (offsetFormat4 == OFFSETERROR) {
1363         return;
1364     }
1365 //    DASSERT(offsetFormat4 != OFFSETERROR);
1366 
1367     SUBTABLE subTable;
1368     (void) GetData(offsetFormat4, &subTable, sizeof(SUBTABLE));
1369     SwapShort(subTable.format);
1370     SwapShort(subTable.segCountX2);
1371     DASSERT(subTable.format == 4);
1372 
1373     m_cSegCount = subTable.segCountX2/2;
1374 
1375     // read in the array of segment end values
1376     m_piEnd = new USHORT[m_cSegCount];
1377 
1378     ULONG offset = offsetFormat4
1379         + sizeof(SUBTABLE); //skip constant # bytes in subtable
1380     cbData = m_cSegCount * sizeof(USHORT);
1381     (void) GetData(offset, m_piEnd, cbData);
1382     for (i = 0; i < m_cSegCount; i++)
1383         SwapShort(m_piEnd[i]);
1384     DASSERT(m_piEnd[m_cSegCount-1] == 0xffff);
1385 
1386     // read in the array of segment start values
1387     try {
1388         m_piStart = new USHORT[m_cSegCount];
1389     } catch (std::bad_alloc&) {
1390         delete [] m_piEnd;
1391         m_piEnd = NULL;
1392         throw;
1393     }
1394 
1395     offset += cbData        //skip SegEnd array
1396         + sizeof(USHORT);   //skip reservedPad
1397     (void) GetData(offset, m_piStart, cbData);
1398     for (i = 0; i < m_cSegCount; i++)
1399         SwapShort(m_piStart[i]);
1400     DASSERT(m_piStart[m_cSegCount-1] == 0xffff);
1401 }
1402 
1403 BOOL CSegTable::In(USHORT iChar)
1404 {
1405     if (!HasCmap()) {
1406         return FALSE;
1407     }
1408 //    DASSERT(m_piStart);
1409 //    DASSERT(m_piEnd);
1410 
1411     if (iChar > m_piEnd[m_cSeg]) {
1412         for (; (m_cSeg < m_cSegCount)&&(iChar > m_piEnd[m_cSeg]); m_cSeg++);
1413     } else if (iChar < m_piStart[m_cSeg]) {
1414         for (; (m_cSeg > 0)&&(iChar < m_piStart[m_cSeg]); m_cSeg--);
1415     }
1416 
1417     if ((iChar <= m_piEnd[m_cSeg])&&(iChar >= m_piStart[m_cSeg])&&(iChar != 0xffff))
1418         return TRUE;
1419     else
1420         return FALSE;
1421 }
1422 
1423 inline BOOL CSegTable::HasCmap()
1424 {
1425     return (((m_piEnd)&&(m_piStart)) ? TRUE : FALSE);
1426 }
1427 
1428 inline void CSegTable::SwapShort(USHORT& p)
1429 {
1430     SHORT temp;
1431 
1432     temp = (SHORT)(HIBYTE(p) + (LOBYTE(p) << 8));
1433     p = temp;
1434 }
1435 
1436 inline void CSegTable::SwapULong(ULONG& p)
1437 {
1438     ULONG temp;
1439 
1440     temp = (LONG) ((BYTE) p);
1441     temp <<= 8;
1442     p >>= 8;
1443 
1444     temp += (LONG) ((BYTE) p);
1445     temp <<= 8;
1446     p >>= 8;
1447 
1448     temp += (LONG) ((BYTE) p);
1449     temp <<= 8;
1450     p >>= 8;
1451 
1452     temp += (LONG) ((BYTE) p);
1453     p = temp;
1454 }
1455 
1456 class CStdSegTable : public CSegTable
1457 {
1458 public:
1459     CStdSegTable();
1460     virtual ~CStdSegTable();
1461     BOOL IsEUDC() { return FALSE; };
1462     virtual void Create(LPWSTR name);
1463 
1464 protected:
1465     void GetData(DWORD dwOffset, LPVOID lpData, DWORD cbData);
1466 
1467 private:
1468     HDC m_hTmpDC;
1469 };
1470 
1471 CStdSegTable::CStdSegTable()
1472 {
1473     m_hTmpDC = NULL;
1474 }
1475 
1476 CStdSegTable::~CStdSegTable()
1477 {
1478     DASSERT(m_hTmpDC == NULL);
1479 }
1480 
1481 inline void CStdSegTable::GetData(DWORD dwOffset,
1482                                   LPVOID lpData, DWORD cbData)
1483 {
1484     DASSERT(m_hTmpDC);
1485     DWORD nBytes =
1486         ::GetFontData(m_hTmpDC, CMAPHEX, dwOffset, lpData, cbData);
1487     DASSERT(nBytes != GDI_ERROR);
1488 }
1489 
1490 void CStdSegTable::Create(LPWSTR name)
1491 {
1492     CSegTableComponent::Create(name);
1493 
1494     HWND hWnd = ::GetDesktopWindow();
1495     DASSERT(hWnd);
1496     m_hTmpDC = ::GetWindowDC(hWnd);
1497     DASSERT(m_hTmpDC);
1498 
1499     HFONT hFont = CreateHFont_sub(name, 0, 20);
1500 
1501     HFONT hOldFont = (HFONT)::SelectObject(m_hTmpDC, hFont);
1502     DASSERT(hOldFont);
1503 
1504     (void) MakeTable();
1505 
1506     VERIFY(::SelectObject(m_hTmpDC, hOldFont));
1507     VERIFY(::DeleteObject(hFont));
1508     VERIFY(::ReleaseDC(hWnd, m_hTmpDC) != 0);
1509     m_hTmpDC = NULL;
1510 }
1511 
1512 class CEUDCSegTable : public CSegTable
1513 {
1514 public:
1515     CEUDCSegTable();
1516     virtual ~CEUDCSegTable();
1517     BOOL IsEUDC() { return TRUE; };
1518     virtual void Create(LPWSTR name);
1519 
1520 protected:
1521     void GetData(DWORD dwOffset, LPVOID lpData, DWORD cbData);
1522 
1523 private:
1524     HANDLE m_hTmpFile;
1525     ULONG m_hTmpCMapOffset;
1526 };
1527 
1528 CEUDCSegTable::CEUDCSegTable()
1529 {
1530     m_hTmpFile = NULL;
1531     m_hTmpCMapOffset = 0;
1532 }
1533 
1534 CEUDCSegTable::~CEUDCSegTable()
1535 {
1536     DASSERT(m_hTmpFile == NULL);
1537     DASSERT(m_hTmpCMapOffset == 0);
1538 }
1539 
1540 inline void CEUDCSegTable::GetData(DWORD dwOffset,
1541                                    LPVOID lpData, DWORD cbData)
1542 {
1543     DASSERT(m_hTmpFile);
1544     DASSERT(m_hTmpCMapOffset);
1545     ::SetFilePointer(m_hTmpFile, m_hTmpCMapOffset + dwOffset,
1546         NULL, FILE_BEGIN);
1547     DWORD dwRead;
1548     VERIFY(::ReadFile(m_hTmpFile, lpData, cbData, &dwRead, NULL));
1549     DASSERT(dwRead == cbData);
1550 }
1551 
1552 void CEUDCSegTable::Create(LPWSTR name)
1553 {
1554 typedef struct tagHEAD{
1555     FIXED   sfnt_version;
1556     USHORT  numTables;
1557     USHORT  searchRange;
1558     USHORT  entrySelector;
1559     USHORT  rangeShift;
1560 } HEAD, *PHEAD;
1561 
1562 typedef struct tagENTRY{
1563     ULONG   tag;
1564     ULONG   checkSum;
1565     ULONG   offset;
1566     ULONG   length;
1567 } ENTRY, *PENTRY;
1568 
1569     CSegTableComponent::Create(name);
1570 
1571     // create EUDC font file and make EUDCSegTable
1572     // after wrapper function for CreateFileW, we use only CreateFileW
1573     if (IS_NT) {
1574         m_hTmpFile = ::CreateFileW(name, GENERIC_READ,
1575             FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1576     } else {
1577 #ifdef WIN32
1578         DASSERT(IS_WIN95);
1579 #endif
1580         char szFileName[_MAX_PATH];
1581         ::WideCharToMultiByte(CP_ACP, 0, name, -1,
1582             szFileName, sizeof(szFileName), NULL, NULL);
1583         m_hTmpFile = ::CreateFileA(szFileName, GENERIC_READ,
1584             FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1585     }
1586     if (m_hTmpFile == INVALID_HANDLE_VALUE){
1587         m_hTmpFile = NULL;
1588         return;
1589     }
1590 
1591     HEAD head;
1592     DWORD dwRead;
1593     VERIFY(::ReadFile(m_hTmpFile, &head, sizeof(head), &dwRead, NULL));
1594     DASSERT(dwRead == sizeof(HEAD));
1595     SwapShort(head.numTables);
1596     ENTRY entry;
1597     for (int i = 0; i < head.numTables; i++){
1598         VERIFY(::ReadFile(m_hTmpFile, &entry, sizeof(entry), &dwRead, NULL));
1599         DASSERT(dwRead == sizeof(ENTRY));
1600         if (entry.tag == CMAPHEX)
1601             break;
1602     }
1603     DASSERT(entry.tag == CMAPHEX);
1604     SwapULong(entry.offset);
1605     m_hTmpCMapOffset = entry.offset;
1606 
1607     (void) MakeTable();
1608 
1609     m_hTmpCMapOffset = 0;
1610     VERIFY(::CloseHandle(m_hTmpFile));
1611     m_hTmpFile = NULL;
1612 }
1613 
1614 class CSegTableManagerComponent
1615 {
1616 public:
1617     CSegTableManagerComponent();
1618     ~CSegTableManagerComponent();
1619 
1620 protected:
1621     void MakeBiggerTable();
1622     CSegTableComponent **m_tables;
1623     int m_nTable;
1624     int m_nMaxTable;
1625 };
1626 
1627 #define TABLENUM 20
1628 
1629 CSegTableManagerComponent::CSegTableManagerComponent()
1630 {
1631     m_nTable = 0;
1632     m_nMaxTable = TABLENUM;
1633     m_tables = new CSegTableComponent*[m_nMaxTable];
1634 }
1635 
1636 CSegTableManagerComponent::~CSegTableManagerComponent()
1637 {
1638     for (int i = 0; i < m_nTable; i++) {
1639         DASSERT(m_tables[i]);
1640         delete m_tables[i];
1641     }
1642     delete [] m_tables;
1643     m_tables = NULL;
1644 }
1645 
1646 void CSegTableManagerComponent::MakeBiggerTable()
1647 {
1648     CSegTableComponent **tables =
1649         new CSegTableComponent*[m_nMaxTable + TABLENUM];
1650 
1651     for (int i = 0; i < m_nMaxTable; i++)
1652         tables[i] = m_tables[i];
1653 
1654     delete[] m_tables;
1655 
1656     m_tables = tables;
1657     m_nMaxTable += TABLENUM;
1658 }
1659 
1660 class CSegTableManager : public CSegTableManagerComponent
1661 {
1662 public:
1663     CSegTable* GetTable(LPWSTR lpszFontName, BOOL fEUDC);
1664 };
1665 
1666 CSegTable* CSegTableManager::GetTable(LPWSTR lpszFontName, BOOL fEUDC)
1667 {
1668     for (int i = 0; i < m_nTable; i++) {
1669         if ((((CSegTable*)m_tables[i])->IsEUDC() == fEUDC) &&
1670             (wcscmp(m_tables[i]->GetFontName(),lpszFontName) == 0))
1671             return (CSegTable*) m_tables[i];
1672     }
1673 
1674     if (m_nTable == m_nMaxTable) {
1675         (void) MakeBiggerTable();
1676     }
1677     DASSERT(m_nTable < m_nMaxTable);
1678 
1679     if (!fEUDC) {
1680         m_tables[m_nTable] = new CStdSegTable;
1681     } else {
1682         m_tables[m_nTable] = new CEUDCSegTable;
1683     }
1684     m_tables[m_nTable]->Create(lpszFontName);
1685     return (CSegTable*) m_tables[m_nTable++];
1686 }
1687 
1688 CSegTableManager g_segTableManager;
1689 
1690 class CCombinedSegTable : public CSegTableComponent
1691 {
1692 public:
1693     CCombinedSegTable();
1694     void Create(LPWSTR name);
1695     BOOL In(USHORT iChar);
1696 
1697 private:
1698     LPSTR GetCodePageSubkey();
1699     void GetEUDCFileName(LPWSTR lpszFileName, int cchFileName);
1700     static char m_szCodePageSubkey[16];
1701     static WCHAR m_szDefaultEUDCFile[_MAX_PATH];
1702     static BOOL m_fEUDCSubKeyExist;
1703     static BOOL m_fTTEUDCFileExist;
1704     CStdSegTable* m_pStdSegTable;
1705     CEUDCSegTable* m_pEUDCSegTable;
1706 };
1707 
1708 char CCombinedSegTable::m_szCodePageSubkey[16] = "";
1709 
1710 WCHAR CCombinedSegTable::m_szDefaultEUDCFile[_MAX_PATH] = L"";
1711 
1712 BOOL CCombinedSegTable::m_fEUDCSubKeyExist = TRUE;
1713 
1714 BOOL CCombinedSegTable::m_fTTEUDCFileExist = TRUE;
1715 
1716 CCombinedSegTable::CCombinedSegTable()
1717 {
1718     m_pStdSegTable = NULL;
1719     m_pEUDCSegTable = NULL;
1720 }
1721 
1722 #include <locale.h>
1723 LPSTR CCombinedSegTable::GetCodePageSubkey()
1724 {
1725     if (strlen(m_szCodePageSubkey) > 0) {
1726         return m_szCodePageSubkey;
1727     }
1728 
1729     LPSTR lpszLocale = setlocale(LC_CTYPE, "");
1730     // cf lpszLocale = "Japanese_Japan.932"
1731     if (lpszLocale == NULL) {
1732         return NULL;
1733     }
1734     LPSTR lpszCP = strchr(lpszLocale, (int) '.');
1735     if (lpszCP == NULL) {
1736         return NULL;
1737     }
1738     lpszCP++; // cf lpszCP = "932"
1739 
1740     char szSubKey[80];
1741     strcpy(szSubKey, "EUDC\\");
1742     strcpy(&(szSubKey[strlen(szSubKey)]), lpszCP);
1743     strcpy(m_szCodePageSubkey, szSubKey);
1744     return m_szCodePageSubkey;
1745 }
1746 
1747 void CCombinedSegTable::GetEUDCFileName(LPWSTR lpszFileName, int cchFileName)
1748 {
1749     if (m_fEUDCSubKeyExist == FALSE)
1750         return;
1751 
1752     // get filename of typeface-specific TureType EUDC font
1753     LPSTR lpszSubKey = GetCodePageSubkey();
1754     if (lpszSubKey == NULL) {
1755         m_fEUDCSubKeyExist = FALSE;
1756         return; // can not get codepage information
1757     }
1758     HKEY hRootKey = HKEY_CURRENT_USER;
1759     HKEY hKey;
1760     LONG lRet = ::RegOpenKeyExA(hRootKey, lpszSubKey, 0, KEY_ALL_ACCESS, &hKey);
1761     if (lRet != ERROR_SUCCESS) {
1762         m_fEUDCSubKeyExist = FALSE;
1763         return; // no EUDC font
1764     }
1765 
1766     // get EUDC font file name
1767     WCHAR szFamilyName[80];
1768     wcscpy(szFamilyName, GetFontName());
1769     WCHAR* delimit = wcschr(szFamilyName, L',');
1770     if (delimit != NULL)
1771         *delimit = L'\0';
1772     DWORD dwType;
1773     UCHAR szFileName[_MAX_PATH];
1774     ::ZeroMemory(szFileName, sizeof(szFileName));
1775     DWORD dwBytes = sizeof(szFileName);
1776     // try Typeface-specific EUDC font
1777     char szTmpName[80];
1778     VERIFY(::WideCharToMultiByte(CP_ACP, 0, szFamilyName, -1,
1779         szTmpName, sizeof(szTmpName), NULL, NULL));
1780     LONG lStatus = ::RegQueryValueExA(hKey, (LPCSTR) szTmpName,
1781         NULL, &dwType, szFileName, &dwBytes);
1782     BOOL fUseDefault = FALSE;
1783     if (lStatus != ERROR_SUCCESS){ // try System default EUDC font
1784         if (m_fTTEUDCFileExist == FALSE)
1785             return;
1786         if (wcslen(m_szDefaultEUDCFile) > 0) {
1787             wcscpy(lpszFileName, m_szDefaultEUDCFile);
1788             return;
1789         }
1790         char szDefault[] = "SystemDefaultEUDCFont";
1791         lStatus = ::RegQueryValueExA(hKey, (LPCSTR) szDefault,
1792             NULL, &dwType, szFileName, &dwBytes);
1793         fUseDefault = TRUE;
1794         if (lStatus != ERROR_SUCCESS) {
1795             m_fTTEUDCFileExist = FALSE;
1796             // This font is associated with no EUDC font
1797             // and there is no system default EUDC font
1798             return;
1799         }
1800     }
1801 
1802     if (strcmp((LPCSTR) szFileName, "userfont.fon") == 0) {
1803         // This font is associated with no EUDC font
1804         // and the system default EUDC font is not TrueType
1805         m_fTTEUDCFileExist = FALSE;
1806         return;
1807     }
1808 
1809     DASSERT(strlen((LPCSTR)szFileName) > 0);
1810     VERIFY(::MultiByteToWideChar(CP_ACP, 0,
1811         (LPCSTR)szFileName, -1, lpszFileName, cchFileName) != 0);
1812     if (fUseDefault)
1813         wcscpy(m_szDefaultEUDCFile, lpszFileName);
1814 }
1815 
1816 void CCombinedSegTable::Create(LPWSTR name)
1817 {
1818     CSegTableComponent::Create(name);
1819 
1820     m_pStdSegTable =
1821         (CStdSegTable*) g_segTableManager.GetTable(name, FALSE/*not EUDC*/);
1822     WCHAR szEUDCFileName[_MAX_PATH];
1823     ::ZeroMemory(szEUDCFileName, sizeof(szEUDCFileName));
1824     (void) GetEUDCFileName(szEUDCFileName,
1825         sizeof(szEUDCFileName)/sizeof(WCHAR));
1826     if (wcslen(szEUDCFileName) > 0) {
1827         m_pEUDCSegTable = (CEUDCSegTable*) g_segTableManager.GetTable(
1828             szEUDCFileName, TRUE/*EUDC*/);
1829         if (m_pEUDCSegTable->HasCmap() == FALSE)
1830             m_pEUDCSegTable = NULL;
1831     }
1832 }
1833 
1834 BOOL CCombinedSegTable::In(USHORT iChar)
1835 {
1836     DASSERT(m_pStdSegTable);
1837     if (m_pStdSegTable->In(iChar))
1838         return TRUE;
1839 
1840     if (m_pEUDCSegTable != NULL)
1841         return m_pEUDCSegTable->In(iChar);
1842 
1843     return FALSE;
1844 }
1845 
1846 class CCombinedSegTableManager : public CSegTableManagerComponent
1847 {
1848 public:
1849     CCombinedSegTable* GetTable(LPWSTR lpszFontName);
1850 };
1851 
1852 CCombinedSegTable* CCombinedSegTableManager::GetTable(LPWSTR lpszFontName)
1853 {
1854     for (int i = 0; i < m_nTable; i++) {
1855         if (wcscmp(m_tables[i]->GetFontName(),lpszFontName) == 0)
1856             return (CCombinedSegTable*) m_tables[i];
1857     }
1858 
1859     if (m_nTable == m_nMaxTable) {
1860         (void) MakeBiggerTable();
1861     }
1862     DASSERT(m_nTable < m_nMaxTable);
1863 
1864     m_tables[m_nTable] = new CCombinedSegTable;
1865     m_tables[m_nTable]->Create(lpszFontName);
1866 
1867     return (CCombinedSegTable*) m_tables[m_nTable++];
1868 }
1869 
1870 
1871 /************************************************************************
1872  * WDefaultFontCharset native methos
1873  */
1874 
1875 extern "C" {
1876 
1877 JNIEXPORT void JNICALL
1878 Java_sun_awt_windows_WDefaultFontCharset_initIDs(JNIEnv *env, jclass cls)
1879 {
1880     TRY;
1881 
1882     AwtFont::fontNameID = env->GetFieldID(cls, "fontName",
1883                                           "Ljava/lang/String;");
1884     DASSERT(AwtFont::fontNameID != NULL);
1885 
1886     CATCH_BAD_ALLOC;
1887 }
1888 
1889 
1890 /*
1891  * !!!!!!!!!!!!!!!!!!!! this does not work. I am not sure why, but
1892  * when active, this will reliably crash HJ, with no hope of debugging
1893  * for java.  It doesn't seem to crash the _g version.
1894  * !!!!!!!!!!!!!!!!!!!!!!!!!!!!
1895  *
1896  * I suspect may be running out of C stack: see alloca in
1897  * JNI_GET_STRING, the alloca in it.
1898  *
1899  * (the method is prefixed with XXX so that the linker won't find it) */
1900 JNIEXPORT jboolean JNICALL
1901 Java_sun_awt_windows_WDefaultFontCharset_canConvert(JNIEnv *env, jobject self,
1902                                                     jchar ch)
1903 {
1904     TRY;
1905 
1906     static CCombinedSegTableManager tableManager;
1907 
1908     jstring fontName = (jstring)env->GetObjectField(self, AwtFont::fontNameID);
1909     DASSERT(fontName != NULL);
1910     LPWSTR fontNameWStr = TO_WSTRING(fontName);
1911     CCombinedSegTable* pTable = tableManager.GetTable(fontNameWStr);
1912     return (pTable->In((USHORT) ch) ? JNI_TRUE : JNI_FALSE);
1913 
1914     CATCH_BAD_ALLOC_RET(FALSE);
1915 }
1916 
1917 } /* extern "C" */