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