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