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