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 
IsMultiFont(JNIEnv * env,jobject obj)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 
GetTextComponentFontName(JNIEnv * env,jobject font)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  */
AwtFont(int num,JNIEnv * env,jobject javaFont)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 
~AwtFont()156 AwtFont::~AwtFont()
157 {
158     delete[] m_hFont;
159 }
160 
Dispose()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 
pDataDisposeMethod(JNIEnv * env,jlong pData)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 
GetFont(JNIEnv * env,jobject font,jint angle,jfloat awScale)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.
GetNativeCharset(LPCWSTR name)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 
Create(JNIEnv * env,jobject font,jint angle,jfloat awScale)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 
strip_tail(wchar_t * text,wchar_t * tail)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 
ScaleUpX(float x)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 
ScaleUpY(int y)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 
ScaleDownX(int x)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 
ScaleDownY(int y)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 
CreateHFont_sub(LPCWSTR name,int style,int height,int angle=0,float awScale=1.0f)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 
CreateHFont(WCHAR * name,int style,int height,int angle,float awScale)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 
Cleanup()525 void AwtFont::Cleanup()
526 {
527     fontCache.Clear();
528 }
529 
SetupAscent(AwtFont * font)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 
LoadMetrics(JNIEnv * env,jobject fontMetrics)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 
TextSize(AwtFont * font,int columns,int rows)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 
getFontDescriptorNumber(JNIEnv * env,jobject font,jobject fontDescriptor)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  */
DrawStringSize_sub(jstring str,HDC hDC,jobject font,long x,long y,BOOL draw,UINT codePage)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
Java_sun_awt_windows_WFontMetrics_stringWidth(JNIEnv * env,jobject self,jstring str)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
Java_sun_awt_windows_WFontMetrics_charsWidth(JNIEnv * env,jobject self,jcharArray str,jint off,jint len)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
Java_sun_awt_windows_WFontMetrics_bytesWidth(JNIEnv * env,jobject self,jbyteArray str,jint off,jint len)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
Java_sun_awt_windows_WFontMetrics_init(JNIEnv * env,jobject self)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
Java_sun_awt_windows_WFontMetrics_initIDs(JNIEnv * env,jclass cls)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
Java_java_awt_Font_initIDs(JNIEnv * env,jclass cls)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
Java_java_awt_FontMetrics_initIDs(JNIEnv * env,jclass cls)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
Java_sun_awt_FontDescriptor_initIDs(JNIEnv * env,jclass cls)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
Java_sun_awt_PlatformFont_initIDs(JNIEnv * env,jclass cls)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
Java_sun_awt_windows_WFontPeer_initIDs(JNIEnv * env,jclass cls)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 
Add(WCHAR * name,HFONT font)1135 void AwtFontCache::Add(WCHAR* name, HFONT font)
1136 {
1137     fontCache.m_head = new Item(name, font, fontCache.m_head);
1138 }
1139 
Lookup(WCHAR * name)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 
Search(HFONT font)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 
Remove(HFONT font)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 
Clear()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 
IncRefCount(HFONT hFont)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 
IncRefCount(Item * item)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 
DecRefCount(Item * item)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 
Item(const WCHAR * s,HFONT f,AwtFontCache::Item * n)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 
~Item()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);
In(USHORT iChar)1262     virtual BOOL In(USHORT iChar) { DASSERT(FALSE); return FALSE; };
GetFontName()1263     LPWSTR GetFontName(){
1264         DASSERT(m_lpszFontName != NULL); return m_lpszFontName;
1265     };
1266 
1267 private:
1268     LPWSTR m_lpszFontName;
1269 };
1270 
CSegTableComponent()1271 CSegTableComponent::CSegTableComponent()
1272 {
1273     m_lpszFontName = NULL;
1274 }
1275 
~CSegTableComponent()1276 CSegTableComponent::~CSegTableComponent()
1277 {
1278     if (m_lpszFontName != NULL) {
1279         free(m_lpszFontName);
1280         m_lpszFontName = NULL;
1281     }
1282 }
1283 
Create(LPCWSTR name)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();
IsEUDC()1304     virtual BOOL IsEUDC() { DASSERT(FALSE); return FALSE; };
1305 
1306 protected:
GetData(DWORD dwOffset,LPVOID lpData,DWORD cbData)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 
CSegTable()1320 CSegTable::CSegTable()
1321 {
1322     m_cSegCount = 0;
1323     m_piStart = NULL;
1324     m_piEnd = NULL;
1325     m_cSeg = 0;
1326 }
1327 
~CSegTable()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 
MakeTable()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 
In(USHORT iChar)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 
HasCmap()1444 inline BOOL CSegTable::HasCmap()
1445 {
1446     return (((m_piEnd)&&(m_piStart)) ? TRUE : FALSE);
1447 }
1448 
SwapShort(USHORT & p)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 
SwapULong(ULONG & p)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();
IsEUDC()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 
CStdSegTable()1492 CStdSegTable::CStdSegTable()
1493 {
1494     m_hTmpDC = NULL;
1495 }
1496 
~CStdSegTable()1497 CStdSegTable::~CStdSegTable()
1498 {
1499     DASSERT(m_hTmpDC == NULL);
1500 }
1501 
GetData(DWORD dwOffset,LPVOID lpData,DWORD cbData)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 
Create(LPCWSTR name)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();
IsEUDC()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 
CEUDCSegTable()1549 CEUDCSegTable::CEUDCSegTable()
1550 {
1551     m_hTmpFile = NULL;
1552     m_hTmpCMapOffset = 0;
1553 }
1554 
~CEUDCSegTable()1555 CEUDCSegTable::~CEUDCSegTable()
1556 {
1557     DASSERT(m_hTmpFile == NULL);
1558     DASSERT(m_hTmpCMapOffset == 0);
1559 }
1560 
GetData(DWORD dwOffset,LPVOID lpData,DWORD cbData)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 
Create(LPCWSTR name)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 
CSegTableManagerComponent()1639 CSegTableManagerComponent::CSegTableManagerComponent()
1640 {
1641     m_nTable = 0;
1642     m_nMaxTable = TABLENUM;
1643     m_tables = new CSegTableComponent*[m_nMaxTable];
1644 }
1645 
~CSegTableManagerComponent()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 
MakeBiggerTable()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 
GetTable(LPCWSTR lpszFontName,BOOL fEUDC)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 
CCombinedSegTable()1728 CCombinedSegTable::CCombinedSegTable()
1729 {
1730     m_pStdSegTable = NULL;
1731     m_pEUDCSegTable = NULL;
1732 }
1733 
1734 #include <locale.h>
GetCodePageSubkey()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 
GetEUDCFileName(LPWSTR lpszFileName,int cchFileName)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 
Create(LPCWSTR name)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 
In(USHORT iChar)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 
GetTable(LPCWSTR lpszFontName)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
Java_sun_awt_windows_WDefaultFontCharset_initIDs(JNIEnv * env,jclass cls)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
Java_sun_awt_windows_WDefaultFontCharset_canConvert(JNIEnv * env,jobject self,jchar ch)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" */
1936