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