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