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