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