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