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