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