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