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