forked from AuroraMiddleware/gtk
12c7fc52d8
2001-12-28 Tor Lillqvist <tml@iki.fi> * gdk/win32/gdkfont-win32.c: Use G_N_ELEMENTS(). (unicode_classify): Don't return -1 on encountering an unclassified character, but play it safe and return U_BASIC_LATIN.
2102 lines
56 KiB
C
2102 lines
56 KiB
C
/* GDK - The GIMP Drawing Kit
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
|
* file for a list of people on the GTK+ Team. See the ChangeLog
|
|
* files for a list of changes. These files are distributed with
|
|
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#include <pango/pangowin32.h>
|
|
|
|
#include "gdkfont.h"
|
|
#include "gdkpango.h" /* gdk_pango_context_get() */
|
|
#include "gdkprivate-win32.h"
|
|
|
|
static GHashTable *font_name_hash = NULL;
|
|
static GHashTable *fontset_name_hash = NULL;
|
|
|
|
static void
|
|
gdk_font_hash_insert (GdkFontType type,
|
|
GdkFont *font,
|
|
const gchar *font_name)
|
|
{
|
|
GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
|
|
GHashTable **hashp = (type == GDK_FONT_FONT) ?
|
|
&font_name_hash : &fontset_name_hash;
|
|
|
|
if (!*hashp)
|
|
*hashp = g_hash_table_new (g_str_hash, g_str_equal);
|
|
|
|
private->names = g_slist_prepend (private->names, g_strdup (font_name));
|
|
g_hash_table_insert (*hashp, private->names->data, font);
|
|
}
|
|
|
|
static void
|
|
gdk_font_hash_remove (GdkFontType type,
|
|
GdkFont *font)
|
|
{
|
|
GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
|
|
GSList *tmp_list;
|
|
GHashTable *hash = (type == GDK_FONT_FONT) ?
|
|
font_name_hash : fontset_name_hash;
|
|
|
|
tmp_list = private->names;
|
|
while (tmp_list)
|
|
{
|
|
g_hash_table_remove (hash, tmp_list->data);
|
|
g_free (tmp_list->data);
|
|
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
|
|
g_slist_free (private->names);
|
|
private->names = NULL;
|
|
}
|
|
|
|
static GdkFont *
|
|
gdk_font_hash_lookup (GdkFontType type,
|
|
const gchar *font_name)
|
|
{
|
|
GdkFont *result;
|
|
GHashTable *hash = (type == GDK_FONT_FONT) ?
|
|
font_name_hash : fontset_name_hash;
|
|
|
|
if (!hash)
|
|
return NULL;
|
|
else
|
|
{
|
|
result = g_hash_table_lookup (hash, font_name);
|
|
if (result)
|
|
gdk_font_ref (result);
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
static const char *
|
|
charset_name (DWORD charset)
|
|
{
|
|
switch (charset)
|
|
{
|
|
case ANSI_CHARSET: return "ansi";
|
|
case DEFAULT_CHARSET: return "default";
|
|
case SYMBOL_CHARSET: return "symbol";
|
|
case SHIFTJIS_CHARSET: return "shiftjis";
|
|
case HANGEUL_CHARSET: return "hangeul";
|
|
case GB2312_CHARSET: return "gb2312";
|
|
case CHINESEBIG5_CHARSET: return "big5";
|
|
case JOHAB_CHARSET: return "johab";
|
|
case HEBREW_CHARSET: return "hebrew";
|
|
case ARABIC_CHARSET: return "arabic";
|
|
case GREEK_CHARSET: return "greek";
|
|
case TURKISH_CHARSET: return "turkish";
|
|
case VIETNAMESE_CHARSET: return "vietnamese";
|
|
case THAI_CHARSET: return "thai";
|
|
case EASTEUROPE_CHARSET: return "easteurope";
|
|
case RUSSIAN_CHARSET: return "russian";
|
|
case MAC_CHARSET: return "mac";
|
|
case BALTIC_CHARSET: return "baltic";
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
static gint num_fonts;
|
|
static gint font_names_size;
|
|
static gchar **xfontnames;
|
|
|
|
static gchar *
|
|
logfont_to_xlfd (const LOGFONT *lfp,
|
|
int size,
|
|
int res,
|
|
int avg_width)
|
|
{
|
|
const gchar *weight;
|
|
const gchar *registry, *encoding;
|
|
int point_size;
|
|
static int logpixelsy = 0;
|
|
gchar facename[LF_FACESIZE*5];
|
|
gchar *utf8_facename;
|
|
gchar *p;
|
|
const gchar *q;
|
|
|
|
if (logpixelsy == 0)
|
|
{
|
|
logpixelsy = GetDeviceCaps (gdk_display_hdc, LOGPIXELSY);
|
|
}
|
|
|
|
if (lfp->lfWeight >= FW_HEAVY)
|
|
weight = "heavy";
|
|
else if (lfp->lfWeight >= FW_EXTRABOLD)
|
|
weight = "extrabold";
|
|
else if (lfp->lfWeight >= FW_BOLD)
|
|
weight = "bold";
|
|
#ifdef FW_DEMIBOLD
|
|
else if (lfp->lfWeight >= FW_DEMIBOLD)
|
|
weight = "demibold";
|
|
#endif
|
|
else if (lfp->lfWeight >= FW_MEDIUM)
|
|
weight = "medium";
|
|
else if (lfp->lfWeight >= FW_NORMAL)
|
|
weight = "normal";
|
|
else if (lfp->lfWeight >= FW_LIGHT)
|
|
weight = "light";
|
|
else if (lfp->lfWeight >= FW_EXTRALIGHT)
|
|
weight = "extralight";
|
|
else if (lfp->lfWeight >= FW_THIN)
|
|
weight = "thin";
|
|
else
|
|
weight = "regular";
|
|
|
|
switch (lfp->lfCharSet)
|
|
{
|
|
case ANSI_CHARSET:
|
|
registry = "iso8859";
|
|
encoding = "1";
|
|
break;
|
|
case SHIFTJIS_CHARSET:
|
|
registry = "jisx0208.1983";
|
|
encoding = "0";
|
|
break;
|
|
case HANGEUL_CHARSET:
|
|
registry = "ksc5601.1987";
|
|
encoding = "0";
|
|
break;
|
|
case GB2312_CHARSET:
|
|
registry = "gb2312.1980";
|
|
encoding = "0";
|
|
break;
|
|
case CHINESEBIG5_CHARSET:
|
|
registry = "big5";
|
|
encoding = "0";
|
|
break;
|
|
case GREEK_CHARSET:
|
|
registry = "iso8859";
|
|
encoding = "7";
|
|
break;
|
|
case TURKISH_CHARSET:
|
|
registry = "iso8859";
|
|
encoding = "9";
|
|
break;
|
|
#if 0 /* Not a good idea, I think, to use ISO8859-8 and -6 for the Windows
|
|
* hebrew and arabic codepages, they differ too much.
|
|
*/
|
|
case HEBREW_CHARSET:
|
|
registry = "iso8859";
|
|
encoding = "8";
|
|
break;
|
|
case ARABIC_CHARSET:
|
|
registry = "iso8859";
|
|
encoding = "6";
|
|
break;
|
|
#endif
|
|
default:
|
|
registry = "microsoft";
|
|
encoding = charset_name (lfp->lfCharSet);
|
|
}
|
|
|
|
point_size = (int) (((double) size/logpixelsy) * 720.);
|
|
|
|
if (res == -1)
|
|
res = logpixelsy;
|
|
|
|
/* Convert the facename Windows fives us from the locale-dependent
|
|
* codepage to UTF-8.
|
|
*/
|
|
utf8_facename = g_filename_to_utf8 (lfp->lfFaceName, -1, NULL, NULL, NULL);
|
|
|
|
/* Replace characters illegal in an XLFD with hex escapes. */
|
|
p = facename;
|
|
q = utf8_facename;
|
|
while (*q)
|
|
{
|
|
if (*q == '-' || *q == '*' || *q == '?' || *q == '%')
|
|
p += sprintf (p, "%%%.02x", *q);
|
|
else
|
|
*p++ = *q;
|
|
q++;
|
|
}
|
|
*p = '\0';
|
|
g_free (utf8_facename);
|
|
|
|
return g_strdup_printf
|
|
("-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d-%s-%s",
|
|
"unknown",
|
|
facename,
|
|
weight,
|
|
(lfp->lfItalic ?
|
|
((lfp->lfPitchAndFamily & 0xF0) == FF_ROMAN
|
|
|| (lfp->lfPitchAndFamily & 0xF0) == FF_SCRIPT ?
|
|
"i" : "o") : "r"),
|
|
"normal",
|
|
"",
|
|
size,
|
|
point_size,
|
|
res,
|
|
res,
|
|
((lfp->lfPitchAndFamily & 0x03) == FIXED_PITCH ? "m" : "p"),
|
|
avg_width,
|
|
registry, encoding);
|
|
}
|
|
|
|
gchar *
|
|
gdk_font_full_name_get (GdkFont *font)
|
|
{
|
|
GdkFontPrivateWin32 *private;
|
|
GdkWin32SingleFont *singlefont;
|
|
GSList *list;
|
|
GString *string;
|
|
gchar *result;
|
|
gchar *xlfd;
|
|
LOGFONT logfont;
|
|
|
|
g_return_val_if_fail (font != NULL, NULL);
|
|
|
|
private = (GdkFontPrivateWin32 *) font;
|
|
|
|
list = private->fonts;
|
|
string = g_string_new ("");
|
|
|
|
while (list)
|
|
{
|
|
singlefont = (GdkWin32SingleFont *) list->data;
|
|
|
|
if (GetObject (singlefont->hfont, sizeof (LOGFONT), &logfont) == 0)
|
|
{
|
|
WIN32_GDI_FAILED ("GetObject");
|
|
return NULL;
|
|
}
|
|
|
|
xlfd = logfont_to_xlfd (&logfont, logfont.lfHeight, -1, 0);
|
|
string = g_string_append (string, xlfd);
|
|
g_free (xlfd);
|
|
list = list->next;
|
|
if (list)
|
|
string = g_string_append_c (string, ',');
|
|
}
|
|
result = string->str;
|
|
g_string_free (string, FALSE);
|
|
return result;
|
|
}
|
|
|
|
void
|
|
gdk_font_full_name_free (gchar *name)
|
|
{
|
|
g_free (name);
|
|
}
|
|
|
|
static gboolean
|
|
pattern_match (const gchar *pattern,
|
|
const gchar *string)
|
|
{
|
|
const gchar *p = pattern, *n = string;
|
|
gchar c, c1;
|
|
|
|
/* Common case first */
|
|
if ((pattern[0] == '*'
|
|
&& pattern[1] == '\0')
|
|
|| (pattern[0] == '-'
|
|
&& pattern[1] == '*'
|
|
&& pattern[2] == '\0'))
|
|
return TRUE;
|
|
|
|
while ((c = *p++) != '\0')
|
|
{
|
|
c = tolower (c);
|
|
|
|
switch (c)
|
|
{
|
|
case '?':
|
|
if (*n == '\0')
|
|
return FALSE;
|
|
break;
|
|
|
|
case '*':
|
|
for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
|
|
if (c == '?' && *n == '\0')
|
|
return FALSE;
|
|
|
|
if (c == '\0')
|
|
return TRUE;
|
|
|
|
c1 = tolower (c);
|
|
for (--p; *n != '\0'; ++n)
|
|
if (tolower (*n) == c1
|
|
&& pattern_match (p, n))
|
|
return TRUE;
|
|
return FALSE;
|
|
|
|
default:
|
|
if (c != tolower (*n))
|
|
return FALSE;
|
|
}
|
|
|
|
++n;
|
|
}
|
|
|
|
if (*n == '\0')
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int CALLBACK
|
|
InnerEnumFontFamExProc (const LOGFONT *lfp,
|
|
const TEXTMETRIC *metrics,
|
|
DWORD fontType,
|
|
LPARAM lParam)
|
|
{
|
|
int size;
|
|
gchar *xlfd;
|
|
|
|
if (fontType == TRUETYPE_FONTTYPE)
|
|
{
|
|
size = 0;
|
|
}
|
|
else
|
|
{
|
|
size = lfp->lfHeight;
|
|
}
|
|
|
|
xlfd = logfont_to_xlfd (lfp, size, 0, 0);
|
|
|
|
if (!pattern_match ((gchar *) lParam, xlfd))
|
|
{
|
|
g_free (xlfd);
|
|
return 1;
|
|
}
|
|
|
|
num_fonts++;
|
|
if (num_fonts == font_names_size)
|
|
{
|
|
font_names_size *= 2;
|
|
xfontnames = g_realloc (xfontnames, font_names_size * sizeof (gchar *));
|
|
}
|
|
xfontnames[num_fonts-1] = xlfd;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int CALLBACK
|
|
EnumFontFamExProc (const LOGFONT *lfp,
|
|
const TEXTMETRIC *metrics,
|
|
DWORD fontType,
|
|
LPARAM lParam)
|
|
{
|
|
if (fontType == TRUETYPE_FONTTYPE)
|
|
{
|
|
LOGFONT lf;
|
|
|
|
lf = *lfp;
|
|
|
|
EnumFontFamiliesEx (gdk_display_hdc, &lf, InnerEnumFontFamExProc, lParam, 0);
|
|
}
|
|
else
|
|
InnerEnumFontFamExProc (lfp, metrics, fontType, lParam);
|
|
|
|
return 1;
|
|
}
|
|
|
|
gchar **
|
|
gdk_font_list_new (const gchar *font_pattern,
|
|
gint *n_returned)
|
|
{
|
|
LOGFONT logfont;
|
|
gchar **result;
|
|
|
|
num_fonts = 0;
|
|
font_names_size = 100;
|
|
xfontnames = g_new (gchar *, font_names_size);
|
|
memset (&logfont, 0, sizeof (logfont));
|
|
logfont.lfCharSet = DEFAULT_CHARSET;
|
|
EnumFontFamiliesEx (gdk_display_hdc, &logfont, EnumFontFamExProc,
|
|
(LPARAM) font_pattern, 0);
|
|
|
|
result = g_new (gchar *, num_fonts + 1);
|
|
memmove (result, xfontnames, num_fonts * sizeof (gchar *));
|
|
result[num_fonts] = NULL;
|
|
g_free (xfontnames);
|
|
|
|
*n_returned = num_fonts;
|
|
return result;
|
|
}
|
|
|
|
void
|
|
gdk_font_list_free (gchar **font_list)
|
|
{
|
|
g_strfreev (font_list);
|
|
}
|
|
|
|
/* This table classifies Unicode characters according to the Microsoft
|
|
* Unicode subset numbering. This is based on the table in "Developing
|
|
* International Software for Windows 95 and Windows NT". This is almost,
|
|
* but not quite, the same as the official Unicode block table in
|
|
* Blocks.txt from ftp.unicode.org. The bit number field is the bitfield
|
|
* number as in the FONTSIGNATURE struct's fsUsb field.
|
|
* There are some grave bugs in the table in the books. For instance
|
|
* it claims there are Hangul at U+3400..U+4DFF while this range in
|
|
* fact contains CJK Unified Ideographs Extension A. Also, the whole
|
|
* block of Hangul Syllables U+AC00..U+D7A3 is missing from the book.
|
|
*/
|
|
|
|
typedef enum
|
|
{
|
|
U_BASIC_LATIN = 0,
|
|
U_LATIN_1_SUPPLEMENT = 1,
|
|
U_LATIN_EXTENDED_A = 2,
|
|
U_LATIN_EXTENDED_B = 3,
|
|
U_IPA_EXTENSIONS = 4,
|
|
U_SPACING_MODIFIER_LETTERS = 5,
|
|
U_COMBINING_DIACRITICAL_MARKS = 6,
|
|
U_BASIC_GREEK = 7,
|
|
U_GREEK_SYMBOLS_AND_COPTIC = 8,
|
|
U_CYRILLIC = 9,
|
|
U_ARMENIAN = 10,
|
|
U_HEBREW_EXTENDED = 12,
|
|
U_BASIC_HEBREW = 11,
|
|
U_BASIC_ARABIC = 13,
|
|
U_ARABIC_EXTENDED = 14,
|
|
U_DEVANAGARI = 15,
|
|
U_BENGALI = 16,
|
|
U_GURMUKHI = 17,
|
|
U_GUJARATI = 18,
|
|
U_ORIYA = 19,
|
|
U_TAMIL = 20,
|
|
U_TELUGU = 21,
|
|
U_KANNADA = 22,
|
|
U_MALAYALAM = 23,
|
|
U_THAI = 24,
|
|
U_LAO = 25,
|
|
U_GEORGIAN_EXTENDED = 27,
|
|
U_BASIC_GEORGIAN = 26,
|
|
U_HANGUL_JAMO = 28,
|
|
U_LATIN_EXTENDED_ADDITIONAL = 29,
|
|
U_GREEK_EXTENDED = 30,
|
|
U_GENERAL_PUNCTUATION = 31,
|
|
U_SUPERSCRIPTS_AND_SUBSCRIPTS = 32,
|
|
U_CURRENCY_SYMBOLS = 33,
|
|
U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS = 34,
|
|
U_LETTERLIKE_SYMBOLS = 35,
|
|
U_NUMBER_FORMS = 36,
|
|
U_ARROWS = 37,
|
|
U_MATHEMATICAL_OPERATORS = 38,
|
|
U_MISCELLANEOUS_TECHNICAL = 39,
|
|
U_CONTROL_PICTURES = 40,
|
|
U_OPTICAL_CHARACTER_RECOGNITION = 41,
|
|
U_ENCLOSED_ALPHANUMERICS = 42,
|
|
U_BOX_DRAWING = 43,
|
|
U_BLOCK_ELEMENTS = 44,
|
|
U_GEOMETRIC_SHAPES = 45,
|
|
U_MISCELLANEOUS_SYMBOLS = 46,
|
|
U_DINGBATS = 47,
|
|
U_CJK_SYMBOLS_AND_PUNCTUATION = 48,
|
|
U_HIRAGANA = 49,
|
|
U_KATAKANA = 50,
|
|
U_BOPOMOFO = 51,
|
|
U_HANGUL_COMPATIBILITY_JAMO = 52,
|
|
U_CJK_MISCELLANEOUS = 53,
|
|
U_ENCLOSED_CJK = 54,
|
|
U_CJK_COMPATIBILITY = 55,
|
|
U_HANGUL = 56,
|
|
U_HANGUL_SUPPLEMENTARY_A = 57,
|
|
U_HANGUL_SUPPLEMENTARY_B = 58,
|
|
U_CJK_UNIFIED_IDEOGRAPHS = 59,
|
|
U_PRIVATE_USE_AREA = 60,
|
|
U_CJK_COMPATIBILITY_IDEOGRAPHS = 61,
|
|
U_ALPHABETIC_PRESENTATION_FORMS = 62,
|
|
U_ARABIC_PRESENTATION_FORMS_A = 63,
|
|
U_COMBINING_HALF_MARKS = 64,
|
|
U_CJK_COMPATIBILITY_FORMS = 65,
|
|
U_SMALL_FORM_VARIANTS = 66,
|
|
U_ARABIC_PRESENTATION_FORMS_B = 67,
|
|
U_SPECIALS = 69,
|
|
U_HALFWIDTH_AND_FULLWIDTH_FORMS = 68,
|
|
U_LAST_PLUS_ONE
|
|
} unicode_subset;
|
|
|
|
static struct {
|
|
wchar_t low, high;
|
|
unicode_subset bit;
|
|
gchar *name;
|
|
} utab[] =
|
|
{
|
|
{ 0x0000, 0x007E,
|
|
U_BASIC_LATIN, "Basic Latin" },
|
|
{ 0x00A0, 0x00FF,
|
|
U_LATIN_1_SUPPLEMENT, "Latin-1 Supplement" },
|
|
{ 0x0100, 0x017F,
|
|
U_LATIN_EXTENDED_A, "Latin Extended-A" },
|
|
{ 0x0180, 0x024F,
|
|
U_LATIN_EXTENDED_B, "Latin Extended-B" },
|
|
{ 0x0250, 0x02AF,
|
|
U_IPA_EXTENSIONS, "IPA Extensions" },
|
|
{ 0x02B0, 0x02FF,
|
|
U_SPACING_MODIFIER_LETTERS, "Spacing Modifier Letters" },
|
|
{ 0x0300, 0x036F,
|
|
U_COMBINING_DIACRITICAL_MARKS, "Combining Diacritical Marks" },
|
|
{ 0x0370, 0x03CF,
|
|
U_BASIC_GREEK, "Basic Greek" },
|
|
{ 0x03D0, 0x03FF,
|
|
U_GREEK_SYMBOLS_AND_COPTIC, "Greek Symbols and Coptic" },
|
|
{ 0x0400, 0x04FF,
|
|
U_CYRILLIC, "Cyrillic" },
|
|
{ 0x0530, 0x058F,
|
|
U_ARMENIAN, "Armenian" },
|
|
{ 0x0590, 0x05CF,
|
|
U_HEBREW_EXTENDED, "Hebrew Extended" },
|
|
{ 0x05D0, 0x05FF,
|
|
U_BASIC_HEBREW, "Basic Hebrew" },
|
|
{ 0x0600, 0x0652,
|
|
U_BASIC_ARABIC, "Basic Arabic" },
|
|
{ 0x0653, 0x06FF,
|
|
U_ARABIC_EXTENDED, "Arabic Extended" },
|
|
{ 0x0900, 0x097F,
|
|
U_DEVANAGARI, "Devanagari" },
|
|
{ 0x0980, 0x09FF,
|
|
U_BENGALI, "Bengali" },
|
|
{ 0x0A00, 0x0A7F,
|
|
U_GURMUKHI, "Gurmukhi" },
|
|
{ 0x0A80, 0x0AFF,
|
|
U_GUJARATI, "Gujarati" },
|
|
{ 0x0B00, 0x0B7F,
|
|
U_ORIYA, "Oriya" },
|
|
{ 0x0B80, 0x0BFF,
|
|
U_TAMIL, "Tamil" },
|
|
{ 0x0C00, 0x0C7F,
|
|
U_TELUGU, "Telugu" },
|
|
{ 0x0C80, 0x0CFF,
|
|
U_KANNADA, "Kannada" },
|
|
{ 0x0D00, 0x0D7F,
|
|
U_MALAYALAM, "Malayalam" },
|
|
{ 0x0E00, 0x0E7F,
|
|
U_THAI, "Thai" },
|
|
{ 0x0E80, 0x0EFF,
|
|
U_LAO, "Lao" },
|
|
{ 0x10A0, 0x10CF,
|
|
U_GEORGIAN_EXTENDED, "Georgian Extended" },
|
|
{ 0x10D0, 0x10FF,
|
|
U_BASIC_GEORGIAN, "Basic Georgian" },
|
|
{ 0x1100, 0x11FF,
|
|
U_HANGUL_JAMO, "Hangul Jamo" },
|
|
{ 0x1E00, 0x1EFF,
|
|
U_LATIN_EXTENDED_ADDITIONAL, "Latin Extended Additional" },
|
|
{ 0x1F00, 0x1FFF,
|
|
U_GREEK_EXTENDED, "Greek Extended" },
|
|
{ 0x2000, 0x206F,
|
|
U_GENERAL_PUNCTUATION, "General Punctuation" },
|
|
{ 0x2070, 0x209F,
|
|
U_SUPERSCRIPTS_AND_SUBSCRIPTS, "Superscripts and Subscripts" },
|
|
{ 0x20A0, 0x20CF,
|
|
U_CURRENCY_SYMBOLS, "Currency Symbols" },
|
|
{ 0x20D0, 0x20FF,
|
|
U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS, "Combining Diacritical Marks for Symbols" },
|
|
{ 0x2100, 0x214F,
|
|
U_LETTERLIKE_SYMBOLS, "Letterlike Symbols" },
|
|
{ 0x2150, 0x218F,
|
|
U_NUMBER_FORMS, "Number Forms" },
|
|
{ 0x2190, 0x21FF,
|
|
U_ARROWS, "Arrows" },
|
|
{ 0x2200, 0x22FF,
|
|
U_MATHEMATICAL_OPERATORS, "Mathematical Operators" },
|
|
{ 0x2300, 0x23FF,
|
|
U_MISCELLANEOUS_TECHNICAL, "Miscellaneous Technical" },
|
|
{ 0x2400, 0x243F,
|
|
U_CONTROL_PICTURES, "Control Pictures" },
|
|
{ 0x2440, 0x245F,
|
|
U_OPTICAL_CHARACTER_RECOGNITION, "Optical Character Recognition" },
|
|
{ 0x2460, 0x24FF,
|
|
U_ENCLOSED_ALPHANUMERICS, "Enclosed Alphanumerics" },
|
|
{ 0x2500, 0x257F,
|
|
U_BOX_DRAWING, "Box Drawing" },
|
|
{ 0x2580, 0x259F,
|
|
U_BLOCK_ELEMENTS, "Block Elements" },
|
|
{ 0x25A0, 0x25FF,
|
|
U_GEOMETRIC_SHAPES, "Geometric Shapes" },
|
|
{ 0x2600, 0x26FF,
|
|
U_MISCELLANEOUS_SYMBOLS, "Miscellaneous Symbols" },
|
|
{ 0x2700, 0x27BF,
|
|
U_DINGBATS, "Dingbats" },
|
|
{ 0x3000, 0x303F,
|
|
U_CJK_SYMBOLS_AND_PUNCTUATION, "CJK Symbols and Punctuation" },
|
|
{ 0x3040, 0x309F,
|
|
U_HIRAGANA, "Hiragana" },
|
|
{ 0x30A0, 0x30FF,
|
|
U_KATAKANA, "Katakana" },
|
|
{ 0x3100, 0x312F,
|
|
U_BOPOMOFO, "Bopomofo" },
|
|
{ 0x3130, 0x318F,
|
|
U_HANGUL_COMPATIBILITY_JAMO, "Hangul Compatibility Jamo" },
|
|
{ 0x3190, 0x319F,
|
|
U_CJK_MISCELLANEOUS, "CJK Miscellaneous" },
|
|
{ 0x3200, 0x32FF,
|
|
U_ENCLOSED_CJK, "Enclosed CJK" },
|
|
{ 0x3300, 0x33FF,
|
|
U_CJK_COMPATIBILITY, "CJK Compatibility" },
|
|
/* The book claims:
|
|
* U+3400..U+3D2D = Hangul
|
|
* U+3D2E..U+44B7 = Hangul Supplementary A
|
|
* U+44B8..U+4DFF = Hangul Supplementary B
|
|
* but actually in Unicode
|
|
* U+3400..U+4DB5 = CJK Unified Ideographs Extension A
|
|
*/
|
|
{ 0x3400, 0x4DB5,
|
|
U_CJK_UNIFIED_IDEOGRAPHS, "CJK Unified Ideographs Extension A" },
|
|
{ 0x4E00, 0x9FFF,
|
|
U_CJK_UNIFIED_IDEOGRAPHS, "CJK Unified Ideographs" },
|
|
/* This was missing completely from the book's table. */
|
|
{ 0xAC00, 0xD7A3,
|
|
U_HANGUL, "Hangul Syllables" },
|
|
{ 0xE000, 0xF8FF,
|
|
U_PRIVATE_USE_AREA, "Private Use Area" },
|
|
{ 0xF900, 0xFAFF,
|
|
U_CJK_COMPATIBILITY_IDEOGRAPHS, "CJK Compatibility Ideographs" },
|
|
{ 0xFB00, 0xFB4F,
|
|
U_ALPHABETIC_PRESENTATION_FORMS, "Alphabetic Presentation Forms" },
|
|
{ 0xFB50, 0xFDFF,
|
|
U_ARABIC_PRESENTATION_FORMS_A, "Arabic Presentation Forms-A" },
|
|
{ 0xFE20, 0xFE2F,
|
|
U_COMBINING_HALF_MARKS, "Combining Half Marks" },
|
|
{ 0xFE30, 0xFE4F,
|
|
U_CJK_COMPATIBILITY_FORMS, "CJK Compatibility Forms" },
|
|
{ 0xFE50, 0xFE6F,
|
|
U_SMALL_FORM_VARIANTS, "Small Form Variants" },
|
|
{ 0xFE70, 0xFEFE,
|
|
U_ARABIC_PRESENTATION_FORMS_B, "Arabic Presentation Forms-B" },
|
|
{ 0xFEFF, 0xFEFF,
|
|
U_SPECIALS, "Specials" },
|
|
{ 0xFF00, 0xFFEF,
|
|
U_HALFWIDTH_AND_FULLWIDTH_FORMS, "Halfwidth and Fullwidth Forms" },
|
|
{ 0xFFF0, 0xFFFD,
|
|
U_SPECIALS, "Specials" }
|
|
};
|
|
|
|
static void
|
|
print_unicode_subranges (FONTSIGNATURE *fsp)
|
|
{
|
|
int i;
|
|
gboolean checked[G_N_ELEMENTS (utab)];
|
|
gboolean need_comma = FALSE;
|
|
|
|
memset (checked, 0, sizeof (checked));
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (utab); i++)
|
|
if (!checked[i]
|
|
&& (fsp->fsUsb[utab[i].bit/32] & (1 << (utab[i].bit % 32))))
|
|
{
|
|
g_print ("%s %s", (need_comma ? "," : ""), utab[i].name);
|
|
need_comma = TRUE;
|
|
checked[i] = TRUE;
|
|
}
|
|
if (!need_comma)
|
|
g_print (" none!");
|
|
g_print ("\n");
|
|
}
|
|
|
|
static gboolean
|
|
check_unicode_subranges (UINT charset,
|
|
FONTSIGNATURE *fsp)
|
|
{
|
|
gint i;
|
|
gboolean retval = FALSE;
|
|
|
|
/* If the fsUsb bit array has at least one of the bits set, trust it */
|
|
for (i = 0; i < U_LAST_PLUS_ONE; i++)
|
|
if (i != U_PRIVATE_USE_AREA && (fsp->fsUsb[i/32] & (1 << (i % 32))))
|
|
return FALSE;
|
|
|
|
/* Otherwise, guess what subranges there should be in the font */
|
|
fsp->fsUsb[0] = fsp->fsUsb[1] = fsp->fsUsb[2] = fsp->fsUsb[3] = 0;
|
|
|
|
#define set_bit(bitno) (fsp->fsUsb[(bitno)/32] |= (1 << ((bitno) % 32)))
|
|
|
|
/* Set Unicode subrange bits based on code pages supported.
|
|
* This is mostly just guesswork.
|
|
*/
|
|
|
|
#define check_cp(bit) (fsp->fsCsb[0] & (bit))
|
|
|
|
if (check_cp(FS_LATIN1))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_LATIN2))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_CYRILLIC))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_CYRILLIC);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_GREEK))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_BASIC_GREEK);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_TURKISH))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_HEBREW))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
set_bit (U_BASIC_HEBREW);
|
|
set_bit (U_HEBREW_EXTENDED);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_ARABIC))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
set_bit (U_BASIC_ARABIC);
|
|
set_bit (U_ARABIC_EXTENDED);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_BALTIC))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_VIETNAMESE))
|
|
{
|
|
/* ??? */
|
|
set_bit (U_BASIC_LATIN);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_THAI))
|
|
{
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_THAI);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_JISJAPAN))
|
|
{
|
|
/* Based on MS Gothic */
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_CJK_SYMBOLS_AND_PUNCTUATION);
|
|
set_bit (U_HIRAGANA);
|
|
set_bit (U_KATAKANA);
|
|
set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
|
|
set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_CHINESESIMP))
|
|
{
|
|
/* Based on MS Hei */
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_HIRAGANA);
|
|
set_bit (U_KATAKANA);
|
|
set_bit (U_BOPOMOFO);
|
|
set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_WANSUNG)
|
|
|| check_cp (FS_JOHAB)) /* ??? */
|
|
{
|
|
/* Based on GulimChe. I wonder if all Korean fonts
|
|
* really support this large range of Unicode subranges?
|
|
*/
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_SPACING_MODIFIER_LETTERS);
|
|
set_bit (U_BASIC_GREEK);
|
|
set_bit (U_CYRILLIC);
|
|
set_bit (U_HANGUL_JAMO);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_NUMBER_FORMS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_ENCLOSED_ALPHANUMERICS);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
set_bit (U_CJK_SYMBOLS_AND_PUNCTUATION);
|
|
set_bit (U_HIRAGANA);
|
|
set_bit (U_KATAKANA);
|
|
set_bit (U_HANGUL_COMPATIBILITY_JAMO);
|
|
set_bit (U_ENCLOSED_CJK);
|
|
set_bit (U_CJK_COMPATIBILITY_FORMS);
|
|
set_bit (U_HANGUL);
|
|
set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
|
|
set_bit (U_CJK_COMPATIBILITY_IDEOGRAPHS);
|
|
set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_CHINESETRAD))
|
|
{
|
|
/* Based on MingLiU */
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_CJK_SYMBOLS_AND_PUNCTUATION);
|
|
set_bit (U_BOPOMOFO);
|
|
set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
|
|
set_bit (U_CJK_COMPATIBILITY_IDEOGRAPHS);
|
|
set_bit (U_SMALL_FORM_VARIANTS);
|
|
set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
|
|
retval = TRUE;
|
|
}
|
|
if (check_cp (FS_SYMBOL) || charset == MAC_CHARSET)
|
|
{
|
|
/* Non-Unicode encoding, I guess. Pretend it covers
|
|
* the single-byte range of values.
|
|
*/
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
retval = TRUE;
|
|
}
|
|
|
|
if (retval)
|
|
return TRUE;
|
|
|
|
GDK_NOTE (MISC, g_print ("... No code page bits set!\n"));
|
|
|
|
/* Sigh. Not even any code page bits were set. Guess based on
|
|
* charset, then. These somewhat optimistic guesses are based on the
|
|
* table in Appendix M in the book "Developing ..." mentioned
|
|
* above.
|
|
*/
|
|
switch (charset)
|
|
{
|
|
case ANSI_CHARSET:
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
set_bit (U_SPACING_MODIFIER_LETTERS);
|
|
set_bit (U_COMBINING_DIACRITICAL_MARKS);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
#if 0 /* I find this too hard to believe... */
|
|
set_bit (U_BASIC_GREEK);
|
|
set_bit (U_CYRILLIC);
|
|
set_bit (U_BASIC_HEBREW);
|
|
set_bit (U_HEBREW_EXTENDED);
|
|
set_bit (U_BASIC_ARABIC);
|
|
set_bit (U_ARABIC_EXTENDED);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_NUMBER_FORMS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_ENCLOSED_ALPHANUMERICS);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
set_bit (U_HIRAGANA);
|
|
set_bit (U_KATAKANA);
|
|
set_bit (U_BOPOMOFO);
|
|
set_bit (U_HANGUL_COMPATIBILITY_JAMO);
|
|
set_bit (U_CJK_MISCELLANEOUS);
|
|
set_bit (U_CJK_COMPATIBILITY);
|
|
set_bit (U_HANGUL);
|
|
set_bit (U_HANGUL_SUPPLEMENTARY_A);
|
|
set_bit (U_CJK_COMPATIBILITY_IDEOGRAPHS);
|
|
set_bit (U_ALPHABETIC_PRESENTATION_FORMS);
|
|
set_bit (U_SMALL_FORM_VARIANTS);
|
|
set_bit (U_ARABIC_PRESENTATION_FORMS_B);
|
|
set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
|
|
set_bit (U_SPECIALS);
|
|
#endif
|
|
retval = TRUE;
|
|
break;
|
|
case SYMBOL_CHARSET:
|
|
/* Unggh */
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
retval = TRUE;
|
|
break;
|
|
case SHIFTJIS_CHARSET:
|
|
case HANGEUL_CHARSET:
|
|
case GB2312_CHARSET:
|
|
case CHINESEBIG5_CHARSET:
|
|
case JOHAB_CHARSET:
|
|
/* The table really does claim these "locales" (it doesn't
|
|
* talk about charsets per se) cover the same Unicode
|
|
* subranges
|
|
*/
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
set_bit (U_SPACING_MODIFIER_LETTERS);
|
|
set_bit (U_COMBINING_DIACRITICAL_MARKS_FOR_SYMBOLS);
|
|
set_bit (U_BASIC_GREEK);
|
|
set_bit (U_CYRILLIC);
|
|
set_bit (U_HANGUL_JAMO);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_NUMBER_FORMS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_ENCLOSED_ALPHANUMERICS);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
set_bit (U_CJK_SYMBOLS_AND_PUNCTUATION);
|
|
set_bit (U_HIRAGANA);
|
|
set_bit (U_KATAKANA);
|
|
set_bit (U_BOPOMOFO);
|
|
set_bit (U_HANGUL_COMPATIBILITY_JAMO);
|
|
set_bit (U_CJK_MISCELLANEOUS);
|
|
set_bit (U_CJK_COMPATIBILITY);
|
|
set_bit (U_HANGUL);
|
|
set_bit (U_HANGUL_SUPPLEMENTARY_A);
|
|
set_bit (U_CJK_UNIFIED_IDEOGRAPHS);
|
|
set_bit (U_CJK_COMPATIBILITY_IDEOGRAPHS);
|
|
set_bit (U_ALPHABETIC_PRESENTATION_FORMS);
|
|
set_bit (U_SMALL_FORM_VARIANTS);
|
|
set_bit (U_ARABIC_PRESENTATION_FORMS_B);
|
|
set_bit (U_SPECIALS);
|
|
retval = TRUE;
|
|
break;
|
|
case HEBREW_CHARSET:
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
set_bit (U_SPACING_MODIFIER_LETTERS);
|
|
set_bit (U_BASIC_HEBREW);
|
|
set_bit (U_HEBREW_EXTENDED);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
retval = TRUE;
|
|
break;
|
|
case ARABIC_CHARSET:
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
set_bit (U_SPACING_MODIFIER_LETTERS);
|
|
set_bit (U_BASIC_GREEK);
|
|
set_bit (U_BASIC_ARABIC);
|
|
set_bit (U_ARABIC_EXTENDED);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
set_bit (U_HALFWIDTH_AND_FULLWIDTH_FORMS);
|
|
retval = TRUE;
|
|
break;
|
|
case GREEK_CHARSET:
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
set_bit (U_BASIC_GREEK);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
retval = TRUE;
|
|
break;
|
|
case TURKISH_CHARSET:
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
set_bit (U_SPACING_MODIFIER_LETTERS);
|
|
set_bit (U_BASIC_GREEK);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
retval = TRUE;
|
|
break;
|
|
case VIETNAMESE_CHARSET:
|
|
case THAI_CHARSET:
|
|
/* These are not in the table, so I have no idea */
|
|
break;
|
|
case BALTIC_CHARSET:
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
set_bit (U_SPACING_MODIFIER_LETTERS);
|
|
set_bit (U_BASIC_GREEK);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
retval = TRUE;
|
|
break;
|
|
case EASTEUROPE_CHARSET:
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_LATIN_EXTENDED_A);
|
|
set_bit (U_LATIN_EXTENDED_B);
|
|
set_bit (U_SPACING_MODIFIER_LETTERS);
|
|
set_bit (U_BASIC_GREEK);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_SUPERSCRIPTS_AND_SUBSCRIPTS);
|
|
set_bit (U_CURRENCY_SYMBOLS);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
retval = TRUE;
|
|
break;
|
|
case RUSSIAN_CHARSET:
|
|
set_bit (U_BASIC_LATIN);
|
|
set_bit (U_LATIN_1_SUPPLEMENT);
|
|
set_bit (U_CYRILLIC);
|
|
set_bit (U_GENERAL_PUNCTUATION);
|
|
set_bit (U_LETTERLIKE_SYMBOLS);
|
|
set_bit (U_ARROWS);
|
|
set_bit (U_MATHEMATICAL_OPERATORS);
|
|
set_bit (U_MISCELLANEOUS_TECHNICAL);
|
|
set_bit (U_BOX_DRAWING);
|
|
set_bit (U_BLOCK_ELEMENTS);
|
|
set_bit (U_GEOMETRIC_SHAPES);
|
|
set_bit (U_MISCELLANEOUS_SYMBOLS);
|
|
retval = TRUE;
|
|
break;
|
|
}
|
|
|
|
#undef set_bit
|
|
return retval;
|
|
}
|
|
|
|
static GdkWin32SingleFont *
|
|
gdk_font_load_logfont (LOGFONT *lfp)
|
|
{
|
|
GdkWin32SingleFont *singlefont;
|
|
HFONT hfont;
|
|
LOGFONT logfont;
|
|
CHARSETINFO csi;
|
|
HGDIOBJ oldfont;
|
|
int tries;
|
|
gchar face[100];
|
|
|
|
for (tries = 0; ; tries++)
|
|
{
|
|
GDK_NOTE (MISC, g_print ("... trying %ld,%ld,%ld,%ld,"
|
|
"%ld,%d,%d,%d,"
|
|
"%d,%d,%d,"
|
|
"%d,%#.02x,\"%s\"\n",
|
|
lfp->lfHeight, lfp->lfWidth,
|
|
lfp->lfEscapement, lfp->lfOrientation,
|
|
lfp->lfWeight, lfp->lfItalic,
|
|
lfp->lfUnderline, lfp->lfStrikeOut,
|
|
lfp->lfCharSet,
|
|
lfp->lfOutPrecision, lfp->lfClipPrecision,
|
|
lfp->lfQuality, lfp->lfPitchAndFamily,
|
|
lfp->lfFaceName));
|
|
hfont = CreateFontIndirect (lfp);
|
|
|
|
if (hfont != NULL)
|
|
break;
|
|
|
|
/* If we fail, try some similar fonts often found on Windows. */
|
|
if (tries == 0)
|
|
{
|
|
if (g_strcasecmp (lfp->lfFaceName, "helvetica") == 0)
|
|
strcpy (lfp->lfFaceName, "arial");
|
|
else if (g_strcasecmp (lfp->lfFaceName, "new century schoolbook") == 0)
|
|
strcpy (lfp->lfFaceName, "century schoolbook");
|
|
else if (g_strcasecmp (lfp->lfFaceName, "courier") == 0)
|
|
strcpy (lfp->lfFaceName, "courier new");
|
|
else if (g_strcasecmp (lfp->lfFaceName, "lucida") == 0)
|
|
strcpy (lfp->lfFaceName, "lucida sans unicode");
|
|
else if (g_strcasecmp (lfp->lfFaceName, "lucidatypewriter") == 0)
|
|
strcpy (lfp->lfFaceName, "lucida console");
|
|
else if (g_strcasecmp (lfp->lfFaceName, "times") == 0)
|
|
strcpy (lfp->lfFaceName, "times new roman");
|
|
}
|
|
else if (tries == 1)
|
|
{
|
|
if (g_strcasecmp (lfp->lfFaceName, "courier") == 0)
|
|
{
|
|
strcpy (lfp->lfFaceName, "");
|
|
lfp->lfPitchAndFamily |= FF_MODERN;
|
|
}
|
|
else if (g_strcasecmp (lfp->lfFaceName, "times new roman") == 0)
|
|
{
|
|
strcpy (lfp->lfFaceName, "");
|
|
lfp->lfPitchAndFamily |= FF_ROMAN;
|
|
}
|
|
else if (g_strcasecmp (lfp->lfFaceName, "helvetica") == 0
|
|
|| g_strcasecmp (lfp->lfFaceName, "lucida") == 0)
|
|
{
|
|
strcpy (lfp->lfFaceName, "");
|
|
lfp->lfPitchAndFamily |= FF_SWISS;
|
|
}
|
|
else
|
|
{
|
|
strcpy (lfp->lfFaceName, "");
|
|
lfp->lfPitchAndFamily = (lfp->lfPitchAndFamily & 0x0F) | FF_DONTCARE;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
tries++;
|
|
}
|
|
|
|
if (!hfont)
|
|
return NULL;
|
|
|
|
singlefont = g_new (GdkWin32SingleFont, 1);
|
|
singlefont->hfont = hfont;
|
|
GetObject (singlefont->hfont, sizeof (logfont), &logfont);
|
|
oldfont = SelectObject (gdk_display_hdc, singlefont->hfont);
|
|
memset (&singlefont->fs, 0, sizeof (singlefont->fs));
|
|
singlefont->charset = GetTextCharsetInfo (gdk_display_hdc, &singlefont->fs, 0);
|
|
GetTextFace (gdk_display_hdc, sizeof (face), face);
|
|
SelectObject (gdk_display_hdc, oldfont);
|
|
if (TranslateCharsetInfo ((DWORD *) singlefont->charset, &csi,
|
|
TCI_SRCCHARSET)
|
|
&& singlefont->charset != MAC_CHARSET)
|
|
singlefont->codepage = csi.ciACP;
|
|
else
|
|
singlefont->codepage = 0;
|
|
|
|
GDK_NOTE (MISC, (g_print ("... = %#x %s cs %s cp%d\n",
|
|
(guint) singlefont->hfont, face,
|
|
charset_name (singlefont->charset),
|
|
singlefont->codepage),
|
|
g_print ("... Unicode subranges:"),
|
|
print_unicode_subranges (&singlefont->fs)));
|
|
if (check_unicode_subranges (singlefont->charset, &singlefont->fs))
|
|
GDK_NOTE (MISC, (g_print ("... Guesstimated Unicode subranges:"),
|
|
print_unicode_subranges (&singlefont->fs)));
|
|
|
|
return singlefont;
|
|
}
|
|
|
|
static GdkWin32SingleFont *
|
|
gdk_font_load_internal (const gchar *font_name)
|
|
{
|
|
LOGFONT logfont;
|
|
|
|
char *fn;
|
|
int numfields, n1, n2;
|
|
char foundry[32], family[100], weight[32], slant[32], set_width[32],
|
|
spacing[32], registry[32], encoding[32];
|
|
char pixel_size[10], point_size[10], res_x[10], res_y[10], avg_width[10];
|
|
int c;
|
|
char *p;
|
|
int logpixelsy;
|
|
|
|
g_return_val_if_fail (font_name != NULL, NULL);
|
|
|
|
GDK_NOTE (MISC, g_print ("gdk_font_load_internal: %s\n", font_name));
|
|
|
|
numfields = sscanf (font_name,
|
|
"-%30[^-]-%100[^-]-%30[^-]-%30[^-]-%30[^-]-%n",
|
|
foundry,
|
|
family,
|
|
weight,
|
|
slant,
|
|
set_width,
|
|
&n1);
|
|
if (numfields == 0)
|
|
{
|
|
/* Probably a plain Windows font name */
|
|
logfont.lfHeight = 0;
|
|
logfont.lfWidth = 0;
|
|
logfont.lfEscapement = 0;
|
|
logfont.lfOrientation = 0;
|
|
logfont.lfWeight = FW_DONTCARE;
|
|
logfont.lfItalic = FALSE;
|
|
logfont.lfUnderline = FALSE;
|
|
logfont.lfStrikeOut = FALSE;
|
|
logfont.lfCharSet = ANSI_CHARSET;
|
|
logfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
|
|
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
logfont.lfQuality = PROOF_QUALITY;
|
|
logfont.lfPitchAndFamily = DEFAULT_PITCH;
|
|
fn = g_filename_from_utf8 (font_name, -1, NULL, NULL, NULL);
|
|
strcpy (logfont.lfFaceName, fn);
|
|
g_free (fn);
|
|
}
|
|
else if (numfields != 5)
|
|
{
|
|
g_warning ("gdk_font_load: font name %s illegal", font_name);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
/* It must be a XLFD name */
|
|
|
|
/* Check for hex escapes in the font family,
|
|
* put in there by logfont_to_xlfd. Convert them in-place.
|
|
*/
|
|
p = family;
|
|
while (*p)
|
|
{
|
|
if (*p == '%' && isxdigit (p[1]) && isxdigit (p[2]))
|
|
{
|
|
sscanf (p+1, "%2x", &c);
|
|
*p = c;
|
|
strcpy (p+1, p+3);
|
|
}
|
|
p++;
|
|
}
|
|
|
|
/* Skip add_style which often is empty in the requested font name */
|
|
while (font_name[n1] && font_name[n1] != '-')
|
|
n1++;
|
|
numfields++;
|
|
|
|
numfields += sscanf (font_name + n1,
|
|
"-%8[^-]-%8[^-]-%8[^-]-%8[^-]-%30[^-]-%8[^-]-%30[^-]-%30[^-]%n",
|
|
pixel_size,
|
|
point_size,
|
|
res_x,
|
|
res_y,
|
|
spacing,
|
|
avg_width,
|
|
registry,
|
|
encoding,
|
|
&n2);
|
|
|
|
if (numfields != 14 || font_name[n1 + n2] != '\0')
|
|
{
|
|
g_warning ("gdk_font_load: font name %s illegal", font_name);
|
|
return NULL;
|
|
}
|
|
|
|
logpixelsy = GetDeviceCaps (gdk_display_hdc, LOGPIXELSY);
|
|
|
|
if (strcmp (pixel_size, "*") == 0)
|
|
if (strcmp (point_size, "*") == 0)
|
|
logfont.lfHeight = 0;
|
|
else
|
|
logfont.lfHeight = (int) (((double) atoi (point_size))/720.*logpixelsy);
|
|
else
|
|
logfont.lfHeight = atoi (pixel_size);
|
|
|
|
logfont.lfWidth = 0;
|
|
logfont.lfEscapement = 0;
|
|
logfont.lfOrientation = 0;
|
|
|
|
if (g_strcasecmp (weight, "thin") == 0)
|
|
logfont.lfWeight = FW_THIN;
|
|
else if (g_strcasecmp (weight, "extralight") == 0)
|
|
logfont.lfWeight = FW_EXTRALIGHT;
|
|
else if (g_strcasecmp (weight, "ultralight") == 0)
|
|
#ifdef FW_ULTRALIGHT
|
|
logfont.lfWeight = FW_ULTRALIGHT;
|
|
#else
|
|
logfont.lfWeight = FW_EXTRALIGHT; /* In fact, FW_ULTRALIGHT really is
|
|
* defined as FW_EXTRALIGHT anyway.
|
|
*/
|
|
#endif
|
|
else if (g_strcasecmp (weight, "light") == 0)
|
|
logfont.lfWeight = FW_LIGHT;
|
|
else if (g_strcasecmp (weight, "normal") == 0)
|
|
logfont.lfWeight = FW_NORMAL;
|
|
else if (g_strcasecmp (weight, "regular") == 0)
|
|
logfont.lfWeight = FW_REGULAR;
|
|
else if (g_strcasecmp (weight, "medium") == 0)
|
|
logfont.lfWeight = FW_MEDIUM;
|
|
else if (g_strcasecmp (weight, "semibold") == 0)
|
|
logfont.lfWeight = FW_SEMIBOLD;
|
|
else if (g_strcasecmp (weight, "demibold") == 0)
|
|
#ifdef FW_DEMIBOLD
|
|
logfont.lfWeight = FW_DEMIBOLD;
|
|
#else
|
|
logfont.lfWeight = FW_SEMIBOLD; /* As above */
|
|
#endif
|
|
else if (g_strcasecmp (weight, "bold") == 0)
|
|
logfont.lfWeight = FW_BOLD;
|
|
else if (g_strcasecmp (weight, "extrabold") == 0)
|
|
logfont.lfWeight = FW_EXTRABOLD;
|
|
else if (g_strcasecmp (weight, "ultrabold") == 0)
|
|
#ifdef FW_ULTRABOLD
|
|
logfont.lfWeight = FW_ULTRABOLD;
|
|
#else
|
|
logfont.lfWeight = FW_EXTRABOLD; /* As above */
|
|
#endif
|
|
else if (g_strcasecmp (weight, "heavy") == 0)
|
|
logfont.lfWeight = FW_HEAVY;
|
|
else if (g_strcasecmp (weight, "black") == 0)
|
|
#ifdef FW_BLACK
|
|
logfont.lfWeight = FW_BLACK;
|
|
#else
|
|
logfont.lfWeight = FW_HEAVY; /* As above */
|
|
#endif
|
|
else
|
|
logfont.lfWeight = FW_DONTCARE;
|
|
|
|
if (g_strcasecmp (slant, "italic") == 0
|
|
|| g_strcasecmp (slant, "oblique") == 0
|
|
|| g_strcasecmp (slant, "i") == 0
|
|
|| g_strcasecmp (slant, "o") == 0)
|
|
logfont.lfItalic = TRUE;
|
|
else
|
|
logfont.lfItalic = FALSE;
|
|
logfont.lfUnderline = FALSE;
|
|
logfont.lfStrikeOut = FALSE;
|
|
if (g_strcasecmp (registry, "iso8859") == 0)
|
|
if (strcmp (encoding, "1") == 0)
|
|
logfont.lfCharSet = ANSI_CHARSET;
|
|
else if (strcmp (encoding, "2") == 0)
|
|
logfont.lfCharSet = EASTEUROPE_CHARSET;
|
|
else if (strcmp (encoding, "7") == 0)
|
|
logfont.lfCharSet = GREEK_CHARSET;
|
|
else if (strcmp (encoding, "8") == 0)
|
|
logfont.lfCharSet = HEBREW_CHARSET;
|
|
else if (strcmp (encoding, "9") == 0)
|
|
logfont.lfCharSet = TURKISH_CHARSET;
|
|
else
|
|
logfont.lfCharSet = ANSI_CHARSET; /* XXX ??? */
|
|
else if (g_strcasecmp (registry, "jisx0208.1983") == 0)
|
|
logfont.lfCharSet = SHIFTJIS_CHARSET;
|
|
else if (g_strcasecmp (registry, "ksc5601.1987") == 0)
|
|
logfont.lfCharSet = HANGEUL_CHARSET;
|
|
else if (g_strcasecmp (registry, "gb2312.1980") == 0)
|
|
logfont.lfCharSet = GB2312_CHARSET;
|
|
else if (g_strcasecmp (registry, "big5") == 0)
|
|
logfont.lfCharSet = CHINESEBIG5_CHARSET;
|
|
else if (g_strcasecmp (registry, "windows") == 0
|
|
|| g_strcasecmp (registry, "microsoft") == 0)
|
|
if (g_strcasecmp (encoding, "symbol") == 0)
|
|
logfont.lfCharSet = SYMBOL_CHARSET;
|
|
else if (g_strcasecmp (encoding, "shiftjis") == 0)
|
|
logfont.lfCharSet = SHIFTJIS_CHARSET;
|
|
else if (g_strcasecmp (encoding, "gb2312") == 0)
|
|
logfont.lfCharSet = GB2312_CHARSET;
|
|
else if (g_strcasecmp (encoding, "hangeul") == 0)
|
|
logfont.lfCharSet = HANGEUL_CHARSET;
|
|
else if (g_strcasecmp (encoding, "big5") == 0)
|
|
logfont.lfCharSet = CHINESEBIG5_CHARSET;
|
|
else if (g_strcasecmp (encoding, "johab") == 0)
|
|
logfont.lfCharSet = JOHAB_CHARSET;
|
|
else if (g_strcasecmp (encoding, "hebrew") == 0)
|
|
logfont.lfCharSet = HEBREW_CHARSET;
|
|
else if (g_strcasecmp (encoding, "arabic") == 0)
|
|
logfont.lfCharSet = ARABIC_CHARSET;
|
|
else if (g_strcasecmp (encoding, "greek") == 0)
|
|
logfont.lfCharSet = GREEK_CHARSET;
|
|
else if (g_strcasecmp (encoding, "turkish") == 0)
|
|
logfont.lfCharSet = TURKISH_CHARSET;
|
|
else if (g_strcasecmp (encoding, "easteurope") == 0)
|
|
logfont.lfCharSet = EASTEUROPE_CHARSET;
|
|
else if (g_strcasecmp (encoding, "russian") == 0)
|
|
logfont.lfCharSet = RUSSIAN_CHARSET;
|
|
else if (g_strcasecmp (encoding, "mac") == 0)
|
|
logfont.lfCharSet = MAC_CHARSET;
|
|
else if (g_strcasecmp (encoding, "baltic") == 0)
|
|
logfont.lfCharSet = BALTIC_CHARSET;
|
|
else if (g_strcasecmp (encoding, "cp1251") == 0)
|
|
logfont.lfCharSet = RUSSIAN_CHARSET;
|
|
else
|
|
logfont.lfCharSet = ANSI_CHARSET; /* XXX ??? */
|
|
else
|
|
logfont.lfCharSet = ANSI_CHARSET; /* XXX ??? */
|
|
logfont.lfOutPrecision = OUT_TT_PRECIS;
|
|
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
logfont.lfQuality = PROOF_QUALITY;
|
|
if (g_strcasecmp (spacing, "m") == 0)
|
|
logfont.lfPitchAndFamily = FIXED_PITCH;
|
|
else if (g_strcasecmp (spacing, "p") == 0)
|
|
logfont.lfPitchAndFamily = VARIABLE_PITCH;
|
|
else
|
|
logfont.lfPitchAndFamily = DEFAULT_PITCH;
|
|
fn = g_filename_from_utf8 (family, -1, NULL, NULL, NULL);
|
|
strcpy (logfont.lfFaceName, fn);
|
|
g_free (fn);
|
|
}
|
|
|
|
return gdk_font_load_logfont (&logfont);
|
|
}
|
|
|
|
static GdkFont *
|
|
gdk_font_from_one_singlefont (GdkWin32SingleFont *singlefont)
|
|
{
|
|
GdkFont *font;
|
|
GdkFontPrivateWin32 *private;
|
|
HGDIOBJ oldfont;
|
|
TEXTMETRIC textmetric;
|
|
|
|
private = g_new (GdkFontPrivateWin32, 1);
|
|
font = (GdkFont*) private;
|
|
|
|
private->base.ref_count = 1;
|
|
private->names = NULL;
|
|
private->fonts = g_slist_append (NULL, singlefont);
|
|
|
|
/* Pretend all fonts are fontsets... Gtktext and gtkentry work better
|
|
* that way, they use wide chars, which is necessary for non-ASCII
|
|
* chars to work. (Yes, even Latin-1, as we use Unicode internally.)
|
|
*/
|
|
font->type = GDK_FONT_FONTSET;
|
|
oldfont = SelectObject (gdk_display_hdc, singlefont->hfont);
|
|
GetTextMetrics (gdk_display_hdc, &textmetric);
|
|
SelectObject (gdk_display_hdc, oldfont);
|
|
font->ascent = textmetric.tmAscent;
|
|
font->descent = textmetric.tmDescent;
|
|
|
|
GDK_NOTE (MISC, g_print ("... asc %d desc %d\n",
|
|
font->ascent, font->descent));
|
|
|
|
return font;
|
|
}
|
|
|
|
GdkFont*
|
|
gdk_font_load (const gchar *font_name)
|
|
{
|
|
GdkFont *font;
|
|
GdkFontPrivateWin32 *private;
|
|
GdkWin32SingleFont *singlefont;
|
|
HGDIOBJ oldfont;
|
|
TEXTMETRIC textmetric;
|
|
|
|
g_return_val_if_fail (font_name != NULL, NULL);
|
|
|
|
font = gdk_font_hash_lookup (GDK_FONT_FONTSET, font_name);
|
|
if (font)
|
|
return font;
|
|
|
|
private = g_new (GdkFontPrivateWin32, 1);
|
|
font = (GdkFont*) private;
|
|
|
|
singlefont = gdk_font_load_internal (font_name);
|
|
|
|
private->base.ref_count = 1;
|
|
private->names = NULL;
|
|
private->fonts = g_slist_append (NULL, singlefont);
|
|
|
|
/* Pretend all fonts are fontsets... Gtktext and gtkentry work better
|
|
* that way, they use wide chars, which is necessary for non-ASCII
|
|
* chars to work. (Yes, even Latin-1, as we use Unicode internally.)
|
|
*/
|
|
font->type = GDK_FONT_FONTSET;
|
|
oldfont = SelectObject (gdk_display_hdc, singlefont->hfont);
|
|
GetTextMetrics (gdk_display_hdc, &textmetric);
|
|
SelectObject (gdk_display_hdc, oldfont);
|
|
font->ascent = textmetric.tmAscent;
|
|
font->descent = textmetric.tmDescent;
|
|
|
|
GDK_NOTE (MISC, g_print ("... asc %d desc %d\n",
|
|
font->ascent, font->descent));
|
|
|
|
gdk_font_hash_insert (GDK_FONT_FONTSET, font, font_name);
|
|
|
|
return gdk_font_from_one_singlefont (gdk_font_load_internal (font_name));
|
|
}
|
|
|
|
/**
|
|
* gdk_font_from_description:
|
|
* @font_desc: a #PangoFontDescription.
|
|
*
|
|
* Load a #GdkFont based on a Pango font description. This font will
|
|
* only be an approximation of the Pango font, and
|
|
* internationalization will not be handled correctly. This function
|
|
* should only be used for legacy code that cannot be easily converted
|
|
* to use Pango. Using Pango directly will produce better results.
|
|
*
|
|
* Return value: the newly loaded font, or %NULL if the font
|
|
* cannot be loaded.
|
|
**/
|
|
GdkFont*
|
|
gdk_font_from_description (PangoFontDescription *font_desc)
|
|
{
|
|
PangoFontMap *font_map;
|
|
PangoFont *font;
|
|
GdkFont *result = NULL;
|
|
|
|
g_return_val_if_fail (font_desc != NULL, NULL);
|
|
|
|
font_map = pango_win32_font_map_for_display ();
|
|
font = pango_font_map_load_font (font_map, gdk_pango_context_get (), font_desc);
|
|
|
|
if (font)
|
|
{
|
|
LOGFONT *lfp =
|
|
pango_win32_font_logfont (font);
|
|
result = gdk_font_from_one_singlefont (gdk_font_load_logfont (lfp));
|
|
g_free (lfp);
|
|
|
|
g_object_unref (G_OBJECT (font));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
GdkFont*
|
|
gdk_fontset_load (const gchar *fontset_name)
|
|
{
|
|
GdkFont *font;
|
|
GdkFontPrivateWin32 *private;
|
|
GdkWin32SingleFont *singlefont;
|
|
HGDIOBJ oldfont;
|
|
TEXTMETRIC textmetric;
|
|
gchar *fs;
|
|
gchar *b, *p, *s;
|
|
|
|
g_return_val_if_fail (fontset_name != NULL, NULL);
|
|
|
|
font = gdk_font_hash_lookup (GDK_FONT_FONTSET, fontset_name);
|
|
if (font)
|
|
return font;
|
|
|
|
s = fs = g_strdup (fontset_name);
|
|
while (*s && isspace (*s))
|
|
s++;
|
|
|
|
g_return_val_if_fail (*s, NULL);
|
|
|
|
private = g_new (GdkFontPrivateWin32, 1);
|
|
font = (GdkFont*) private;
|
|
|
|
private->base.ref_count = 1;
|
|
private->names = NULL;
|
|
private->fonts = NULL;
|
|
|
|
font->type = GDK_FONT_FONTSET;
|
|
font->ascent = 0;
|
|
font->descent = 0;
|
|
|
|
while (TRUE)
|
|
{
|
|
if ((p = strchr (s, ',')) != NULL)
|
|
b = p;
|
|
else
|
|
b = s + strlen (s);
|
|
|
|
while (isspace (b[-1]))
|
|
b--;
|
|
*b = '\0';
|
|
singlefont = gdk_font_load_internal (s);
|
|
if (singlefont)
|
|
{
|
|
private->fonts = g_slist_append (private->fonts, singlefont);
|
|
oldfont = SelectObject (gdk_display_hdc, singlefont->hfont);
|
|
GetTextMetrics (gdk_display_hdc, &textmetric);
|
|
SelectObject (gdk_display_hdc, oldfont);
|
|
font->ascent = MAX (font->ascent, textmetric.tmAscent);
|
|
font->descent = MAX (font->descent, textmetric.tmDescent);
|
|
}
|
|
if (p)
|
|
{
|
|
s = p + 1;
|
|
while (*s && isspace (*s))
|
|
s++;
|
|
}
|
|
else
|
|
break;
|
|
if (!*s)
|
|
break;
|
|
}
|
|
|
|
g_free (fs);
|
|
|
|
gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
|
|
|
|
return font;
|
|
}
|
|
|
|
void
|
|
_gdk_font_destroy (GdkFont *font)
|
|
{
|
|
GdkFontPrivateWin32 *private = (GdkFontPrivateWin32 *) font;
|
|
GdkWin32SingleFont *singlefont;
|
|
GSList *list;
|
|
|
|
singlefont = (GdkWin32SingleFont *) private->fonts->data;
|
|
GDK_NOTE (MISC, g_print ("_gdk_font_destroy %#x\n",
|
|
(guint)singlefont->hfont));
|
|
|
|
gdk_font_hash_remove (font->type, font);
|
|
|
|
switch (font->type)
|
|
{
|
|
case GDK_FONT_FONT:
|
|
DeleteObject (singlefont->hfont);
|
|
break;
|
|
|
|
case GDK_FONT_FONTSET:
|
|
list = private->fonts;
|
|
while (list)
|
|
{
|
|
singlefont = (GdkWin32SingleFont *) list->data;
|
|
DeleteObject (singlefont->hfont);
|
|
|
|
list = list->next;
|
|
}
|
|
g_slist_free (private->fonts);
|
|
break;
|
|
}
|
|
g_free (font);
|
|
}
|
|
|
|
gint
|
|
_gdk_font_strlen (GdkFont *font,
|
|
const gchar *str)
|
|
{
|
|
g_return_val_if_fail (font != NULL, -1);
|
|
g_return_val_if_fail (str != NULL, -1);
|
|
|
|
return strlen (str);
|
|
}
|
|
|
|
gint
|
|
gdk_font_id (const GdkFont *font)
|
|
{
|
|
const GdkFontPrivateWin32 *private;
|
|
|
|
g_return_val_if_fail (font != NULL, 0);
|
|
|
|
private = (const GdkFontPrivateWin32 *) font;
|
|
|
|
if (font->type == GDK_FONT_FONT)
|
|
return (gint) ((GdkWin32SingleFont *) private->fonts->data)->hfont;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
gboolean
|
|
gdk_font_equal (const GdkFont *fonta,
|
|
const GdkFont *fontb)
|
|
{
|
|
const GdkFontPrivateWin32 *privatea;
|
|
const GdkFontPrivateWin32 *privateb;
|
|
|
|
g_return_val_if_fail (fonta != NULL, FALSE);
|
|
g_return_val_if_fail (fontb != NULL, FALSE);
|
|
|
|
privatea = (const GdkFontPrivateWin32 *) fonta;
|
|
privateb = (const GdkFontPrivateWin32 *) fontb;
|
|
|
|
if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
|
|
return (((GdkWin32SingleFont *) privatea->fonts->data)->hfont
|
|
== ((GdkWin32SingleFont *) privateb->fonts->data)->hfont);
|
|
else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
|
|
{
|
|
GSList *lista = privatea->fonts;
|
|
GSList *listb = privateb->fonts;
|
|
|
|
while (lista && listb)
|
|
{
|
|
if (((GdkWin32SingleFont *) lista->data)->hfont
|
|
!= ((GdkWin32SingleFont *) listb->data)->hfont)
|
|
return 0;
|
|
lista = lista->next;
|
|
listb = listb->next;
|
|
}
|
|
if (lista || listb)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/* Return the Unicode Subset bitfield number for a Unicode character */
|
|
|
|
static int
|
|
unicode_classify (wchar_t wc)
|
|
{
|
|
int min = 0;
|
|
int max = G_N_ELEMENTS (utab) - 1;
|
|
int mid;
|
|
|
|
while (max >= min)
|
|
{
|
|
mid = (min + max) / 2;
|
|
if (utab[mid].high < wc)
|
|
min = mid + 1;
|
|
else if (wc < utab[mid].low)
|
|
max = mid - 1;
|
|
else if (utab[mid].low <= wc && wc <= utab[mid].high)
|
|
return utab[mid].bit;
|
|
else
|
|
break;
|
|
}
|
|
/* Fallback... returning -1 might cause problems. Returning
|
|
* U_BASIC_LATIN won't help handling strange characters, but won't
|
|
* do harm either.
|
|
*/
|
|
return U_BASIC_LATIN;
|
|
}
|
|
|
|
void
|
|
_gdk_wchar_text_handle (GdkFont *font,
|
|
const wchar_t *wcstr,
|
|
int wclen,
|
|
void (*handler)(GdkWin32SingleFont *,
|
|
const wchar_t *,
|
|
int,
|
|
void *),
|
|
void *arg)
|
|
{
|
|
GdkFontPrivateWin32 *private;
|
|
GdkWin32SingleFont *singlefont;
|
|
GSList *list;
|
|
int block;
|
|
const wchar_t *start, *end, *wcp;
|
|
|
|
wcp = wcstr;
|
|
end = wcp + wclen;
|
|
private = (GdkFontPrivateWin32 *) font;
|
|
|
|
g_assert (private->base.ref_count > 0);
|
|
|
|
GDK_NOTE (MISC, g_print ("_gdk_wchar_text_handle: "));
|
|
|
|
while (wcp < end)
|
|
{
|
|
/* Split Unicode string into pieces of the same class */
|
|
start = wcp;
|
|
block = unicode_classify (*wcp);
|
|
while (wcp + 1 < end && unicode_classify (wcp[1]) == block)
|
|
wcp++;
|
|
|
|
/* Find a font in the fontset that can handle this class */
|
|
list = private->fonts;
|
|
while (list)
|
|
{
|
|
singlefont = (GdkWin32SingleFont *) list->data;
|
|
|
|
if (singlefont->fs.fsUsb[block/32] & (1 << (block % 32)))
|
|
break;
|
|
|
|
list = list->next;
|
|
}
|
|
|
|
if (!list)
|
|
singlefont = NULL;
|
|
|
|
GDK_NOTE (MISC, g_print ("%d:%d:%d:%#x ",
|
|
start-wcstr, wcp-wcstr, block,
|
|
(singlefont ? (guint) singlefont->hfont : 0)));
|
|
|
|
/* Call the callback function */
|
|
(*handler) (singlefont, start, wcp+1 - start, arg);
|
|
wcp++;
|
|
}
|
|
GDK_NOTE (MISC, g_print ("\n"));
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
SIZE total;
|
|
} gdk_text_size_arg;
|
|
|
|
static void
|
|
gdk_text_size_handler (GdkWin32SingleFont *singlefont,
|
|
const wchar_t *wcstr,
|
|
int wclen,
|
|
void *argp)
|
|
{
|
|
SIZE this_size;
|
|
HGDIOBJ oldfont;
|
|
gdk_text_size_arg *arg = (gdk_text_size_arg *) argp;
|
|
|
|
if (!singlefont)
|
|
return;
|
|
|
|
if ((oldfont = SelectObject (gdk_display_hdc, singlefont->hfont)) == NULL)
|
|
{
|
|
WIN32_GDI_FAILED ("SelectObject");
|
|
return;
|
|
}
|
|
GetTextExtentPoint32W (gdk_display_hdc, wcstr, wclen, &this_size);
|
|
SelectObject (gdk_display_hdc, oldfont);
|
|
|
|
arg->total.cx += this_size.cx;
|
|
arg->total.cy = MAX (arg->total.cy, this_size.cy);
|
|
}
|
|
|
|
static gboolean
|
|
gdk_text_size (GdkFont *font,
|
|
const gchar *text,
|
|
gint text_length,
|
|
gdk_text_size_arg *arg)
|
|
{
|
|
gint wlen;
|
|
wchar_t *wcstr;
|
|
|
|
g_return_val_if_fail (font != NULL, FALSE);
|
|
g_return_val_if_fail (text != NULL, FALSE);
|
|
|
|
if (text_length == 0)
|
|
return 0;
|
|
|
|
g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
|
|
|
|
wcstr = g_new (wchar_t, text_length);
|
|
if (text_length == 1)
|
|
{
|
|
/* For single characters, don't try to interpret as UTF-8.
|
|
*/
|
|
wcstr[0] = (guchar) text[0];
|
|
_gdk_wchar_text_handle (font, wcstr, 1, gdk_text_size_handler, arg);
|
|
}
|
|
else
|
|
{
|
|
if ((wlen = _gdk_win32_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
|
|
g_warning ("gdk_text_size: _gdk_win32_nmbstowchar_ts failed");
|
|
else
|
|
_gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, arg);
|
|
}
|
|
|
|
g_free (wcstr);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gint
|
|
gdk_text_width (GdkFont *font,
|
|
const gchar *text,
|
|
gint text_length)
|
|
{
|
|
gdk_text_size_arg arg;
|
|
|
|
arg.total.cx = arg.total.cy = 0;
|
|
|
|
if (!gdk_text_size (font, text, text_length, &arg))
|
|
return -1;
|
|
|
|
return arg.total.cx;
|
|
}
|
|
|
|
gint
|
|
gdk_text_width_wc (GdkFont *font,
|
|
const GdkWChar *text,
|
|
gint text_length)
|
|
{
|
|
gdk_text_size_arg arg;
|
|
wchar_t *wcstr;
|
|
gint i;
|
|
|
|
g_return_val_if_fail (font != NULL, -1);
|
|
g_return_val_if_fail (text != NULL, -1);
|
|
|
|
if (text_length == 0)
|
|
return 0;
|
|
|
|
g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
|
|
|
|
if (sizeof (wchar_t) != sizeof (GdkWChar))
|
|
{
|
|
wcstr = g_new (wchar_t, text_length);
|
|
for (i = 0; i < text_length; i++)
|
|
wcstr[i] = text[i];
|
|
}
|
|
else
|
|
wcstr = (wchar_t *) text;
|
|
|
|
arg.total.cx = arg.total.cy = 0;
|
|
|
|
_gdk_wchar_text_handle (font, wcstr, text_length,
|
|
gdk_text_size_handler, &arg);
|
|
|
|
if (sizeof (wchar_t) != sizeof (GdkWChar))
|
|
g_free (wcstr);
|
|
|
|
return arg.total.cx;
|
|
}
|
|
|
|
void
|
|
gdk_text_extents (GdkFont *font,
|
|
const gchar *text,
|
|
gint text_length,
|
|
gint *lbearing,
|
|
gint *rbearing,
|
|
gint *width,
|
|
gint *ascent,
|
|
gint *descent)
|
|
{
|
|
gdk_text_size_arg arg;
|
|
gint wlen;
|
|
wchar_t *wcstr;
|
|
|
|
g_return_if_fail (font != NULL);
|
|
g_return_if_fail (text != NULL);
|
|
|
|
if (text_length == 0)
|
|
{
|
|
if (lbearing)
|
|
*lbearing = 0;
|
|
if (rbearing)
|
|
*rbearing = 0;
|
|
if (width)
|
|
*width = 0;
|
|
if (ascent)
|
|
*ascent = 0;
|
|
if (descent)
|
|
*descent = 0;
|
|
return;
|
|
}
|
|
|
|
g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
|
|
|
|
arg.total.cx = arg.total.cy = 0;
|
|
|
|
wcstr = g_new (wchar_t, text_length);
|
|
if (text_length == 1)
|
|
{
|
|
wcstr[0] = (guchar) text[0];
|
|
_gdk_wchar_text_handle (font, wcstr, 1, gdk_text_size_handler, &arg);
|
|
}
|
|
else
|
|
{
|
|
if ((wlen = _gdk_win32_nmbstowchar_ts (wcstr, text, text_length, text_length)) == -1)
|
|
g_warning ("gdk_text_extents: _gdk_win32_nmbstowchar_ts failed");
|
|
else
|
|
_gdk_wchar_text_handle (font, wcstr, wlen, gdk_text_size_handler, &arg);
|
|
}
|
|
|
|
g_free (wcstr);
|
|
|
|
/* XXX This is quite bogus */
|
|
if (lbearing)
|
|
*lbearing = 0;
|
|
if (rbearing)
|
|
*rbearing = arg.total.cx;
|
|
/* What should be the difference between width and rbearing? */
|
|
if (width)
|
|
*width = arg.total.cx;
|
|
if (ascent)
|
|
*ascent = arg.total.cy + 1;
|
|
if (descent)
|
|
*descent = font->descent + 1;
|
|
}
|
|
|
|
void
|
|
gdk_text_extents_wc (GdkFont *font,
|
|
const GdkWChar *text,
|
|
gint text_length,
|
|
gint *lbearing,
|
|
gint *rbearing,
|
|
gint *width,
|
|
gint *ascent,
|
|
gint *descent)
|
|
{
|
|
gdk_text_size_arg arg;
|
|
wchar_t *wcstr;
|
|
gint i;
|
|
|
|
g_return_if_fail (font != NULL);
|
|
g_return_if_fail (text != NULL);
|
|
|
|
if (text_length == 0)
|
|
{
|
|
if (lbearing)
|
|
*lbearing = 0;
|
|
if (rbearing)
|
|
*rbearing = 0;
|
|
if (width)
|
|
*width = 0;
|
|
if (ascent)
|
|
*ascent = 0;
|
|
if (descent)
|
|
*descent = 0;
|
|
return;
|
|
}
|
|
|
|
g_assert (font->type == GDK_FONT_FONT || font->type == GDK_FONT_FONTSET);
|
|
|
|
if (sizeof (wchar_t) != sizeof (GdkWChar))
|
|
{
|
|
wcstr = g_new (wchar_t, text_length);
|
|
for (i = 0; i < text_length; i++)
|
|
wcstr[i] = text[i];
|
|
}
|
|
else
|
|
wcstr = (wchar_t *) text;
|
|
|
|
arg.total.cx = arg.total.cy = 0;
|
|
|
|
_gdk_wchar_text_handle (font, wcstr, text_length,
|
|
gdk_text_size_handler, &arg);
|
|
|
|
if (sizeof (wchar_t) != sizeof (GdkWChar))
|
|
g_free (wcstr);
|
|
|
|
/* XXX This is quite bogus */
|
|
if (lbearing)
|
|
*lbearing = 0;
|
|
if (rbearing)
|
|
*rbearing = arg.total.cx;
|
|
if (width)
|
|
*width = arg.total.cx;
|
|
if (ascent)
|
|
*ascent = arg.total.cy + 1;
|
|
if (descent)
|
|
*descent = font->descent + 1;
|
|
}
|