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