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" */