From f3a77d3c00c095a53f37aa7efb39d56168799596 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Wed, 6 Jan 2010 16:32:59 +0000 Subject: Port to core buildsystem. The python module (and associated make runes) need some love (as does non-GCC building with the core buildsystem in general) svn path=/trunk/rufl/; revision=9792 --- src/Glyphs | 1406 ++++++++++++++++++++++++++++++++++ src/Makefile | 12 + src/rufl_character_set_test.c | 37 + src/rufl_decompose.c | 161 ++++ src/rufl_dump_state.c | 138 ++++ src/rufl_find.c | 201 +++++ src/rufl_init.c | 1678 +++++++++++++++++++++++++++++++++++++++++ src/rufl_internal.h | 194 +++++ src/rufl_invalidate_cache.c | 28 + src/rufl_metrics.c | 312 ++++++++ src/rufl_paint.c | 621 +++++++++++++++ src/rufl_quit.c | 49 ++ src/strfuncs.c | 37 + src/strfuncs.h | 5 + 14 files changed, 4879 insertions(+) create mode 100644 src/Glyphs create mode 100644 src/Makefile create mode 100644 src/rufl_character_set_test.c create mode 100644 src/rufl_decompose.c create mode 100644 src/rufl_dump_state.c create mode 100644 src/rufl_find.c create mode 100644 src/rufl_init.c create mode 100644 src/rufl_internal.h create mode 100644 src/rufl_invalidate_cache.c create mode 100644 src/rufl_metrics.c create mode 100644 src/rufl_paint.c create mode 100644 src/rufl_quit.c create mode 100644 src/strfuncs.c create mode 100644 src/strfuncs.h (limited to 'src') diff --git a/src/Glyphs b/src/Glyphs new file mode 100644 index 0000000..d39fa0a --- /dev/null +++ b/src/Glyphs @@ -0,0 +1,1406 @@ +# +# Name: Adobe Glyph List +# Table version: 1.2 +# Date: 22 Oct 1998 +# +# Description: +# +# The Adobe Glyph List (AGL) list relates Unicode values (UVs) to glyph +# names, and should be used only as described in the document "Unicode and +# Glyph Names," at +# http://www.adobe.com/supportservice/devrelations/typeforum/unicodegn.html . +# +# The glyph name to UV relation is one to many. 12 glyph names are mapped to +# two UVs each; each UV has a separate entry. All other glyph names are +# mapped to one UV each. +# +# The Unicode Standard version 2.1 is used for all UVs outside of the Private +# Use area, except for 4 entries (see Revision History for 1.2 below). +# +# There are 1051 entries in this list, 171 of which are in the Corporate Use +# subarea (CUS). Refer to the document "Unicode Corporate Use Subarea as used +# by Adobe Systems," at +# http://www.adobe.com/supportservice/devrelations/typeforum/corporateuse.txt +# for compatibility decompositions for these characters, and to the document +# "Unicode and Glyph Names" for more information the CUS. +# +# Format: Semicolon-delimited fields: +# +# (1) Standard UV or CUS UV. (4 uppercase hexadecimal digits) +# +# (2) Glyph name. (upper- and lowercase letters, digits) +# +# (3) Character names: Unicode character names for standard UVs, and +# descriptive names for CUS UVs. (uppercase letters, hyphen, space) +# +# (4) [optional] Comment. A comment of "Duplicate" indicates one of two +# UVs of a double-mapping. It is the UV that may be given a uni +# override, or the UV that is in the CUS, as described in the document +# "Unicode and Glyph Names." +# +# The entries are sorted by glyph name in increasing ASCII order; entries +# with the same glyph name are sorted in decreasing priority order. +# +# Lines starting with "#" are comments; blank lines should be ignored. +# +# Revision History: +# +# 1.2 [22 Oct 1998] +# +# Some Central European glyph names were remapped and the glyph "dotlessj" +# was added. Some entries in the table below have not changed but are +# included to provide a complete context for other glyphs that have been +# remapped or double-mapped. "-" means that the entry for that UV does not +# exist in the AGL. +# +# -------- ---------------------- ---------------- -------------- +# UV Character name AGL 1.1 AGL 1.2 +# (shortened) glyph name glyph name +# -------- ---------------------- ---------------- -------------- +# 015E/F S/s with cedilla S/scommaaccent S/scedilla +# 0162/3 T/t with cedilla T/tcommaaccent T/tcommaaccent +# 0218/9 S/s with comma below - S/scommaaccent +# 021A/B T/t with comma below - T/tcommaaccent +# 1E9E/F S/s with comma below S/scedilla - +# F6C1/2 S/s with cedilla S/scedilla S/scedilla +# F6BE dotless j - dotlessj +# -------- ---------------------- ---------------- -------------- +# +# The characters at U+1E9E/F in AGL 1.1, LATIN CAPITAL/SMALL LETTER S WITH +# COMMA BELOW, which are proposed new characters (see (b) in the notes for +# AGL 1.1 below), have since been reassigned by the Unicode Standard to new +# proposed values of U+0218/9. These characters, as well as U+021A/B, LATIN +# CAPITAL/SMALL LETTER T WITH COMMA BELOW, are not in the Unicode Standard +# 2.1. +# +# Entries with the same glyph name are now sorted in decreasing priority +# order instead of in increasing UV order. +# +# 1.1 [24 Nov 1997] +# +# a. The "Euro" glyph's UV assignment is changed from U+20A0 (EURO-CURRENCY +# SIGN) to U+20AC (EURO SIGN). While U+20AC is not defined in the +# Unicode Standard 2.0, it has been accepted by the Unicode Technical +# Committee for the next version of the Standard; it has not yet passed +# the ISO approval process as of 7 November '97. +# +# b. Glyphs "Scedilla" and "scedilla", which were assigned in the Corporate +# Use Subarea in AGL 1.0, are now additionally mapped to U+1E9E and +# U+1E9F respectively. These two UVs share the same Unicode approval +# status as the Euro glyph (see a. above). +# +# c. The "fraction" glyph is now additionally mapped to U+2215, to match +# Windows Glyph List 4. +# +# d. The descriptive name for glyph "onefitted", in the Corporate Use +# subarea, is changed from "TABULAR DIGIT ONE" to "PROPORTIONAL DIGIT +# ONE". +# +# 1.0 [17 Jul 1997] Original version +# +0041;A;LATIN CAPITAL LETTER A +00C6;AE;LATIN CAPITAL LETTER AE +01FC;AEacute;LATIN CAPITAL LETTER AE WITH ACUTE +F7E6;AEsmall;LATIN SMALL CAPITAL LETTER AE +00C1;Aacute;LATIN CAPITAL LETTER A WITH ACUTE +F7E1;Aacutesmall;LATIN SMALL CAPITAL LETTER A WITH ACUTE +0102;Abreve;LATIN CAPITAL LETTER A WITH BREVE +00C2;Acircumflex;LATIN CAPITAL LETTER A WITH CIRCUMFLEX +F7E2;Acircumflexsmall;LATIN SMALL CAPITAL LETTER A WITH CIRCUMFLEX +F6C9;Acute;CAPITAL ACUTE ACCENT +F7B4;Acutesmall;SMALL CAPITAL ACUTE ACCENT +00C4;Adieresis;LATIN CAPITAL LETTER A WITH DIAERESIS +F7E4;Adieresissmall;LATIN SMALL CAPITAL LETTER A WITH DIAERESIS +00C0;Agrave;LATIN CAPITAL LETTER A WITH GRAVE +F7E0;Agravesmall;LATIN SMALL CAPITAL LETTER A WITH GRAVE +0391;Alpha;GREEK CAPITAL LETTER ALPHA +0386;Alphatonos;GREEK CAPITAL LETTER ALPHA WITH TONOS +0100;Amacron;LATIN CAPITAL LETTER A WITH MACRON +0104;Aogonek;LATIN CAPITAL LETTER A WITH OGONEK +00C5;Aring;LATIN CAPITAL LETTER A WITH RING ABOVE +01FA;Aringacute;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +F7E5;Aringsmall;LATIN SMALL CAPITAL LETTER A WITH RING ABOVE +F761;Asmall;LATIN SMALL CAPITAL LETTER A +00C3;Atilde;LATIN CAPITAL LETTER A WITH TILDE +F7E3;Atildesmall;LATIN SMALL CAPITAL LETTER A WITH TILDE +0042;B;LATIN CAPITAL LETTER B +0392;Beta;GREEK CAPITAL LETTER BETA +F6F4;Brevesmall;SMALL CAPITAL BREVE +F762;Bsmall;LATIN SMALL CAPITAL LETTER B +0043;C;LATIN CAPITAL LETTER C +0106;Cacute;LATIN CAPITAL LETTER C WITH ACUTE +F6CA;Caron;CAPITAL CARON +F6F5;Caronsmall;SMALL CAPITAL CARON +010C;Ccaron;LATIN CAPITAL LETTER C WITH CARON +00C7;Ccedilla;LATIN CAPITAL LETTER C WITH CEDILLA +F7E7;Ccedillasmall;LATIN SMALL CAPITAL LETTER C WITH CEDILLA +0108;Ccircumflex;LATIN CAPITAL LETTER C WITH CIRCUMFLEX +010A;Cdotaccent;LATIN CAPITAL LETTER C WITH DOT ABOVE +F7B8;Cedillasmall;SMALL CAPITAL CEDILLA +03A7;Chi;GREEK CAPITAL LETTER CHI +F6F6;Circumflexsmall;SMALL CAPITAL MODIFIER LETTER CIRCUMFLEX ACCENT +F763;Csmall;LATIN SMALL CAPITAL LETTER C +0044;D;LATIN CAPITAL LETTER D +010E;Dcaron;LATIN CAPITAL LETTER D WITH CARON +0110;Dcroat;LATIN CAPITAL LETTER D WITH STROKE +2206;Delta;INCREMENT +0394;Delta;GREEK CAPITAL LETTER DELTA;Duplicate +F6CB;Dieresis;CAPITAL DIAERESIS +F6CC;DieresisAcute;CAPITAL DIAERESIS ACUTE ACCENT +F6CD;DieresisGrave;CAPITAL DIAERESIS GRAVE ACCENT +F7A8;Dieresissmall;SMALL CAPITAL DIAERESIS +F6F7;Dotaccentsmall;SMALL CAPITAL DOT ABOVE +F764;Dsmall;LATIN SMALL CAPITAL LETTER D +0045;E;LATIN CAPITAL LETTER E +00C9;Eacute;LATIN CAPITAL LETTER E WITH ACUTE +F7E9;Eacutesmall;LATIN SMALL CAPITAL LETTER E WITH ACUTE +0114;Ebreve;LATIN CAPITAL LETTER E WITH BREVE +011A;Ecaron;LATIN CAPITAL LETTER E WITH CARON +00CA;Ecircumflex;LATIN CAPITAL LETTER E WITH CIRCUMFLEX +F7EA;Ecircumflexsmall;LATIN SMALL CAPITAL LETTER E WITH CIRCUMFLEX +00CB;Edieresis;LATIN CAPITAL LETTER E WITH DIAERESIS +F7EB;Edieresissmall;LATIN SMALL CAPITAL LETTER E WITH DIAERESIS +0116;Edotaccent;LATIN CAPITAL LETTER E WITH DOT ABOVE +00C8;Egrave;LATIN CAPITAL LETTER E WITH GRAVE +F7E8;Egravesmall;LATIN SMALL CAPITAL LETTER E WITH GRAVE +0112;Emacron;LATIN CAPITAL LETTER E WITH MACRON +014A;Eng;LATIN CAPITAL LETTER ENG +0118;Eogonek;LATIN CAPITAL LETTER E WITH OGONEK +0395;Epsilon;GREEK CAPITAL LETTER EPSILON +0388;Epsilontonos;GREEK CAPITAL LETTER EPSILON WITH TONOS +F765;Esmall;LATIN SMALL CAPITAL LETTER E +0397;Eta;GREEK CAPITAL LETTER ETA +0389;Etatonos;GREEK CAPITAL LETTER ETA WITH TONOS +00D0;Eth;LATIN CAPITAL LETTER ETH +F7F0;Ethsmall;LATIN SMALL CAPITAL LETTER ETH +20AC;Euro;EURO SIGN +0046;F;LATIN CAPITAL LETTER F +F766;Fsmall;LATIN SMALL CAPITAL LETTER F +0047;G;LATIN CAPITAL LETTER G +0393;Gamma;GREEK CAPITAL LETTER GAMMA +011E;Gbreve;LATIN CAPITAL LETTER G WITH BREVE +01E6;Gcaron;LATIN CAPITAL LETTER G WITH CARON +011C;Gcircumflex;LATIN CAPITAL LETTER G WITH CIRCUMFLEX +0122;Gcommaaccent;LATIN CAPITAL LETTER G WITH CEDILLA +0120;Gdotaccent;LATIN CAPITAL LETTER G WITH DOT ABOVE +F6CE;Grave;CAPITAL GRAVE ACCENT +F760;Gravesmall;SMALL CAPITAL GRAVE ACCENT +F767;Gsmall;LATIN SMALL CAPITAL LETTER G +0048;H;LATIN CAPITAL LETTER H +25CF;H18533;BLACK CIRCLE +25AA;H18543;BLACK SMALL SQUARE +25AB;H18551;WHITE SMALL SQUARE +25A1;H22073;WHITE SQUARE +0126;Hbar;LATIN CAPITAL LETTER H WITH STROKE +0124;Hcircumflex;LATIN CAPITAL LETTER H WITH CIRCUMFLEX +F768;Hsmall;LATIN SMALL CAPITAL LETTER H +F6CF;Hungarumlaut;CAPITAL DOUBLE ACUTE ACCENT +F6F8;Hungarumlautsmall;SMALL CAPITAL DOUBLE ACUTE ACCENT +0049;I;LATIN CAPITAL LETTER I +0132;IJ;LATIN CAPITAL LIGATURE IJ +00CD;Iacute;LATIN CAPITAL LETTER I WITH ACUTE +F7ED;Iacutesmall;LATIN SMALL CAPITAL LETTER I WITH ACUTE +012C;Ibreve;LATIN CAPITAL LETTER I WITH BREVE +00CE;Icircumflex;LATIN CAPITAL LETTER I WITH CIRCUMFLEX +F7EE;Icircumflexsmall;LATIN SMALL CAPITAL LETTER I WITH CIRCUMFLEX +00CF;Idieresis;LATIN CAPITAL LETTER I WITH DIAERESIS +F7EF;Idieresissmall;LATIN SMALL CAPITAL LETTER I WITH DIAERESIS +0130;Idotaccent;LATIN CAPITAL LETTER I WITH DOT ABOVE +2111;Ifraktur;BLACK-LETTER CAPITAL I +00CC;Igrave;LATIN CAPITAL LETTER I WITH GRAVE +F7EC;Igravesmall;LATIN SMALL CAPITAL LETTER I WITH GRAVE +012A;Imacron;LATIN CAPITAL LETTER I WITH MACRON +012E;Iogonek;LATIN CAPITAL LETTER I WITH OGONEK +0399;Iota;GREEK CAPITAL LETTER IOTA +03AA;Iotadieresis;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +038A;Iotatonos;GREEK CAPITAL LETTER IOTA WITH TONOS +F769;Ismall;LATIN SMALL CAPITAL LETTER I +0128;Itilde;LATIN CAPITAL LETTER I WITH TILDE +004A;J;LATIN CAPITAL LETTER J +0134;Jcircumflex;LATIN CAPITAL LETTER J WITH CIRCUMFLEX +F76A;Jsmall;LATIN SMALL CAPITAL LETTER J +004B;K;LATIN CAPITAL LETTER K +039A;Kappa;GREEK CAPITAL LETTER KAPPA +0136;Kcommaaccent;LATIN CAPITAL LETTER K WITH CEDILLA +F76B;Ksmall;LATIN SMALL CAPITAL LETTER K +004C;L;LATIN CAPITAL LETTER L +F6BF;LL;LATIN CAPITAL LETTER LL +0139;Lacute;LATIN CAPITAL LETTER L WITH ACUTE +039B;Lambda;GREEK CAPITAL LETTER LAMDA +013D;Lcaron;LATIN CAPITAL LETTER L WITH CARON +013B;Lcommaaccent;LATIN CAPITAL LETTER L WITH CEDILLA +013F;Ldot;LATIN CAPITAL LETTER L WITH MIDDLE DOT +0141;Lslash;LATIN CAPITAL LETTER L WITH STROKE +F6F9;Lslashsmall;LATIN SMALL CAPITAL LETTER L WITH STROKE +F76C;Lsmall;LATIN SMALL CAPITAL LETTER L +004D;M;LATIN CAPITAL LETTER M +F6D0;Macron;CAPITAL MACRON +F7AF;Macronsmall;SMALL CAPITAL MACRON +F76D;Msmall;LATIN SMALL CAPITAL LETTER M +039C;Mu;GREEK CAPITAL LETTER MU +004E;N;LATIN CAPITAL LETTER N +0143;Nacute;LATIN CAPITAL LETTER N WITH ACUTE +0147;Ncaron;LATIN CAPITAL LETTER N WITH CARON +0145;Ncommaaccent;LATIN CAPITAL LETTER N WITH CEDILLA +F76E;Nsmall;LATIN SMALL CAPITAL LETTER N +00D1;Ntilde;LATIN CAPITAL LETTER N WITH TILDE +F7F1;Ntildesmall;LATIN SMALL CAPITAL LETTER N WITH TILDE +039D;Nu;GREEK CAPITAL LETTER NU +004F;O;LATIN CAPITAL LETTER O +0152;OE;LATIN CAPITAL LIGATURE OE +F6FA;OEsmall;LATIN SMALL CAPITAL LIGATURE OE +00D3;Oacute;LATIN CAPITAL LETTER O WITH ACUTE +F7F3;Oacutesmall;LATIN SMALL CAPITAL LETTER O WITH ACUTE +014E;Obreve;LATIN CAPITAL LETTER O WITH BREVE +00D4;Ocircumflex;LATIN CAPITAL LETTER O WITH CIRCUMFLEX +F7F4;Ocircumflexsmall;LATIN SMALL CAPITAL LETTER O WITH CIRCUMFLEX +00D6;Odieresis;LATIN CAPITAL LETTER O WITH DIAERESIS +F7F6;Odieresissmall;LATIN SMALL CAPITAL LETTER O WITH DIAERESIS +F6FB;Ogoneksmall;SMALL CAPITAL OGONEK +00D2;Ograve;LATIN CAPITAL LETTER O WITH GRAVE +F7F2;Ogravesmall;LATIN SMALL CAPITAL LETTER O WITH GRAVE +01A0;Ohorn;LATIN CAPITAL LETTER O WITH HORN +0150;Ohungarumlaut;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +014C;Omacron;LATIN CAPITAL LETTER O WITH MACRON +2126;Omega;OHM SIGN +03A9;Omega;GREEK CAPITAL LETTER OMEGA;Duplicate +038F;Omegatonos;GREEK CAPITAL LETTER OMEGA WITH TONOS +039F;Omicron;GREEK CAPITAL LETTER OMICRON +038C;Omicrontonos;GREEK CAPITAL LETTER OMICRON WITH TONOS +00D8;Oslash;LATIN CAPITAL LETTER O WITH STROKE +01FE;Oslashacute;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +F7F8;Oslashsmall;LATIN SMALL CAPITAL LETTER O WITH STROKE +F76F;Osmall;LATIN SMALL CAPITAL LETTER O +00D5;Otilde;LATIN CAPITAL LETTER O WITH TILDE +F7F5;Otildesmall;LATIN SMALL CAPITAL LETTER O WITH TILDE +0050;P;LATIN CAPITAL LETTER P +03A6;Phi;GREEK CAPITAL LETTER PHI +03A0;Pi;GREEK CAPITAL LETTER PI +03A8;Psi;GREEK CAPITAL LETTER PSI +F770;Psmall;LATIN SMALL CAPITAL LETTER P +0051;Q;LATIN CAPITAL LETTER Q +F771;Qsmall;LATIN SMALL CAPITAL LETTER Q +0052;R;LATIN CAPITAL LETTER R +0154;Racute;LATIN CAPITAL LETTER R WITH ACUTE +0158;Rcaron;LATIN CAPITAL LETTER R WITH CARON +0156;Rcommaaccent;LATIN CAPITAL LETTER R WITH CEDILLA +211C;Rfraktur;BLACK-LETTER CAPITAL R +03A1;Rho;GREEK CAPITAL LETTER RHO +F6FC;Ringsmall;SMALL CAPITAL RING ABOVE +F772;Rsmall;LATIN SMALL CAPITAL LETTER R +0053;S;LATIN CAPITAL LETTER S +250C;SF010000;BOX DRAWINGS LIGHT DOWN AND RIGHT +2514;SF020000;BOX DRAWINGS LIGHT UP AND RIGHT +2510;SF030000;BOX DRAWINGS LIGHT DOWN AND LEFT +2518;SF040000;BOX DRAWINGS LIGHT UP AND LEFT +253C;SF050000;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL +252C;SF060000;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL +2534;SF070000;BOX DRAWINGS LIGHT UP AND HORIZONTAL +251C;SF080000;BOX DRAWINGS LIGHT VERTICAL AND RIGHT +2524;SF090000;BOX DRAWINGS LIGHT VERTICAL AND LEFT +2500;SF100000;BOX DRAWINGS LIGHT HORIZONTAL +2502;SF110000;BOX DRAWINGS LIGHT VERTICAL +2561;SF190000;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE +2562;SF200000;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE +2556;SF210000;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE +2555;SF220000;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE +2563;SF230000;BOX DRAWINGS DOUBLE VERTICAL AND LEFT +2551;SF240000;BOX DRAWINGS DOUBLE VERTICAL +2557;SF250000;BOX DRAWINGS DOUBLE DOWN AND LEFT +255D;SF260000;BOX DRAWINGS DOUBLE UP AND LEFT +255C;SF270000;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE +255B;SF280000;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE +255E;SF360000;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE +255F;SF370000;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE +255A;SF380000;BOX DRAWINGS DOUBLE UP AND RIGHT +2554;SF390000;BOX DRAWINGS DOUBLE DOWN AND RIGHT +2569;SF400000;BOX DRAWINGS DOUBLE UP AND HORIZONTAL +2566;SF410000;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL +2560;SF420000;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT +2550;SF430000;BOX DRAWINGS DOUBLE HORIZONTAL +256C;SF440000;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL +2567;SF450000;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE +2568;SF460000;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE +2564;SF470000;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE +2565;SF480000;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE +2559;SF490000;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE +2558;SF500000;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE +2552;SF510000;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE +2553;SF520000;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE +256B;SF530000;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE +256A;SF540000;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE +015A;Sacute;LATIN CAPITAL LETTER S WITH ACUTE +0160;Scaron;LATIN CAPITAL LETTER S WITH CARON +F6FD;Scaronsmall;LATIN SMALL CAPITAL LETTER S WITH CARON +015E;Scedilla;LATIN CAPITAL LETTER S WITH CEDILLA +F6C1;Scedilla;LATIN CAPITAL LETTER S WITH CEDILLA;Duplicate +015C;Scircumflex;LATIN CAPITAL LETTER S WITH CIRCUMFLEX +0218;Scommaaccent;LATIN CAPITAL LETTER S WITH COMMA BELOW +03A3;Sigma;GREEK CAPITAL LETTER SIGMA +F773;Ssmall;LATIN SMALL CAPITAL LETTER S +0054;T;LATIN CAPITAL LETTER T +03A4;Tau;GREEK CAPITAL LETTER TAU +0166;Tbar;LATIN CAPITAL LETTER T WITH STROKE +0164;Tcaron;LATIN CAPITAL LETTER T WITH CARON +0162;Tcommaaccent;LATIN CAPITAL LETTER T WITH CEDILLA +021A;Tcommaaccent;LATIN CAPITAL LETTER T WITH COMMA BELOW;Duplicate +0398;Theta;GREEK CAPITAL LETTER THETA +00DE;Thorn;LATIN CAPITAL LETTER THORN +F7FE;Thornsmall;LATIN SMALL CAPITAL LETTER THORN +F6FE;Tildesmall;SMALL CAPITAL SMALL TILDE +F774;Tsmall;LATIN SMALL CAPITAL LETTER T +0055;U;LATIN CAPITAL LETTER U +00DA;Uacute;LATIN CAPITAL LETTER U WITH ACUTE +F7FA;Uacutesmall;LATIN SMALL CAPITAL LETTER U WITH ACUTE +016C;Ubreve;LATIN CAPITAL LETTER U WITH BREVE +00DB;Ucircumflex;LATIN CAPITAL LETTER U WITH CIRCUMFLEX +F7FB;Ucircumflexsmall;LATIN SMALL CAPITAL LETTER U WITH CIRCUMFLEX +00DC;Udieresis;LATIN CAPITAL LETTER U WITH DIAERESIS +F7FC;Udieresissmall;LATIN SMALL CAPITAL LETTER U WITH DIAERESIS +00D9;Ugrave;LATIN CAPITAL LETTER U WITH GRAVE +F7F9;Ugravesmall;LATIN SMALL CAPITAL LETTER U WITH GRAVE +01AF;Uhorn;LATIN CAPITAL LETTER U WITH HORN +0170;Uhungarumlaut;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +016A;Umacron;LATIN CAPITAL LETTER U WITH MACRON +0172;Uogonek;LATIN CAPITAL LETTER U WITH OGONEK +03A5;Upsilon;GREEK CAPITAL LETTER UPSILON +03D2;Upsilon1;GREEK UPSILON WITH HOOK SYMBOL +03AB;Upsilondieresis;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +038E;Upsilontonos;GREEK CAPITAL LETTER UPSILON WITH TONOS +016E;Uring;LATIN CAPITAL LETTER U WITH RING ABOVE +F775;Usmall;LATIN SMALL CAPITAL LETTER U +0168;Utilde;LATIN CAPITAL LETTER U WITH TILDE +0056;V;LATIN CAPITAL LETTER V +F776;Vsmall;LATIN SMALL CAPITAL LETTER V +0057;W;LATIN CAPITAL LETTER W +1E82;Wacute;LATIN CAPITAL LETTER W WITH ACUTE +0174;Wcircumflex;LATIN CAPITAL LETTER W WITH CIRCUMFLEX +1E84;Wdieresis;LATIN CAPITAL LETTER W WITH DIAERESIS +1E80;Wgrave;LATIN CAPITAL LETTER W WITH GRAVE +F777;Wsmall;LATIN SMALL CAPITAL LETTER W +0058;X;LATIN CAPITAL LETTER X +039E;Xi;GREEK CAPITAL LETTER XI +F778;Xsmall;LATIN SMALL CAPITAL LETTER X +0059;Y;LATIN CAPITAL LETTER Y +00DD;Yacute;LATIN CAPITAL LETTER Y WITH ACUTE +F7FD;Yacutesmall;LATIN SMALL CAPITAL LETTER Y WITH ACUTE +0176;Ycircumflex;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0178;Ydieresis;LATIN CAPITAL LETTER Y WITH DIAERESIS +F7FF;Ydieresissmall;LATIN SMALL CAPITAL LETTER Y WITH DIAERESIS +1EF2;Ygrave;LATIN CAPITAL LETTER Y WITH GRAVE +F779;Ysmall;LATIN SMALL CAPITAL LETTER Y +005A;Z;LATIN CAPITAL LETTER Z +0179;Zacute;LATIN CAPITAL LETTER Z WITH ACUTE +017D;Zcaron;LATIN CAPITAL LETTER Z WITH CARON +F6FF;Zcaronsmall;LATIN SMALL CAPITAL LETTER Z WITH CARON +017B;Zdotaccent;LATIN CAPITAL LETTER Z WITH DOT ABOVE +0396;Zeta;GREEK CAPITAL LETTER ZETA +F77A;Zsmall;LATIN SMALL CAPITAL LETTER Z +0061;a;LATIN SMALL LETTER A +00E1;aacute;LATIN SMALL LETTER A WITH ACUTE +0103;abreve;LATIN SMALL LETTER A WITH BREVE +00E2;acircumflex;LATIN SMALL LETTER A WITH CIRCUMFLEX +00B4;acute;ACUTE ACCENT +0301;acutecomb;COMBINING ACUTE ACCENT +00E4;adieresis;LATIN SMALL LETTER A WITH DIAERESIS +00E6;ae;LATIN SMALL LETTER AE +01FD;aeacute;LATIN SMALL LETTER AE WITH ACUTE +2015;afii00208;HORIZONTAL BAR +0410;afii10017;CYRILLIC CAPITAL LETTER A +0411;afii10018;CYRILLIC CAPITAL LETTER BE +0412;afii10019;CYRILLIC CAPITAL LETTER VE +0413;afii10020;CYRILLIC CAPITAL LETTER GHE +0414;afii10021;CYRILLIC CAPITAL LETTER DE +0415;afii10022;CYRILLIC CAPITAL LETTER IE +0401;afii10023;CYRILLIC CAPITAL LETTER IO +0416;afii10024;CYRILLIC CAPITAL LETTER ZHE +0417;afii10025;CYRILLIC CAPITAL LETTER ZE +0418;afii10026;CYRILLIC CAPITAL LETTER I +0419;afii10027;CYRILLIC CAPITAL LETTER SHORT I +041A;afii10028;CYRILLIC CAPITAL LETTER KA +041B;afii10029;CYRILLIC CAPITAL LETTER EL +041C;afii10030;CYRILLIC CAPITAL LETTER EM +041D;afii10031;CYRILLIC CAPITAL LETTER EN +041E;afii10032;CYRILLIC CAPITAL LETTER O +041F;afii10033;CYRILLIC CAPITAL LETTER PE +0420;afii10034;CYRILLIC CAPITAL LETTER ER +0421;afii10035;CYRILLIC CAPITAL LETTER ES +0422;afii10036;CYRILLIC CAPITAL LETTER TE +0423;afii10037;CYRILLIC CAPITAL LETTER U +0424;afii10038;CYRILLIC CAPITAL LETTER EF +0425;afii10039;CYRILLIC CAPITAL LETTER HA +0426;afii10040;CYRILLIC CAPITAL LETTER TSE +0427;afii10041;CYRILLIC CAPITAL LETTER CHE +0428;afii10042;CYRILLIC CAPITAL LETTER SHA +0429;afii10043;CYRILLIC CAPITAL LETTER SHCHA +042A;afii10044;CYRILLIC CAPITAL LETTER HARD SIGN +042B;afii10045;CYRILLIC CAPITAL LETTER YERU +042C;afii10046;CYRILLIC CAPITAL LETTER SOFT SIGN +042D;afii10047;CYRILLIC CAPITAL LETTER E +042E;afii10048;CYRILLIC CAPITAL LETTER YU +042F;afii10049;CYRILLIC CAPITAL LETTER YA +0490;afii10050;CYRILLIC CAPITAL LETTER GHE WITH UPTURN +0402;afii10051;CYRILLIC CAPITAL LETTER DJE +0403;afii10052;CYRILLIC CAPITAL LETTER GJE +0404;afii10053;CYRILLIC CAPITAL LETTER UKRAINIAN IE +0405;afii10054;CYRILLIC CAPITAL LETTER DZE +0406;afii10055;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0407;afii10056;CYRILLIC CAPITAL LETTER YI +0408;afii10057;CYRILLIC CAPITAL LETTER JE +0409;afii10058;CYRILLIC CAPITAL LETTER LJE +040A;afii10059;CYRILLIC CAPITAL LETTER NJE +040B;afii10060;CYRILLIC CAPITAL LETTER TSHE +040C;afii10061;CYRILLIC CAPITAL LETTER KJE +040E;afii10062;CYRILLIC CAPITAL LETTER SHORT U +F6C4;afii10063;CYRILLIC SMALL LETTER GHE VARIANT +F6C5;afii10064;CYRILLIC SMALL LETTER BE VARIANT +0430;afii10065;CYRILLIC SMALL LETTER A +0431;afii10066;CYRILLIC SMALL LETTER BE +0432;afii10067;CYRILLIC SMALL LETTER VE +0433;afii10068;CYRILLIC SMALL LETTER GHE +0434;afii10069;CYRILLIC SMALL LETTER DE +0435;afii10070;CYRILLIC SMALL LETTER IE +0451;afii10071;CYRILLIC SMALL LETTER IO +0436;afii10072;CYRILLIC SMALL LETTER ZHE +0437;afii10073;CYRILLIC SMALL LETTER ZE +0438;afii10074;CYRILLIC SMALL LETTER I +0439;afii10075;CYRILLIC SMALL LETTER SHORT I +043A;afii10076;CYRILLIC SMALL LETTER KA +043B;afii10077;CYRILLIC SMALL LETTER EL +043C;afii10078;CYRILLIC SMALL LETTER EM +043D;afii10079;CYRILLIC SMALL LETTER EN +043E;afii10080;CYRILLIC SMALL LETTER O +043F;afii10081;CYRILLIC SMALL LETTER PE +0440;afii10082;CYRILLIC SMALL LETTER ER +0441;afii10083;CYRILLIC SMALL LETTER ES +0442;afii10084;CYRILLIC SMALL LETTER TE +0443;afii10085;CYRILLIC SMALL LETTER U +0444;afii10086;CYRILLIC SMALL LETTER EF +0445;afii10087;CYRILLIC SMALL LETTER HA +0446;afii10088;CYRILLIC SMALL LETTER TSE +0447;afii10089;CYRILLIC SMALL LETTER CHE +0448;afii10090;CYRILLIC SMALL LETTER SHA +0449;afii10091;CYRILLIC SMALL LETTER SHCHA +044A;afii10092;CYRILLIC SMALL LETTER HARD SIGN +044B;afii10093;CYRILLIC SMALL LETTER YERU +044C;afii10094;CYRILLIC SMALL LETTER SOFT SIGN +044D;afii10095;CYRILLIC SMALL LETTER E +044E;afii10096;CYRILLIC SMALL LETTER YU +044F;afii10097;CYRILLIC SMALL LETTER YA +0491;afii10098;CYRILLIC SMALL LETTER GHE WITH UPTURN +0452;afii10099;CYRILLIC SMALL LETTER DJE +0453;afii10100;CYRILLIC SMALL LETTER GJE +0454;afii10101;CYRILLIC SMALL LETTER UKRAINIAN IE +0455;afii10102;CYRILLIC SMALL LETTER DZE +0456;afii10103;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +0457;afii10104;CYRILLIC SMALL LETTER YI +0458;afii10105;CYRILLIC SMALL LETTER JE +0459;afii10106;CYRILLIC SMALL LETTER LJE +045A;afii10107;CYRILLIC SMALL LETTER NJE +045B;afii10108;CYRILLIC SMALL LETTER TSHE +045C;afii10109;CYRILLIC SMALL LETTER KJE +045E;afii10110;CYRILLIC SMALL LETTER SHORT U +040F;afii10145;CYRILLIC CAPITAL LETTER DZHE +0462;afii10146;CYRILLIC CAPITAL LETTER YAT +0472;afii10147;CYRILLIC CAPITAL LETTER FITA +0474;afii10148;CYRILLIC CAPITAL LETTER IZHITSA +F6C6;afii10192;CYRILLIC SMALL LETTER DE VARIANT +045F;afii10193;CYRILLIC SMALL LETTER DZHE +0463;afii10194;CYRILLIC SMALL LETTER YAT +0473;afii10195;CYRILLIC SMALL LETTER FITA +0475;afii10196;CYRILLIC SMALL LETTER IZHITSA +F6C7;afii10831;CYRILLIC SMALL LETTER PE VARIANT +F6C8;afii10832;CYRILLIC SMALL LETTER TE VARIANT +04D9;afii10846;CYRILLIC SMALL LETTER SCHWA +200E;afii299;LEFT-TO-RIGHT MARK +200F;afii300;RIGHT-TO-LEFT MARK +200D;afii301;ZERO WIDTH JOINER +066A;afii57381;ARABIC PERCENT SIGN +060C;afii57388;ARABIC COMMA +0660;afii57392;ARABIC-INDIC DIGIT ZERO +0661;afii57393;ARABIC-INDIC DIGIT ONE +0662;afii57394;ARABIC-INDIC DIGIT TWO +0663;afii57395;ARABIC-INDIC DIGIT THREE +0664;afii57396;ARABIC-INDIC DIGIT FOUR +0665;afii57397;ARABIC-INDIC DIGIT FIVE +0666;afii57398;ARABIC-INDIC DIGIT SIX +0667;afii57399;ARABIC-INDIC DIGIT SEVEN +0668;afii57400;ARABIC-INDIC DIGIT EIGHT +0669;afii57401;ARABIC-INDIC DIGIT NINE +061B;afii57403;ARABIC SEMICOLON +061F;afii57407;ARABIC QUESTION MARK +0621;afii57409;ARABIC LETTER HAMZA +0622;afii57410;ARABIC LETTER ALEF WITH MADDA ABOVE +0623;afii57411;ARABIC LETTER ALEF WITH HAMZA ABOVE +0624;afii57412;ARABIC LETTER WAW WITH HAMZA ABOVE +0625;afii57413;ARABIC LETTER ALEF WITH HAMZA BELOW +0626;afii57414;ARABIC LETTER YEH WITH HAMZA ABOVE +0627;afii57415;ARABIC LETTER ALEF +0628;afii57416;ARABIC LETTER BEH +0629;afii57417;ARABIC LETTER TEH MARBUTA +062A;afii57418;ARABIC LETTER TEH +062B;afii57419;ARABIC LETTER THEH +062C;afii57420;ARABIC LETTER JEEM +062D;afii57421;ARABIC LETTER HAH +062E;afii57422;ARABIC LETTER KHAH +062F;afii57423;ARABIC LETTER DAL +0630;afii57424;ARABIC LETTER THAL +0631;afii57425;ARABIC LETTER REH +0632;afii57426;ARABIC LETTER ZAIN +0633;afii57427;ARABIC LETTER SEEN +0634;afii57428;ARABIC LETTER SHEEN +0635;afii57429;ARABIC LETTER SAD +0636;afii57430;ARABIC LETTER DAD +0637;afii57431;ARABIC LETTER TAH +0638;afii57432;ARABIC LETTER ZAH +0639;afii57433;ARABIC LETTER AIN +063A;afii57434;ARABIC LETTER GHAIN +0640;afii57440;ARABIC TATWEEL +0641;afii57441;ARABIC LETTER FEH +0642;afii57442;ARABIC LETTER QAF +0643;afii57443;ARABIC LETTER KAF +0644;afii57444;ARABIC LETTER LAM +0645;afii57445;ARABIC LETTER MEEM +0646;afii57446;ARABIC LETTER NOON +0648;afii57448;ARABIC LETTER WAW +0649;afii57449;ARABIC LETTER ALEF MAKSURA +064A;afii57450;ARABIC LETTER YEH +064B;afii57451;ARABIC FATHATAN +064C;afii57452;ARABIC DAMMATAN +064D;afii57453;ARABIC KASRATAN +064E;afii57454;ARABIC FATHA +064F;afii57455;ARABIC DAMMA +0650;afii57456;ARABIC KASRA +0651;afii57457;ARABIC SHADDA +0652;afii57458;ARABIC SUKUN +0647;afii57470;ARABIC LETTER HEH +06A4;afii57505;ARABIC LETTER VEH +067E;afii57506;ARABIC LETTER PEH +0686;afii57507;ARABIC LETTER TCHEH +0698;afii57508;ARABIC LETTER JEH +06AF;afii57509;ARABIC LETTER GAF +0679;afii57511;ARABIC LETTER TTEH +0688;afii57512;ARABIC LETTER DDAL +0691;afii57513;ARABIC LETTER RREH +06BA;afii57514;ARABIC LETTER NOON GHUNNA +06D2;afii57519;ARABIC LETTER YEH BARREE +06D5;afii57534;ARABIC LETTER AE +20AA;afii57636;NEW SHEQEL SIGN +05BE;afii57645;HEBREW PUNCTUATION MAQAF +05C3;afii57658;HEBREW PUNCTUATION SOF PASUQ +05D0;afii57664;HEBREW LETTER ALEF +05D1;afii57665;HEBREW LETTER BET +05D2;afii57666;HEBREW LETTER GIMEL +05D3;afii57667;HEBREW LETTER DALET +05D4;afii57668;HEBREW LETTER HE +05D5;afii57669;HEBREW LETTER VAV +05D6;afii57670;HEBREW LETTER ZAYIN +05D7;afii57671;HEBREW LETTER HET +05D8;afii57672;HEBREW LETTER TET +05D9;afii57673;HEBREW LETTER YOD +05DA;afii57674;HEBREW LETTER FINAL KAF +05DB;afii57675;HEBREW LETTER KAF +05DC;afii57676;HEBREW LETTER LAMED +05DD;afii57677;HEBREW LETTER FINAL MEM +05DE;afii57678;HEBREW LETTER MEM +05DF;afii57679;HEBREW LETTER FINAL NUN +05E0;afii57680;HEBREW LETTER NUN +05E1;afii57681;HEBREW LETTER SAMEKH +05E2;afii57682;HEBREW LETTER AYIN +05E3;afii57683;HEBREW LETTER FINAL PE +05E4;afii57684;HEBREW LETTER PE +05E5;afii57685;HEBREW LETTER FINAL TSADI +05E6;afii57686;HEBREW LETTER TSADI +05E7;afii57687;HEBREW LETTER QOF +05E8;afii57688;HEBREW LETTER RESH +05E9;afii57689;HEBREW LETTER SHIN +05EA;afii57690;HEBREW LETTER TAV +FB2A;afii57694;HEBREW LETTER SHIN WITH SHIN DOT +FB2B;afii57695;HEBREW LETTER SHIN WITH SIN DOT +FB4B;afii57700;HEBREW LETTER VAV WITH HOLAM +FB1F;afii57705;HEBREW LIGATURE YIDDISH YOD YOD PATAH +05F0;afii57716;HEBREW LIGATURE YIDDISH DOUBLE VAV +05F1;afii57717;HEBREW LIGATURE YIDDISH VAV YOD +05F2;afii57718;HEBREW LIGATURE YIDDISH DOUBLE YOD +FB35;afii57723;HEBREW LETTER VAV WITH DAGESH +05B4;afii57793;HEBREW POINT HIRIQ +05B5;afii57794;HEBREW POINT TSERE +05B6;afii57795;HEBREW POINT SEGOL +05BB;afii57796;HEBREW POINT QUBUTS +05B8;afii57797;HEBREW POINT QAMATS +05B7;afii57798;HEBREW POINT PATAH +05B0;afii57799;HEBREW POINT SHEVA +05B2;afii57800;HEBREW POINT HATAF PATAH +05B1;afii57801;HEBREW POINT HATAF SEGOL +05B3;afii57802;HEBREW POINT HATAF QAMATS +05C2;afii57803;HEBREW POINT SIN DOT +05C1;afii57804;HEBREW POINT SHIN DOT +05B9;afii57806;HEBREW POINT HOLAM +05BC;afii57807;HEBREW POINT DAGESH OR MAPIQ +05BD;afii57839;HEBREW POINT METEG +05BF;afii57841;HEBREW POINT RAFE +05C0;afii57842;HEBREW PUNCTUATION PASEQ +02BC;afii57929;MODIFIER LETTER APOSTROPHE +2105;afii61248;CARE OF +2113;afii61289;SCRIPT SMALL L +2116;afii61352;NUMERO SIGN +202C;afii61573;POP DIRECTIONAL FORMATTING +202D;afii61574;LEFT-TO-RIGHT OVERRIDE +202E;afii61575;RIGHT-TO-LEFT OVERRIDE +200C;afii61664;ZERO WIDTH NON-JOINER +066D;afii63167;ARABIC FIVE POINTED STAR +02BD;afii64937;MODIFIER LETTER REVERSED COMMA +00E0;agrave;LATIN SMALL LETTER A WITH GRAVE +2135;aleph;ALEF SYMBOL +03B1;alpha;GREEK SMALL LETTER ALPHA +03AC;alphatonos;GREEK SMALL LETTER ALPHA WITH TONOS +0101;amacron;LATIN SMALL LETTER A WITH MACRON +0026;ampersand;AMPERSAND +F726;ampersandsmall;SMALL CAPITAL AMPERSAND +2220;angle;ANGLE +2329;angleleft;LEFT-POINTING ANGLE BRACKET +232A;angleright;RIGHT-POINTING ANGLE BRACKET +0387;anoteleia;GREEK ANO TELEIA +0105;aogonek;LATIN SMALL LETTER A WITH OGONEK +2248;approxequal;ALMOST EQUAL TO +00E5;aring;LATIN SMALL LETTER A WITH RING ABOVE +01FB;aringacute;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE +2194;arrowboth;LEFT RIGHT ARROW +21D4;arrowdblboth;LEFT RIGHT DOUBLE ARROW +21D3;arrowdbldown;DOWNWARDS DOUBLE ARROW +21D0;arrowdblleft;LEFTWARDS DOUBLE ARROW +21D2;arrowdblright;RIGHTWARDS DOUBLE ARROW +21D1;arrowdblup;UPWARDS DOUBLE ARROW +2193;arrowdown;DOWNWARDS ARROW +F8E7;arrowhorizex;HORIZONTAL ARROW EXTENDER +2190;arrowleft;LEFTWARDS ARROW +2192;arrowright;RIGHTWARDS ARROW +2191;arrowup;UPWARDS ARROW +2195;arrowupdn;UP DOWN ARROW +21A8;arrowupdnbse;UP DOWN ARROW WITH BASE +F8E6;arrowvertex;VERTICAL ARROW EXTENDER +005E;asciicircum;CIRCUMFLEX ACCENT +007E;asciitilde;TILDE +002A;asterisk;ASTERISK +2217;asteriskmath;ASTERISK OPERATOR +F6E9;asuperior;SUPERSCRIPT LATIN SMALL LETTER A +0040;at;COMMERCIAL AT +00E3;atilde;LATIN SMALL LETTER A WITH TILDE +0062;b;LATIN SMALL LETTER B +005C;backslash;REVERSE SOLIDUS +007C;bar;VERTICAL LINE +03B2;beta;GREEK SMALL LETTER BETA +2588;block;FULL BLOCK +F8F4;braceex;CURLY BRACKET EXTENDER +007B;braceleft;LEFT CURLY BRACKET +F8F3;braceleftbt;LEFT CURLY BRACKET BOTTOM +F8F2;braceleftmid;LEFT CURLY BRACKET MID +F8F1;bracelefttp;LEFT CURLY BRACKET TOP +007D;braceright;RIGHT CURLY BRACKET +F8FE;bracerightbt;RIGHT CURLY BRACKET BOTTOM +F8FD;bracerightmid;RIGHT CURLY BRACKET MID +F8FC;bracerighttp;RIGHT CURLY BRACKET TOP +005B;bracketleft;LEFT SQUARE BRACKET +F8F0;bracketleftbt;LEFT SQUARE BRACKET BOTTOM +F8EF;bracketleftex;LEFT SQUARE BRACKET EXTENDER +F8EE;bracketlefttp;LEFT SQUARE BRACKET TOP +005D;bracketright;RIGHT SQUARE BRACKET +F8FB;bracketrightbt;RIGHT SQUARE BRACKET BOTTOM +F8FA;bracketrightex;RIGHT SQUARE BRACKET EXTENDER +F8F9;bracketrighttp;RIGHT SQUARE BRACKET TOP +02D8;breve;BREVE +00A6;brokenbar;BROKEN BAR +F6EA;bsuperior;SUPERSCRIPT LATIN SMALL LETTER B +2022;bullet;BULLET +0063;c;LATIN SMALL LETTER C +0107;cacute;LATIN SMALL LETTER C WITH ACUTE +02C7;caron;CARON +21B5;carriagereturn;DOWNWARDS ARROW WITH CORNER LEFTWARDS +010D;ccaron;LATIN SMALL LETTER C WITH CARON +00E7;ccedilla;LATIN SMALL LETTER C WITH CEDILLA +0109;ccircumflex;LATIN SMALL LETTER C WITH CIRCUMFLEX +010B;cdotaccent;LATIN SMALL LETTER C WITH DOT ABOVE +00B8;cedilla;CEDILLA +00A2;cent;CENT SIGN +F6DF;centinferior;SUBSCRIPT CENT SIGN +F7A2;centoldstyle;OLDSTYLE CENT SIGN +F6E0;centsuperior;SUPERSCRIPT CENT SIGN +03C7;chi;GREEK SMALL LETTER CHI +25CB;circle;WHITE CIRCLE +2297;circlemultiply;CIRCLED TIMES +2295;circleplus;CIRCLED PLUS +02C6;circumflex;MODIFIER LETTER CIRCUMFLEX ACCENT +2663;club;BLACK CLUB SUIT +003A;colon;COLON +20A1;colonmonetary;COLON SIGN +002C;comma;COMMA +F6C3;commaaccent;COMMA BELOW +F6E1;commainferior;SUBSCRIPT COMMA +F6E2;commasuperior;SUPERSCRIPT COMMA +2245;congruent;APPROXIMATELY EQUAL TO +00A9;copyright;COPYRIGHT SIGN +F8E9;copyrightsans;COPYRIGHT SIGN SANS SERIF +F6D9;copyrightserif;COPYRIGHT SIGN SERIF +00A4;currency;CURRENCY SIGN +F6D1;cyrBreve;CAPITAL CYRILLIC BREVE +F6D2;cyrFlex;CAPITAL CYRILLIC CIRCUMFLEX +F6D4;cyrbreve;CYRILLIC BREVE +F6D5;cyrflex;CYRILLIC CIRCUMFLEX +0064;d;LATIN SMALL LETTER D +2020;dagger;DAGGER +2021;daggerdbl;DOUBLE DAGGER +F6D3;dblGrave;CAPITAL DOUBLE GRAVE ACCENT +F6D6;dblgrave;DOUBLE GRAVE ACCENT +010F;dcaron;LATIN SMALL LETTER D WITH CARON +0111;dcroat;LATIN SMALL LETTER D WITH STROKE +00B0;degree;DEGREE SIGN +03B4;delta;GREEK SMALL LETTER DELTA +2666;diamond;BLACK DIAMOND SUIT +00A8;dieresis;DIAERESIS +F6D7;dieresisacute;DIAERESIS ACUTE ACCENT +F6D8;dieresisgrave;DIAERESIS GRAVE ACCENT +0385;dieresistonos;GREEK DIALYTIKA TONOS +00F7;divide;DIVISION SIGN +2593;dkshade;DARK SHADE +2584;dnblock;LOWER HALF BLOCK +0024;dollar;DOLLAR SIGN +F6E3;dollarinferior;SUBSCRIPT DOLLAR SIGN +F724;dollaroldstyle;OLDSTYLE DOLLAR SIGN +F6E4;dollarsuperior;SUPERSCRIPT DOLLAR SIGN +20AB;dong;DONG SIGN +02D9;dotaccent;DOT ABOVE +0323;dotbelowcomb;COMBINING DOT BELOW +0131;dotlessi;LATIN SMALL LETTER DOTLESS I +F6BE;dotlessj;LATIN SMALL LETTER DOTLESS J +22C5;dotmath;DOT OPERATOR +F6EB;dsuperior;SUPERSCRIPT LATIN SMALL LETTER D +0065;e;LATIN SMALL LETTER E +00E9;eacute;LATIN SMALL LETTER E WITH ACUTE +0115;ebreve;LATIN SMALL LETTER E WITH BREVE +011B;ecaron;LATIN SMALL LETTER E WITH CARON +00EA;ecircumflex;LATIN SMALL LETTER E WITH CIRCUMFLEX +00EB;edieresis;LATIN SMALL LETTER E WITH DIAERESIS +0117;edotaccent;LATIN SMALL LETTER E WITH DOT ABOVE +00E8;egrave;LATIN SMALL LETTER E WITH GRAVE +0038;eight;DIGIT EIGHT +2088;eightinferior;SUBSCRIPT EIGHT +F738;eightoldstyle;OLDSTYLE DIGIT EIGHT +2078;eightsuperior;SUPERSCRIPT EIGHT +2208;element;ELEMENT OF +2026;ellipsis;HORIZONTAL ELLIPSIS +0113;emacron;LATIN SMALL LETTER E WITH MACRON +2014;emdash;EM DASH +2205;emptyset;EMPTY SET +2013;endash;EN DASH +014B;eng;LATIN SMALL LETTER ENG +0119;eogonek;LATIN SMALL LETTER E WITH OGONEK +03B5;epsilon;GREEK SMALL LETTER EPSILON +03AD;epsilontonos;GREEK SMALL LETTER EPSILON WITH TONOS +003D;equal;EQUALS SIGN +2261;equivalence;IDENTICAL TO +212E;estimated;ESTIMATED SYMBOL +F6EC;esuperior;SUPERSCRIPT LATIN SMALL LETTER E +03B7;eta;GREEK SMALL LETTER ETA +03AE;etatonos;GREEK SMALL LETTER ETA WITH TONOS +00F0;eth;LATIN SMALL LETTER ETH +0021;exclam;EXCLAMATION MARK +203C;exclamdbl;DOUBLE EXCLAMATION MARK +00A1;exclamdown;INVERTED EXCLAMATION MARK +F7A1;exclamdownsmall;SMALL CAPITAL INVERTED EXCLAMATION MARK +F721;exclamsmall;SMALL CAPITAL EXCLAMATION MARK +2203;existential;THERE EXISTS +0066;f;LATIN SMALL LETTER F +2640;female;FEMALE SIGN +FB00;ff;LATIN SMALL LIGATURE FF +FB03;ffi;LATIN SMALL LIGATURE FFI +FB04;ffl;LATIN SMALL LIGATURE FFL +FB01;fi;LATIN SMALL LIGATURE FI +2012;figuredash;FIGURE DASH +25A0;filledbox;BLACK SQUARE +25AC;filledrect;BLACK RECTANGLE +0035;five;DIGIT FIVE +215D;fiveeighths;VULGAR FRACTION FIVE EIGHTHS +2085;fiveinferior;SUBSCRIPT FIVE +F735;fiveoldstyle;OLDSTYLE DIGIT FIVE +2075;fivesuperior;SUPERSCRIPT FIVE +FB02;fl;LATIN SMALL LIGATURE FL +0192;florin;LATIN SMALL LETTER F WITH HOOK +0034;four;DIGIT FOUR +2084;fourinferior;SUBSCRIPT FOUR +F734;fouroldstyle;OLDSTYLE DIGIT FOUR +2074;foursuperior;SUPERSCRIPT FOUR +2044;fraction;FRACTION SLASH +2215;fraction;DIVISION SLASH;Duplicate +20A3;franc;FRENCH FRANC SIGN +0067;g;LATIN SMALL LETTER G +03B3;gamma;GREEK SMALL LETTER GAMMA +011F;gbreve;LATIN SMALL LETTER G WITH BREVE +01E7;gcaron;LATIN SMALL LETTER G WITH CARON +011D;gcircumflex;LATIN SMALL LETTER G WITH CIRCUMFLEX +0123;gcommaaccent;LATIN SMALL LETTER G WITH CEDILLA +0121;gdotaccent;LATIN SMALL LETTER G WITH DOT ABOVE +00DF;germandbls;LATIN SMALL LETTER SHARP S +2207;gradient;NABLA +0060;grave;GRAVE ACCENT +0300;gravecomb;COMBINING GRAVE ACCENT +003E;greater;GREATER-THAN SIGN +2265;greaterequal;GREATER-THAN OR EQUAL TO +00AB;guillemotleft;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00BB;guillemotright;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +2039;guilsinglleft;SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A;guilsinglright;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0068;h;LATIN SMALL LETTER H +0127;hbar;LATIN SMALL LETTER H WITH STROKE +0125;hcircumflex;LATIN SMALL LETTER H WITH CIRCUMFLEX +2665;heart;BLACK HEART SUIT +0309;hookabovecomb;COMBINING HOOK ABOVE +2302;house;HOUSE +02DD;hungarumlaut;DOUBLE ACUTE ACCENT +002D;hyphen;HYPHEN-MINUS +00AD;hyphen;SOFT HYPHEN;Duplicate +F6E5;hypheninferior;SUBSCRIPT HYPHEN-MINUS +F6E6;hyphensuperior;SUPERSCRIPT HYPHEN-MINUS +0069;i;LATIN SMALL LETTER I +00ED;iacute;LATIN SMALL LETTER I WITH ACUTE +012D;ibreve;LATIN SMALL LETTER I WITH BREVE +00EE;icircumflex;LATIN SMALL LETTER I WITH CIRCUMFLEX +00EF;idieresis;LATIN SMALL LETTER I WITH DIAERESIS +00EC;igrave;LATIN SMALL LETTER I WITH GRAVE +0133;ij;LATIN SMALL LIGATURE IJ +012B;imacron;LATIN SMALL LETTER I WITH MACRON +221E;infinity;INFINITY +222B;integral;INTEGRAL +2321;integralbt;BOTTOM HALF INTEGRAL +F8F5;integralex;INTEGRAL EXTENDER +2320;integraltp;TOP HALF INTEGRAL +2229;intersection;INTERSECTION +25D8;invbullet;INVERSE BULLET +25D9;invcircle;INVERSE WHITE CIRCLE +263B;invsmileface;BLACK SMILING FACE +012F;iogonek;LATIN SMALL LETTER I WITH OGONEK +03B9;iota;GREEK SMALL LETTER IOTA +03CA;iotadieresis;GREEK SMALL LETTER IOTA WITH DIALYTIKA +0390;iotadieresistonos;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +03AF;iotatonos;GREEK SMALL LETTER IOTA WITH TONOS +F6ED;isuperior;SUPERSCRIPT LATIN SMALL LETTER I +0129;itilde;LATIN SMALL LETTER I WITH TILDE +006A;j;LATIN SMALL LETTER J +0135;jcircumflex;LATIN SMALL LETTER J WITH CIRCUMFLEX +006B;k;LATIN SMALL LETTER K +03BA;kappa;GREEK SMALL LETTER KAPPA +0137;kcommaaccent;LATIN SMALL LETTER K WITH CEDILLA +0138;kgreenlandic;LATIN SMALL LETTER KRA +006C;l;LATIN SMALL LETTER L +013A;lacute;LATIN SMALL LETTER L WITH ACUTE +03BB;lambda;GREEK SMALL LETTER LAMDA +013E;lcaron;LATIN SMALL LETTER L WITH CARON +013C;lcommaaccent;LATIN SMALL LETTER L WITH CEDILLA +0140;ldot;LATIN SMALL LETTER L WITH MIDDLE DOT +003C;less;LESS-THAN SIGN +2264;lessequal;LESS-THAN OR EQUAL TO +258C;lfblock;LEFT HALF BLOCK +20A4;lira;LIRA SIGN +F6C0;ll;LATIN SMALL LETTER LL +2227;logicaland;LOGICAL AND +00AC;logicalnot;NOT SIGN +2228;logicalor;LOGICAL OR +017F;longs;LATIN SMALL LETTER LONG S +25CA;lozenge;LOZENGE +0142;lslash;LATIN SMALL LETTER L WITH STROKE +F6EE;lsuperior;SUPERSCRIPT LATIN SMALL LETTER L +2591;ltshade;LIGHT SHADE +006D;m;LATIN SMALL LETTER M +00AF;macron;MACRON +02C9;macron;MODIFIER LETTER MACRON;Duplicate +2642;male;MALE SIGN +2212;minus;MINUS SIGN +2032;minute;PRIME +F6EF;msuperior;SUPERSCRIPT LATIN SMALL LETTER M +00B5;mu;MICRO SIGN +03BC;mu;GREEK SMALL LETTER MU;Duplicate +00D7;multiply;MULTIPLICATION SIGN +266A;musicalnote;EIGHTH NOTE +266B;musicalnotedbl;BEAMED EIGHTH NOTES +006E;n;LATIN SMALL LETTER N +0144;nacute;LATIN SMALL LETTER N WITH ACUTE +0149;napostrophe;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +0148;ncaron;LATIN SMALL LETTER N WITH CARON +0146;ncommaaccent;LATIN SMALL LETTER N WITH CEDILLA +0039;nine;DIGIT NINE +2089;nineinferior;SUBSCRIPT NINE +F739;nineoldstyle;OLDSTYLE DIGIT NINE +2079;ninesuperior;SUPERSCRIPT NINE +2209;notelement;NOT AN ELEMENT OF +2260;notequal;NOT EQUAL TO +2284;notsubset;NOT A SUBSET OF +207F;nsuperior;SUPERSCRIPT LATIN SMALL LETTER N +00F1;ntilde;LATIN SMALL LETTER N WITH TILDE +03BD;nu;GREEK SMALL LETTER NU +0023;numbersign;NUMBER SIGN +006F;o;LATIN SMALL LETTER O +00F3;oacute;LATIN SMALL LETTER O WITH ACUTE +014F;obreve;LATIN SMALL LETTER O WITH BREVE +00F4;ocircumflex;LATIN SMALL LETTER O WITH CIRCUMFLEX +00F6;odieresis;LATIN SMALL LETTER O WITH DIAERESIS +0153;oe;LATIN SMALL LIGATURE OE +02DB;ogonek;OGONEK +00F2;ograve;LATIN SMALL LETTER O WITH GRAVE +01A1;ohorn;LATIN SMALL LETTER O WITH HORN +0151;ohungarumlaut;LATIN SMALL LETTER O WITH DOUBLE ACUTE +014D;omacron;LATIN SMALL LETTER O WITH MACRON +03C9;omega;GREEK SMALL LETTER OMEGA +03D6;omega1;GREEK PI SYMBOL +03CE;omegatonos;GREEK SMALL LETTER OMEGA WITH TONOS +03BF;omicron;GREEK SMALL LETTER OMICRON +03CC;omicrontonos;GREEK SMALL LETTER OMICRON WITH TONOS +0031;one;DIGIT ONE +2024;onedotenleader;ONE DOT LEADER +215B;oneeighth;VULGAR FRACTION ONE EIGHTH +F6DC;onefitted;PROPORTIONAL DIGIT ONE +00BD;onehalf;VULGAR FRACTION ONE HALF +2081;oneinferior;SUBSCRIPT ONE +F731;oneoldstyle;OLDSTYLE DIGIT ONE +00BC;onequarter;VULGAR FRACTION ONE QUARTER +00B9;onesuperior;SUPERSCRIPT ONE +2153;onethird;VULGAR FRACTION ONE THIRD +25E6;openbullet;WHITE BULLET +00AA;ordfeminine;FEMININE ORDINAL INDICATOR +00BA;ordmasculine;MASCULINE ORDINAL INDICATOR +221F;orthogonal;RIGHT ANGLE +00F8;oslash;LATIN SMALL LETTER O WITH STROKE +01FF;oslashacute;LATIN SMALL LETTER O WITH STROKE AND ACUTE +F6F0;osuperior;SUPERSCRIPT LATIN SMALL LETTER O +00F5;otilde;LATIN SMALL LETTER O WITH TILDE +0070;p;LATIN SMALL LETTER P +00B6;paragraph;PILCROW SIGN +0028;parenleft;LEFT PARENTHESIS +F8ED;parenleftbt;LEFT PAREN BOTTOM +F8EC;parenleftex;LEFT PAREN EXTENDER +208D;parenleftinferior;SUBSCRIPT LEFT PARENTHESIS +207D;parenleftsuperior;SUPERSCRIPT LEFT PARENTHESIS +F8EB;parenlefttp;LEFT PAREN TOP +0029;parenright;RIGHT PARENTHESIS +F8F8;parenrightbt;RIGHT PAREN BOTTOM +F8F7;parenrightex;RIGHT PAREN EXTENDER +208E;parenrightinferior;SUBSCRIPT RIGHT PARENTHESIS +207E;parenrightsuperior;SUPERSCRIPT RIGHT PARENTHESIS +F8F6;parenrighttp;RIGHT PAREN TOP +2202;partialdiff;PARTIAL DIFFERENTIAL +0025;percent;PERCENT SIGN +002E;period;FULL STOP +00B7;periodcentered;MIDDLE DOT +2219;periodcentered;BULLET OPERATOR;Duplicate +F6E7;periodinferior;SUBSCRIPT FULL STOP +F6E8;periodsuperior;SUPERSCRIPT FULL STOP +22A5;perpendicular;UP TACK +2030;perthousand;PER MILLE SIGN +20A7;peseta;PESETA SIGN +03C6;phi;GREEK SMALL LETTER PHI +03D5;phi1;GREEK PHI SYMBOL +03C0;pi;GREEK SMALL LETTER PI +002B;plus;PLUS SIGN +00B1;plusminus;PLUS-MINUS SIGN +211E;prescription;PRESCRIPTION TAKE +220F;product;N-ARY PRODUCT +2282;propersubset;SUBSET OF +2283;propersuperset;SUPERSET OF +221D;proportional;PROPORTIONAL TO +03C8;psi;GREEK SMALL LETTER PSI +0071;q;LATIN SMALL LETTER Q +003F;question;QUESTION MARK +00BF;questiondown;INVERTED QUESTION MARK +F7BF;questiondownsmall;SMALL CAPITAL INVERTED QUESTION MARK +F73F;questionsmall;SMALL CAPITAL QUESTION MARK +0022;quotedbl;QUOTATION MARK +201E;quotedblbase;DOUBLE LOW-9 QUOTATION MARK +201C;quotedblleft;LEFT DOUBLE QUOTATION MARK +201D;quotedblright;RIGHT DOUBLE QUOTATION MARK +2018;quoteleft;LEFT SINGLE QUOTATION MARK +201B;quotereversed;SINGLE HIGH-REVERSED-9 QUOTATION MARK +2019;quoteright;RIGHT SINGLE QUOTATION MARK +201A;quotesinglbase;SINGLE LOW-9 QUOTATION MARK +0027;quotesingle;APOSTROPHE +0072;r;LATIN SMALL LETTER R +0155;racute;LATIN SMALL LETTER R WITH ACUTE +221A;radical;SQUARE ROOT +F8E5;radicalex;RADICAL EXTENDER +0159;rcaron;LATIN SMALL LETTER R WITH CARON +0157;rcommaaccent;LATIN SMALL LETTER R WITH CEDILLA +2286;reflexsubset;SUBSET OF OR EQUAL TO +2287;reflexsuperset;SUPERSET OF OR EQUAL TO +00AE;registered;REGISTERED SIGN +F8E8;registersans;REGISTERED SIGN SANS SERIF +F6DA;registerserif;REGISTERED SIGN SERIF +2310;revlogicalnot;REVERSED NOT SIGN +03C1;rho;GREEK SMALL LETTER RHO +02DA;ring;RING ABOVE +F6F1;rsuperior;SUPERSCRIPT LATIN SMALL LETTER R +2590;rtblock;RIGHT HALF BLOCK +F6DD;rupiah;RUPIAH SIGN +0073;s;LATIN SMALL LETTER S +015B;sacute;LATIN SMALL LETTER S WITH ACUTE +0161;scaron;LATIN SMALL LETTER S WITH CARON +015F;scedilla;LATIN SMALL LETTER S WITH CEDILLA +F6C2;scedilla;LATIN SMALL LETTER S WITH CEDILLA;Duplicate +015D;scircumflex;LATIN SMALL LETTER S WITH CIRCUMFLEX +0219;scommaaccent;LATIN SMALL LETTER S WITH COMMA BELOW +2033;second;DOUBLE PRIME +00A7;section;SECTION SIGN +003B;semicolon;SEMICOLON +0037;seven;DIGIT SEVEN +215E;seveneighths;VULGAR FRACTION SEVEN EIGHTHS +2087;seveninferior;SUBSCRIPT SEVEN +F737;sevenoldstyle;OLDSTYLE DIGIT SEVEN +2077;sevensuperior;SUPERSCRIPT SEVEN +2592;shade;MEDIUM SHADE +03C3;sigma;GREEK SMALL LETTER SIGMA +03C2;sigma1;GREEK SMALL LETTER FINAL SIGMA +223C;similar;TILDE OPERATOR +0036;six;DIGIT SIX +2086;sixinferior;SUBSCRIPT SIX +F736;sixoldstyle;OLDSTYLE DIGIT SIX +2076;sixsuperior;SUPERSCRIPT SIX +002F;slash;SOLIDUS +263A;smileface;WHITE SMILING FACE +0020;space;SPACE +00A0;space;NO-BREAK SPACE;Duplicate +2660;spade;BLACK SPADE SUIT +F6F2;ssuperior;SUPERSCRIPT LATIN SMALL LETTER S +00A3;sterling;POUND SIGN +220B;suchthat;CONTAINS AS MEMBER +2211;summation;N-ARY SUMMATION +263C;sun;WHITE SUN WITH RAYS +0074;t;LATIN SMALL LETTER T +03C4;tau;GREEK SMALL LETTER TAU +0167;tbar;LATIN SMALL LETTER T WITH STROKE +0165;tcaron;LATIN SMALL LETTER T WITH CARON +0163;tcommaaccent;LATIN SMALL LETTER T WITH CEDILLA +021B;tcommaaccent;LATIN SMALL LETTER T WITH COMMA BELOW;Duplicate +2234;therefore;THEREFORE +03B8;theta;GREEK SMALL LETTER THETA +03D1;theta1;GREEK THETA SYMBOL +00FE;thorn;LATIN SMALL LETTER THORN +0033;three;DIGIT THREE +215C;threeeighths;VULGAR FRACTION THREE EIGHTHS +2083;threeinferior;SUBSCRIPT THREE +F733;threeoldstyle;OLDSTYLE DIGIT THREE +00BE;threequarters;VULGAR FRACTION THREE QUARTERS +F6DE;threequartersemdash;THREE QUARTERS EM DASH +00B3;threesuperior;SUPERSCRIPT THREE +02DC;tilde;SMALL TILDE +0303;tildecomb;COMBINING TILDE +0384;tonos;GREEK TONOS +2122;trademark;TRADE MARK SIGN +F8EA;trademarksans;TRADE MARK SIGN SANS SERIF +F6DB;trademarkserif;TRADE MARK SIGN SERIF +25BC;triagdn;BLACK DOWN-POINTING TRIANGLE +25C4;triaglf;BLACK LEFT-POINTING POINTER +25BA;triagrt;BLACK RIGHT-POINTING POINTER +25B2;triagup;BLACK UP-POINTING TRIANGLE +F6F3;tsuperior;SUPERSCRIPT LATIN SMALL LETTER T +0032;two;DIGIT TWO +2025;twodotenleader;TWO DOT LEADER +2082;twoinferior;SUBSCRIPT TWO +F732;twooldstyle;OLDSTYLE DIGIT TWO +00B2;twosuperior;SUPERSCRIPT TWO +2154;twothirds;VULGAR FRACTION TWO THIRDS +0075;u;LATIN SMALL LETTER U +00FA;uacute;LATIN SMALL LETTER U WITH ACUTE +016D;ubreve;LATIN SMALL LETTER U WITH BREVE +00FB;ucircumflex;LATIN SMALL LETTER U WITH CIRCUMFLEX +00FC;udieresis;LATIN SMALL LETTER U WITH DIAERESIS +00F9;ugrave;LATIN SMALL LETTER U WITH GRAVE +01B0;uhorn;LATIN SMALL LETTER U WITH HORN +0171;uhungarumlaut;LATIN SMALL LETTER U WITH DOUBLE ACUTE +016B;umacron;LATIN SMALL LETTER U WITH MACRON +005F;underscore;LOW LINE +2017;underscoredbl;DOUBLE LOW LINE +222A;union;UNION +2200;universal;FOR ALL +0173;uogonek;LATIN SMALL LETTER U WITH OGONEK +2580;upblock;UPPER HALF BLOCK +03C5;upsilon;GREEK SMALL LETTER UPSILON +03CB;upsilondieresis;GREEK SMALL LETTER UPSILON WITH DIALYTIKA +03B0;upsilondieresistonos;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03CD;upsilontonos;GREEK SMALL LETTER UPSILON WITH TONOS +016F;uring;LATIN SMALL LETTER U WITH RING ABOVE +0169;utilde;LATIN SMALL LETTER U WITH TILDE +0076;v;LATIN SMALL LETTER V +0077;w;LATIN SMALL LETTER W +1E83;wacute;LATIN SMALL LETTER W WITH ACUTE +0175;wcircumflex;LATIN SMALL LETTER W WITH CIRCUMFLEX +1E85;wdieresis;LATIN SMALL LETTER W WITH DIAERESIS +2118;weierstrass;SCRIPT CAPITAL P +1E81;wgrave;LATIN SMALL LETTER W WITH GRAVE +0078;x;LATIN SMALL LETTER X +03BE;xi;GREEK SMALL LETTER XI +0079;y;LATIN SMALL LETTER Y +00FD;yacute;LATIN SMALL LETTER Y WITH ACUTE +0177;ycircumflex;LATIN SMALL LETTER Y WITH CIRCUMFLEX +00FF;ydieresis;LATIN SMALL LETTER Y WITH DIAERESIS +00A5;yen;YEN SIGN +1EF3;ygrave;LATIN SMALL LETTER Y WITH GRAVE +007A;z;LATIN SMALL LETTER Z +017A;zacute;LATIN SMALL LETTER Z WITH ACUTE +017E;zcaron;LATIN SMALL LETTER Z WITH CARON +017C;zdotaccent;LATIN SMALL LETTER Z WITH DOT ABOVE +0030;zero;DIGIT ZERO +2080;zeroinferior;SUBSCRIPT ZERO +F730;zerooldstyle;OLDSTYLE DIGIT ZERO +2070;zerosuperior;SUPERSCRIPT ZERO +03B6;zeta;GREEK SMALL LETTER ZETA + +# +# Name: ITC Zapf Dingbats encoding, Unicode values, and +# glyph names +# Table version: 1.0 +# Date: 17 July 1997 +# +# Version of ITC Zapf Dingbats: +# +# ITC Zapf Dingbats (PostScript FontName: ZapfDingbats) contains 202 +# of the 379 glyphs in PCL Zapf Dingbats. +# +# Versions of ZapfDingbats previous to 002.000 do not encode 14 out of the +# 202 available glyphs in their PostScript encoding (though these 14 glyphs +# can be accessed on the Macintosh due to the FOND's reencoding of the +# glyphs). ZapfDingbats version 002.000 encodes all of the 202 glyphs in its +# PostScript encoding. +# +# Unicode encoding of ZapfDingbats: +# +# The 188 glyphs in the PostScript encoding of versions of ZapfDingbats +# previous to 002.000 have regular Unicode values (160 in the Dingbats block +# and 28 in other blocks). The remaining 14 glyphs have been assigned +# Unicode values in the Corporate Use subarea, and coincide exactly with +# Apple's MacOS Dingbats assignments in that area. +# +# Format: Four tab-separated columns: +# +# (1) The PostScript encoding. (2 uppercase hexadecimal digits) +# 202 code points are defined. +# Source: Adobe Systems. +# +# (2) The Unicode value. (4 uppercase hexadecimal digits) +# The 14 glyphs at code points 0x80-8D have Corporate Use subarea +# values. +# Source: ftp://unicode.org/pub/UNIX/MAPPINGS/VENDORS/APPLE/DINGBAT.TXT +# [as of 25 February 1997] +# +# (3) The glyph name. (upper- and lowercase letters, digits) +# Source: Adobe Systems. +# +# (4) The Unicode 2.0 character name. (uppercase letters, hyphen, space) +# Source: The Unicode Standard, Version 2.0 +# +# The 14 Corporate Use subarea glyphs obviously don't have a +# Unicode 2.0 character name. A descriptive name (in lowercase +# letters) taken from the source for (2) above is used instead. +# +# The entries are in PostScript encoding order. +# +# Lines starting with "#" are comments; blank lines are to be ignored. +# + +0020;space;SPACE +2701;a1;UPPER BLADE SCISSORS +2702;a2;BLACK SCISSORS +2703;a202;LOWER BLADE SCISSORS +2704;a3;WHITE SCISSORS +260E;a4;BLACK TELEPHONE +2706;a5;TELEPHONE LOCATION SIGN +2707;a119;TAPE DRIVE +2708;a118;AIRPLANE +2709;a117;ENVELOPE +261B;a11;BLACK RIGHT POINTING INDEX +261E;a12;WHITE RIGHT POINTING INDEX +270C;a13;VICTORY HAND +270D;a14;WRITING HAND +270E;a15;LOWER RIGHT PENCIL +270F;a16;PENCIL +2710;a105;UPPER RIGHT PENCIL +2711;a17;WHITE NIB +2712;a18;BLACK NIB +2713;a19;CHECK MARK +2714;a20;HEAVY CHECK MARK +2715;a21;MULTIPLICATION X +2716;a22;HEAVY MULTIPLICATION X +2717;a23;BALLOT X +2718;a24;HEAVY BALLOT X +2719;a25;OUTLINED GREEK CROSS +271A;a26;HEAVY GREEK CROSS +271B;a27;OPEN CENTRE CROSS +271C;a28;HEAVY OPEN CENTRE CROSS +271D;a6;LATIN CROSS +271E;a7;SHADOWED WHITE LATIN CROSS +271F;a8;OUTLINED LATIN CROSS +2720;a9;MALTESE CROSS +2721;a10;STAR OF DAVID +2722;a29;FOUR TEARDROP-SPOKED ASTERISK +2723;a30;FOUR BALLOON-SPOKED ASTERISK +2724;a31;HEAVY FOUR BALLOON-SPOKED ASTERISK +2725;a32;FOUR CLUB-SPOKED ASTERISK +2726;a33;BLACK FOUR POINTED STAR +2727;a34;WHITE FOUR POINTED STAR +2605;a35;BLACK STAR +2729;a36;STRESS OUTLINED WHITE STAR +272A;a37;CIRCLED WHITE STAR +272B;a38;OPEN CENTRE BLACK STAR +272C;a39;BLACK CENTRE WHITE STAR +272D;a40;OUTLINED BLACK STAR +272E;a41;HEAVY OUTLINED BLACK STAR +272F;a42;PINWHEEL STAR +2730;a43;SHADOWED WHITE STAR +2731;a44;HEAVY ASTERISK +2732;a45;OPEN CENTRE ASTERISK +2733;a46;EIGHT SPOKED ASTERISK +2734;a47;EIGHT POINTED BLACK STAR +2735;a48;EIGHT POINTED PINWHEEL STAR +2736;a49;SIX POINTED BLACK STAR +2737;a50;EIGHT POINTED RECTILINEAR BLACK STAR +2738;a51;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR +2739;a52;TWELVE POINTED BLACK STAR +273A;a53;SIXTEEN POINTED ASTERISK +273B;a54;TEARDROP-SPOKED ASTERISK +273C;a55;OPEN CENTRE TEARDROP-SPOKED ASTERISK +273D;a56;HEAVY TEARDROP-SPOKED ASTERISK +273E;a57;SIX PETALLED BLACK AND WHITE FLORETTE +273F;a58;BLACK FLORETTE +2740;a59;WHITE FLORETTE +2741;a60;EIGHT PETALLED OUTLINED BLACK FLORETTE +2742;a61;CIRCLED OPEN CENTRE EIGHT POINTED STAR +2743;a62;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK +2744;a63;SNOWFLAKE +2745;a64;TIGHT TRIFOLIATE SNOWFLAKE +2746;a65;HEAVY CHEVRON SNOWFLAKE +2747;a66;SPARKLE +2748;a67;HEAVY SPARKLE +2749;a68;BALLOON-SPOKED ASTERISK +274A;a69;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274B;a70;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +25CF;a71;BLACK CIRCLE +274D;a72;SHADOWED WHITE CIRCLE +25A0;a73;BLACK SQUARE +274F;a74;LOWER RIGHT DROP-SHADOWED WHITE SQUARE +2750;a203;UPPER RIGHT DROP-SHADOWED WHITE SQUARE +2751;a75;LOWER RIGHT SHADOWED WHITE SQUARE +2752;a204;UPPER RIGHT SHADOWED WHITE SQUARE +25B2;a76;BLACK UP-POINTING TRIANGLE +25BC;a77;BLACK DOWN-POINTING TRIANGLE +25C6;a78;BLACK DIAMOND +2756;a79;BLACK DIAMOND MINUS WHITE X +25D7;a81;RIGHT HALF BLACK CIRCLE +2758;a82;LIGHT VERTICAL BAR +2759;a83;MEDIUM VERTICAL BAR +275A;a84;HEAVY VERTICAL BAR +275B;a97;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT +275C;a98;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT +275D;a99;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT +275E;a100;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT +F8D7;a89;MEDIUM LEFT PARENTHESIS ORNAMENT +F8D8;a90;MEDIUM RIGHT PARENTHESIS ORNAMENT +F8D9;a93;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT +F8DA;a94;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT +F8DB;a91;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT +F8DC;a92;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT +F8DD;a205;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT +F8DE;a85;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT +F8DF;a206;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT +F8E0;a86;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT +F8E1;a87;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT +F8E2;a88;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT +F8E3;a95;MEDIUM LEFT CURLY BRACKET ORNAMENT +F8E4;a96;MEDIUM RIGHT CURLY BRACKET ORNAMENT +2761;a101;CURVED STEM PARAGRAPH SIGN ORNAMENT +2762;a102;HEAVY EXCLAMATION MARK ORNAMENT +2763;a103;HEAVY HEART EXCLAMATION MARK ORNAMENT +2764;a104;HEAVY BLACK HEART +2765;a106;ROTATED HEAVY BLACK HEART BULLET +2766;a107;FLORAL HEART +2767;a108;ROTATED FLORAL HEART BULLET +2663;a112;BLACK CLUB SUIT +2666;a111;BLACK DIAMOND SUIT +2665;a110;BLACK HEART SUIT +2660;a109;BLACK SPADE SUIT +2460;a120;CIRCLED DIGIT ONE +2461;a121;CIRCLED DIGIT TWO +2462;a122;CIRCLED DIGIT THREE +2463;a123;CIRCLED DIGIT FOUR +2464;a124;CIRCLED DIGIT FIVE +2465;a125;CIRCLED DIGIT SIX +2466;a126;CIRCLED DIGIT SEVEN +2467;a127;CIRCLED DIGIT EIGHT +2468;a128;CIRCLED DIGIT NINE +2469;a129;CIRCLED NUMBER TEN +2776;a130;DINGBAT NEGATIVE CIRCLED DIGIT ONE +2777;a131;DINGBAT NEGATIVE CIRCLED DIGIT TWO +2778;a132;DINGBAT NEGATIVE CIRCLED DIGIT THREE +2779;a133;DINGBAT NEGATIVE CIRCLED DIGIT FOUR +277A;a134;DINGBAT NEGATIVE CIRCLED DIGIT FIVE +277B;a135;DINGBAT NEGATIVE CIRCLED DIGIT SIX +277C;a136;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN +277D;a137;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT +277E;a138;DINGBAT NEGATIVE CIRCLED DIGIT NINE +277F;a139;DINGBAT NEGATIVE CIRCLED NUMBER TEN +2780;a140;DINGBAT CIRCLED SANS-SERIF DIGIT ONE +2781;a141;DINGBAT CIRCLED SANS-SERIF DIGIT TWO +2782;a142;DINGBAT CIRCLED SANS-SERIF DIGIT THREE +2783;a143;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR +2784;a144;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE +2785;a145;DINGBAT CIRCLED SANS-SERIF DIGIT SIX +2786;a146;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN +2787;a147;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT +2788;a148;DINGBAT CIRCLED SANS-SERIF DIGIT NINE +2789;a149;DINGBAT CIRCLED SANS-SERIF NUMBER TEN +278A;a150;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE +278B;a151;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO +278C;a152;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE +278D;a153;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR +278E;a154;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE +278F;a155;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX +2790;a156;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN +2791;a157;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT +2792;a158;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE +2793;a159;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN +2794;a160;HEAVY WIDE-HEADED RIGHTWARDS ARROW +2192;a161;RIGHTWARDS ARROW +2194;a163;LEFT RIGHT ARROW +2195;a164;UP DOWN ARROW +2798;a196;HEAVY SOUTH EAST ARROW +2799;a165;HEAVY RIGHTWARDS ARROW +279A;a192;HEAVY NORTH EAST ARROW +279B;a166;DRAFTING POINT RIGHTWARDS ARROW +279C;a167;HEAVY ROUND-TIPPED RIGHTWARDS ARROW +279D;a168;TRIANGLE-HEADED RIGHTWARDS ARROW +279E;a169;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW +279F;a170;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW +27A0;a171;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW +27A1;a172;BLACK RIGHTWARDS ARROW +27A2;a173;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD +27A3;a162;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD +27A4;a174;BLACK RIGHTWARDS ARROWHEAD +27A5;a175;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW +27A6;a176;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW +27A7;a177;SQUAT BLACK RIGHTWARDS ARROW +27A8;a178;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW +27A9;a179;RIGHT-SHADED WHITE RIGHTWARDS ARROW +27AA;a193;LEFT-SHADED WHITE RIGHTWARDS ARROW +27AB;a180;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW +27AC;a199;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW +27AD;a181;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27AE;a200;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27AF;a182;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B1;a201;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B2;a183;CIRCLED HEAVY WHITE RIGHTWARDS ARROW +27B3;a184;WHITE-FEATHERED RIGHTWARDS ARROW +27B4;a197;BLACK-FEATHERED SOUTH EAST ARROW +27B5;a185;BLACK-FEATHERED RIGHTWARDS ARROW +27B6;a194;BLACK-FEATHERED NORTH EAST ARROW +27B7;a198;HEAVY BLACK-FEATHERED SOUTH EAST ARROW +27B8;a186;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW +27B9;a195;HEAVY BLACK-FEATHERED NORTH EAST ARROW +27BA;a187;TEARDROP-BARBED RIGHTWARDS ARROW +27BB;a188;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW +27BC;a189;WEDGE-TAILED RIGHTWARDS ARROW +27BD;a190;HEAVY WEDGE-TAILED RIGHTWARDS ARROW +27BE;a191;OPEN-OUTLINED RIGHTWARDS ARROW diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..e8a7509 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,12 @@ +# Sources +DIR_SOURCES := rufl_character_set_test.c rufl_decompose.c rufl_dump_state.c \ + rufl_find.c rufl_init.c rufl_invalidate_cache.c \ + rufl_metrics.c rufl_paint.c rufl_quit.c strfuncs.c + +SOURCES := $(SOURCES) $(BUILDDIR)/rufl_glyph_map.c + +$(BUILDDIR)/rufl_glyph_map.c: src/Glyphs + $(VQ)$(ECHO) "MKGLYPHS: $<" + $(Q)$(PERL) build/tools/makeglyphs < $< > $@ + +include build/makefiles/Makefile.subdir diff --git a/src/rufl_character_set_test.c b/src/rufl_character_set_test.c new file mode 100644 index 0000000..45fbcaf --- /dev/null +++ b/src/rufl_character_set_test.c @@ -0,0 +1,37 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2005 James Bursa + */ + +#include "rufl_internal.h" + + +/** + * Test if a character set contains a character. + * + * \param charset character set + * \param c character code + * \return true if present, false if absent + */ + +bool rufl_character_set_test(struct rufl_character_set *charset, + unsigned int c) +{ + unsigned int block = c >> 8; + unsigned int byte = (c >> 3) & 31; + unsigned int bit = c & 7; + + if (256 <= block) + return false; + + if (charset->index[block] == BLOCK_EMPTY) + return false; + else if (charset->index[block] == BLOCK_FULL) + return true; + else { + unsigned char z = charset->block[charset->index[block]][byte]; + return z & (1 << bit); + } +} diff --git a/src/rufl_decompose.c b/src/rufl_decompose.c new file mode 100644 index 0000000..edf9748 --- /dev/null +++ b/src/rufl_decompose.c @@ -0,0 +1,161 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2005 John-Mark Bell + */ + +#include +#include + +#include "oslib/font.h" + +#include "rufl_internal.h" + +/** + * Process a Draw path object + * + * \param path Pointer to path block + * \param funcs Struct of callback functions + * \param user User pointer to be passed to callbacks + * \return Pointer to word after this path, or NULL to terminate processing + */ +static int *process_path(int *path, struct rufl_decomp_funcs *funcs, + void *user) +{ + /* skip forward to style entry */ + path += 9; + + /* skip dash pattern */ + if (path[0] & (1<<7)) + path += path[2] + 2; + + /* and move to start of path components */ + path++; + + while (path[0] != 0) { + switch (path[0]) { + case 2: /* Move to */ + if (funcs->move_to((os_coord *)(path + 1), user)) + return NULL; + path += 3; + break; + case 5: /* Close path */ + path++; + break; + case 6: /* Cubic Bezier to */ + if (funcs->cubic_to((os_coord *)(path + 1), + (os_coord *)(path + 3), + (os_coord *)(path + 5), + user)) + return NULL; + path += 7; + break; + case 8: /* Line to */ + if (funcs->line_to((os_coord *)(path + 1), user)) + return NULL; + path += 3; + break; + default: /* Anything else is broken */ + assert(0); + } + } + + /* + 1 to account for tag 0 - end of path */ + return path + 1; +} + +rufl_code rufl_decompose_glyph(const char *font_family, + rufl_style font_style, unsigned int font_size, + const char *string, size_t len, + struct rufl_decomp_funcs *funcs, void *user) +{ + int *buf, *p, *ep; + int buf_size; + char *buf_end; + rufl_code err; + + /* Get required buffer size */ + rufl_fm_error = xfont_switch_output_to_buffer( + font_NO_OUTPUT | font_ADD_HINTS, (byte *)8, 0); + if (rufl_fm_error) { + LOG("xfont_switch_output_to_buffer: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + err = rufl_paint(font_family, font_style, font_size, string, len, + 0, 0, rufl_BLEND_FONT); + if (err) { + /* reset font redirection - too bad if this fails */ + xfont_switch_output_to_buffer(0, 0, 0); + return err; + } + + rufl_fm_error = xfont_switch_output_to_buffer(0, NULL, &buf_end); + if (rufl_fm_error) { + LOG("xfont_switch_output_to_buffer: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + buf_size = buf_end - (char *)NULL; + + /* Allocate and initialise buffer */ + buf = malloc(buf_size); + if (!buf) { + LOG("Failed to allocate decompose buffer of size %i", buf_size); + return rufl_OUT_OF_MEMORY; + } + buf[0] = 0; + buf[1] = buf_size - 8; + + /* Populate buffer */ + rufl_fm_error = xfont_switch_output_to_buffer( + font_ADD_HINTS, (byte *)buf, 0); + if (rufl_fm_error) { + LOG("xfont_switch_output_to_buffer: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + free(buf); + return rufl_FONT_MANAGER_ERROR; + } + + err = rufl_paint(font_family, font_style, font_size, string, len, + 0, 0, rufl_BLEND_FONT); + if (err) { + /* reset font redirection - too bad if this fails */ + xfont_switch_output_to_buffer(0, 0, 0); + free(buf); + return err; + } + + rufl_fm_error = xfont_switch_output_to_buffer(0, 0, &buf_end); + if (rufl_fm_error) { + LOG("xfont_switch_output_to_buffer: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + free(buf); + return rufl_FONT_MANAGER_ERROR; + } + ep = (int *)(void *)buf_end; + + /* Parse buffer, calling callbacks as required */ + for (p = buf; p < ep;) { + if (p[0] != 2) { + LOG("Object type %d not known", p[0]); + break; + } + + p = process_path(p, funcs, user); + + /* Have the callbacks asked for us to stop? */ + if (p == NULL) + break; + } + + free(buf); + + return rufl_OK; +} diff --git a/src/rufl_dump_state.c b/src/rufl_dump_state.c new file mode 100644 index 0000000..06a1f22 --- /dev/null +++ b/src/rufl_dump_state.c @@ -0,0 +1,138 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2006 James Bursa + */ + +#include +#include "rufl_internal.h" + + +static void rufl_dump_character_set(struct rufl_character_set *charset); +static void rufl_dump_unicode_map(struct rufl_unicode_map *umap); +static void rufl_dump_substitution_table(void); + + +/** + * Dump the internal library state to stdout. + */ + +void rufl_dump_state(void) +{ + unsigned int i, j; + + printf("rufl_font_list:\n"); + for (i = 0; i != rufl_font_list_entries; i++) { + printf(" %u \"%s\"\n", i, rufl_font_list[i].identifier); + if (rufl_font_list[i].charset) { + printf(" "); + rufl_dump_character_set(rufl_font_list[i].charset); + printf("\n"); + } else { + printf(" (no charset table)\n"); + } + if (rufl_font_list[i].umap) { + for (j = 0; j < rufl_font_list[i].num_umaps; j++) { + struct rufl_unicode_map *map = + rufl_font_list[i].umap + j; + + printf(" "); + rufl_dump_unicode_map(map); + printf("\n"); + } + } + } + + printf("rufl_family_list:\n"); + for (i = 0; i != rufl_family_list_entries; i++) { + printf(" %u \"%s\"\n", i, rufl_family_list[i]); + for (j = 0; j != 9; j++) { + struct rufl_family_map_entry *e = &rufl_family_map[i]; + printf(" %u ", j); + if (e->font[j][0] == NO_FONT) + printf("- "); + else + printf("\"%s\" ", rufl_font_list[e->font[j][0]]. + identifier); + if (e->font[j][1] == NO_FONT) + printf("- "); + else + printf("\"%s\" ", rufl_font_list[e->font[j][1]]. + identifier); + printf("\n"); + } + } + + printf("rufl_substitution_table:\n"); + rufl_dump_substitution_table(); +} + + +/** + * Dump a representation of a character set to stdout. + * + * \param charset character set to print + */ + +void rufl_dump_character_set(struct rufl_character_set *charset) +{ + unsigned int u, t; + + u = 0; + while (u != 0x10000) { + while (u != 0x10000 && !rufl_character_set_test(charset, u)) + u++; + if (u != 0x10000) { + if (!rufl_character_set_test(charset, u + 1)) { + printf("%x ", u); + u++; + } else { + t = u; + while (rufl_character_set_test(charset, u)) + u++; + printf("%x-%x ", t, u - 1); + } + } + } +} + + +/** + * Dump a representation of a unicode map to stdout. + * + * \param umap unicode map to print + */ + +void rufl_dump_unicode_map(struct rufl_unicode_map *umap) +{ + unsigned int i; + + if (umap->encoding) + printf("%s: ", umap->encoding); + + for (i = 0; i != umap->entries; i++) + printf("%x:%x ", umap->map[i].u, umap->map[i].c); +} + + +/** + * Dump a representation of the substitution table to stdout. + */ + +void rufl_dump_substitution_table(void) +{ + unsigned int font; + unsigned int u, t; + + u = 0; + while (u != 0x10000) { + t = u; + font = rufl_substitution_table[t]; + while (u != 0x10000 && font == rufl_substitution_table[u]) + u++; + if (font != NOT_AVAILABLE) + printf(" %x-%x => %u \"%s\"\n", t, u - 1, + font, rufl_font_list[font].identifier); + } +} diff --git a/src/rufl_find.c b/src/rufl_find.c new file mode 100644 index 0000000..a1c2785 --- /dev/null +++ b/src/rufl_find.c @@ -0,0 +1,201 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2005 James Bursa + * Copyright 2005 John-Mark Bell + */ + +#include +#include +#include +#include +#include + +#include "rufl_internal.h" + +static int rufl_family_list_cmp(const void *keyval, const void *datum); +static rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, + const char *encoding, font_f f); + +/** + * Find a font family. + */ +rufl_code rufl_find_font_family(const char *font_family, + rufl_style font_style, unsigned int *font, + unsigned int *slanted, struct rufl_character_set **charset) +{ + const char **family; + unsigned int f; + unsigned int weight, slant, used_weight; + unsigned int search_direction; + + family = bsearch(font_family, rufl_family_list, + rufl_family_list_entries, + sizeof rufl_family_list[0], rufl_family_list_cmp); + if (!family) + return rufl_FONT_NOT_FOUND; + + weight = (font_style & 0xf) - 1; + assert(weight <= 8); + slant = font_style & rufl_SLANTED ? 1 : 0; + + struct rufl_family_map_entry *e = + &rufl_family_map[family - rufl_family_list]; + used_weight = weight; + if (weight <= 2) + search_direction = -1; + else + search_direction = +1; + while (1) { + if (e->font[used_weight][slant] != NO_FONT) { + /* the weight and slant is available */ + f = e->font[used_weight][slant]; + break; + } + if (e->font[used_weight][1 - slant] != NO_FONT) { + /* slanted, and non-slanted weight exists, or vv. */ + f = e->font[used_weight][1 - slant]; + break; + } + if (used_weight == 0) { + /* searched down without finding a weight: search up */ + used_weight = weight + 1; + search_direction = +1; + } else if (used_weight == 8) { + /* searched up without finding a weight: search down */ + used_weight = weight - 1; + search_direction = -1; + } else { + /* try the next weight in the current direction */ + used_weight += search_direction; + } + } + + if (font) + (*font) = f; + + if (slanted) + (*slanted) = slant; + + if (charset) + (*charset) = rufl_font_list[f].charset; + + return rufl_OK; +} + + +/** + * Find a sized font, placing in the cache if necessary. + */ +rufl_code rufl_find_font(unsigned int font, unsigned int font_size, + const char *encoding, font_f *fhandle) +{ + font_f f; + char font_name[80]; + unsigned int i; + rufl_code code; + + assert(fhandle != NULL); + + for (i = 0; i != rufl_CACHE_SIZE; i++) { + /* Comparing pointers for the encoding is fine, as the + * encoding string passed to us is either: + * + * a) NULL + * or b) statically allocated + * or c) resides in the font's umap, which is constant + * for the lifetime of the application. + */ + if (rufl_cache[i].font == font && + rufl_cache[i].size == font_size && + rufl_cache[i].encoding == encoding) + break; + } + if (i != rufl_CACHE_SIZE) { + /* found in cache */ + f = rufl_cache[i].f; + rufl_cache[i].last_used = rufl_cache_time++; + } else { + /* not found */ + if (font == rufl_CACHE_CORPUS) { + if (encoding) + snprintf(font_name, sizeof font_name, + "Corpus.Medium\\E%s", encoding); + else + snprintf(font_name, sizeof font_name, + "Corpus.Medium"); + } else { + if (encoding) + snprintf(font_name, sizeof font_name, + "%s\\E%s", + rufl_font_list[font].identifier, + encoding); + else + snprintf(font_name, sizeof font_name, "%s", + rufl_font_list[font].identifier); + } + + rufl_fm_error = xfont_find_font(font_name, + font_size, font_size, 0, 0, &f, 0, 0); + if (rufl_fm_error) { + LOG("xfont_find_font: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + /* place in cache */ + code = rufl_place_in_cache(font, font_size, encoding, f); + if (code != rufl_OK) + return code; + } + + (*fhandle) = f; + + return rufl_OK; +} + + +int rufl_family_list_cmp(const void *keyval, const void *datum) +{ + const char *key = keyval; + const char * const *entry = datum; + return strcasecmp(key, *entry); +} + + +/** + * Place a font into the recent-use cache, making space if necessary. + */ + +rufl_code rufl_place_in_cache(unsigned int font, unsigned int font_size, + const char *encoding, font_f f) +{ + unsigned int i; + unsigned int max_age = 0; + unsigned int evict = 0; + + for (i = 0; i != rufl_CACHE_SIZE; i++) { + if (rufl_cache[i].font == rufl_CACHE_NONE) { + evict = i; + break; + } else if (max_age < rufl_cache_time - + rufl_cache[i].last_used) { + max_age = rufl_cache_time - + rufl_cache[i].last_used; + evict = i; + } + } + if (rufl_cache[evict].font != rufl_CACHE_NONE) { + rufl_fm_error = xfont_lose_font(rufl_cache[evict].f); + if (rufl_fm_error) + return rufl_FONT_MANAGER_ERROR; + } + rufl_cache[evict].font = font; + rufl_cache[evict].size = font_size; + rufl_cache[evict].encoding = encoding; + rufl_cache[evict].f = f; + rufl_cache[evict].last_used = rufl_cache_time++; + + return rufl_OK; +} diff --git a/src/rufl_init.c b/src/rufl_init.c new file mode 100644 index 0000000..533955a --- /dev/null +++ b/src/rufl_init.c @@ -0,0 +1,1678 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2006 James Bursa + */ + +#define _GNU_SOURCE /* for strndup */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rufl_internal.h" + + +struct rufl_font_list_entry *rufl_font_list = 0; +size_t rufl_font_list_entries = 0; +const char **rufl_family_list = 0; +unsigned int rufl_family_list_entries = 0; +struct rufl_family_map_entry *rufl_family_map = 0; +os_error *rufl_fm_error = 0; +void *rufl_family_menu = 0; +unsigned short *rufl_substitution_table = 0; +struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE]; +int rufl_cache_time = 0; +bool rufl_old_font_manager = false; +wimp_w rufl_status_w = 0; +char rufl_status_buffer[80]; + +/** An entry in rufl_weight_table. */ +struct rufl_weight_table_entry { + const char *name; + unsigned int weight; +}; + +/** Map from font name part to font weight. Must be case-insensitive sorted by + * name. */ +const struct rufl_weight_table_entry rufl_weight_table[] = { + { "Black", 9 }, + { "Bold", 7 }, + { "Book", 3 }, + { "Demi", 6 }, + { "DemiBold", 6 }, + { "Extra", 8 }, + { "ExtraBlack", 9 }, + { "ExtraBold", 8 }, + { "ExtraLight", 1 }, + { "Heavy", 8 }, + { "Light", 2 }, + { "Medium", 5 }, + { "Regular", 4 }, + { "Semi", 6 }, + { "SemiBold", 6 }, + { "SemiLight", 3 }, + { "UltraBlack", 9 }, + { "UltraBold", 9 }, +}; + + +static rufl_code rufl_init_font_list(void); +static rufl_code rufl_init_add_font(const char *identifier, + const char *local_name); +static int rufl_weight_table_cmp(const void *keyval, const void *datum); +static rufl_code rufl_init_scan_font(unsigned int font); +static rufl_code rufl_init_scan_font_no_enumerate(unsigned int font); +static bool rufl_is_space(unsigned int u); +static rufl_code rufl_init_scan_font_old(unsigned int font_index); +static rufl_code rufl_init_scan_font_in_encoding(const char *font_name, + const char *encoding, struct rufl_character_set *charset, + struct rufl_unicode_map *umap, unsigned int *last); +static rufl_code rufl_init_read_encoding(font_f font, + struct rufl_unicode_map *umap); +static int rufl_glyph_map_cmp(const void *keyval, const void *datum); +static int rufl_unicode_map_cmp(const void *z1, const void *z2); +static rufl_code rufl_init_substitution_table(void); +static rufl_code rufl_save_cache(void); +static rufl_code rufl_load_cache(void); +static int rufl_font_list_cmp(const void *keyval, const void *datum); +static rufl_code rufl_init_family_menu(void); +static void rufl_init_status_open(void); +static void rufl_init_status(const char *status, float progress); +static void rufl_init_status_close(void); + + +/** + * Initialise RUfl. + * + * All available fonts are scanned. May take some time. + */ + +rufl_code rufl_init(void) +{ + bool rufl_broken_font_enumerate_characters = false; + unsigned int changes = 0; + unsigned int i; + int fm_version; + rufl_code code; + font_f font; + os_colour old_sand, old_glass; + + if (rufl_font_list_entries) + /* already initialized */ + return rufl_OK; + + xhourglass_on(); + + rufl_init_status_open(); + + /* determine if the font manager supports Unicode */ + rufl_fm_error = xfont_find_font("Homerton.Medium\\EUTF8", 160, 160, + 0, 0, &font, 0, 0); + if (rufl_fm_error) { + if (rufl_fm_error->errnum == error_FONT_ENCODING_NOT_FOUND) { + rufl_old_font_manager = true; + } else { + LOG("xfont_find_font: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + rufl_quit(); + xhourglass_off(); + return rufl_FONT_MANAGER_ERROR; + } + } else { + /* New font manager; see if character enumeration works */ + int next; + + rufl_fm_error = xfont_enumerate_characters(font, 0, + &next, NULL); + /* Broken if SWI fails or it doesn't return 0x20 as the first + * character to process. Font Managers earlier than 3.64 have + * a bug that means they do not return the first available + * range of characters in a font. We detect this by asking + * for the first character in Homerton.Medium, which we know + * is 0x20 (i.e. space). If the value returned is not this, + * then we assume the font manager is broken and fall back to + * the old code which is significantly slower. + */ + if (rufl_fm_error || next != 0x20) + rufl_broken_font_enumerate_characters = true; + + xfont_lose_font(font); + } + LOG("%s font manager", rufl_old_font_manager ? "old" : "new"); + + /* test if the font manager supports background blending */ + rufl_fm_error = xfont_cache_addr(&fm_version, 0, 0); + if (rufl_fm_error) + return rufl_FONT_MANAGER_ERROR; + if (fm_version >= 335) + rufl_can_background_blend = true; + + code = rufl_init_font_list(); + if (code != rufl_OK) { + rufl_quit(); + xhourglass_off(); + return code; + } + LOG("%zu faces, %u families", rufl_font_list_entries, + rufl_family_list_entries); + + code = rufl_load_cache(); + if (code != rufl_OK) { + LOG("rufl_load_cache: 0x%x", code); + rufl_quit(); + xhourglass_off(); + return code; + } + + xhourglass_leds(1, 0, 0); + for (i = 0; i != rufl_font_list_entries; i++) { + if (rufl_font_list[i].charset) { + /* character set loaded from cache */ + continue; + } + LOG("scanning %u \"%s\"", i, rufl_font_list[i].identifier); + xhourglass_percentage(100 * i / rufl_font_list_entries); + rufl_init_status(rufl_font_list[i].identifier, + (float) i / rufl_font_list_entries); + if (rufl_old_font_manager) + code = rufl_init_scan_font_old(i); + else if (rufl_broken_font_enumerate_characters) + code = rufl_init_scan_font_no_enumerate(i); + else + code = rufl_init_scan_font(i); + if (code != rufl_OK) { + LOG("rufl_init_scan_font: 0x%x", code); + rufl_quit(); + xhourglass_off(); + return code; + } + changes++; + } + + xhourglass_leds(2, 0, 0); + xhourglass_colours(0x0000ff, 0x00ffff, &old_sand, &old_glass); + code = rufl_init_substitution_table(); + if (code != rufl_OK) { + LOG("rufl_init_substitution_table: 0x%x", code); + rufl_quit(); + xhourglass_off(); + return code; + } + xhourglass_colours(old_sand, old_glass, 0, 0); + + if (changes) { + LOG("%u new charsets", changes); + xhourglass_leds(3, 0, 0); + code = rufl_save_cache(); + if (code != rufl_OK) { + LOG("rufl_save_cache: 0x%x", code); + rufl_quit(); + xhourglass_off(); + return code; + } + } + + for (i = 0; i != rufl_CACHE_SIZE; i++) + rufl_cache[i].font = rufl_CACHE_NONE; + + code = rufl_init_family_menu(); + if (code != rufl_OK) { + LOG("rufl_init_substitution_table: 0x%x", code); + rufl_quit(); + xhourglass_off(); + return code; + } + + rufl_init_status_close(); + + xhourglass_off(); + + return rufl_OK; +} + + +/** + * Build list of font in rufl_font_list and list of font families + * in rufl_family_list. + */ + +rufl_code rufl_init_font_list(void) +{ + rufl_code code; + font_list_context context = 0; + char identifier[80], local_name[80]; + + while (context != -1) { + /* read identifier */ + rufl_fm_error = xfont_list_fonts((byte *)identifier, + font_RETURN_FONT_NAME | + font_RETURN_LOCAL_FONT_NAME | + context, + sizeof identifier, + (byte *)local_name, sizeof local_name, 0, + &context, 0, 0); + if (rufl_fm_error) { + LOG("xfont_list_fonts: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + if (context == -1) + break; + + code = rufl_init_add_font(identifier, local_name); + if (code != rufl_OK) + return code; + } + + return rufl_OK; +} + + +rufl_code rufl_init_add_font(const char *identifier, const char *local_name) +{ + int size; + struct rufl_font_list_entry *font_list; + char *dot; + const char **family_list; + const char *family, *part; + unsigned int weight = 0; + unsigned int slant = 0; + bool special = false; + struct rufl_family_map_entry *family_map; + unsigned int i; + struct rufl_weight_table_entry *entry; + + /* Check that: + * a) it's not a RiScript generated font + * b) it's not a TeX font */ + + /* Read required buffer size */ + rufl_fm_error = xosfscontrol_canonicalise_path(identifier, 0, + "Font$Path", 0, 0, &size); + if (rufl_fm_error) { + LOG("xosfscontrol_canonicalise_path(\"%s\", ...): 0x%x: %s", + identifier, + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_OK; + } + /* size is -(space required - 1) so negate and add 1 */ + size = -size + 1; + + /* Create buffer and canonicalise path */ + char fullpath[size]; + rufl_fm_error = xosfscontrol_canonicalise_path(identifier, + fullpath, "Font$Path", 0, size, 0); + if (rufl_fm_error) { + LOG("xosfscontrol_canonicalise_path(\"%s\", ...): 0x%x: %s", + identifier, + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_OK; + } + + /* LOG("%s", fullpath); */ + + if (strstr(fullpath, "RiScript") || strstr(fullpath, "!TeXFonts")) + /* Ignore this font */ + return rufl_OK; + + /* add identifier to rufl_font_list */ + font_list = realloc(rufl_font_list, sizeof rufl_font_list[0] * + (rufl_font_list_entries + 1)); + if (!font_list) + return rufl_OUT_OF_MEMORY; + rufl_font_list = font_list; + rufl_font_list[rufl_font_list_entries].identifier = strdup(identifier); + if (!rufl_font_list[rufl_font_list_entries].identifier) + return rufl_OUT_OF_MEMORY; + rufl_font_list[rufl_font_list_entries].charset = 0; + rufl_font_list[rufl_font_list_entries].umap = 0; + rufl_font_list_entries++; + + /* determine family, weight, and slant */ + dot = strchr(local_name, '.'); + family = local_name; + if (dot) + *dot = 0; + while (dot) { + part = dot + 1; + dot = strchr(part, '.'); + if (dot) + *dot = 0; + if (strcasecmp(part, "Italic") == 0 || + strcasecmp(part, "Oblique") == 0) { + slant = 1; + continue; + } + entry = bsearch(part, rufl_weight_table, + sizeof rufl_weight_table / + sizeof rufl_weight_table[0], + sizeof rufl_weight_table[0], + rufl_weight_table_cmp); + if (entry) + weight = entry->weight; + else + special = true; /* unknown weight or style */ + } + if (!weight) + weight = 4; + weight--; + + if (rufl_family_list_entries == 0 || strcasecmp(family, + rufl_family_list[rufl_family_list_entries - 1]) != 0) { + /* new family */ + family_list = realloc(rufl_family_list, + sizeof rufl_family_list[0] * + (rufl_family_list_entries + 1)); + if (!family_list) + return rufl_OUT_OF_MEMORY; + rufl_family_list = family_list; + + family_map = realloc(rufl_family_map, + sizeof rufl_family_map[0] * + (rufl_family_list_entries + 1)); + if (!family_map) + return rufl_OUT_OF_MEMORY; + rufl_family_map = family_map; + + family = strdup(family); + if (!family) + return rufl_OUT_OF_MEMORY; + + rufl_family_list[rufl_family_list_entries] = family; + for (i = 0; i != 9; i++) + rufl_family_map[rufl_family_list_entries].font[i][0] = + rufl_family_map[rufl_family_list_entries].font[i][1] = + NO_FONT; + rufl_family_list_entries++; + } + + struct rufl_family_map_entry *e = + &rufl_family_map[rufl_family_list_entries - 1]; + /* prefer fonts with no unknown weight or style in their name, so that, + * for example, Alps.Light takes priority over Alps.Cond.Light */ + if (e->font[weight][slant] == NO_FONT || !special) + e->font[weight][slant] = rufl_font_list_entries - 1; + + rufl_font_list[rufl_font_list_entries - 1].family = + rufl_family_list_entries - 1; + rufl_font_list[rufl_font_list_entries - 1].weight = weight; + rufl_font_list[rufl_font_list_entries - 1].slant = slant; + + return rufl_OK; +} + + +int rufl_weight_table_cmp(const void *keyval, const void *datum) +{ + const char *key = keyval; + const struct rufl_weight_table_entry *entry = datum; + return strcasecmp(key, entry->name); +} + +/** + * Scan a font for available characters. + */ + +rufl_code rufl_init_scan_font(unsigned int font_index) +{ + char font_name[80]; + int x_out, y_out; + unsigned int byte, bit; + unsigned int last_used = 0; + unsigned int string[2] = { 0, 0 }; + unsigned int u, next; + struct rufl_character_set *charset; + struct rufl_character_set *charset2; + font_f font; + font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } }; + + /*LOG("font %u \"%s\"", font_index, + rufl_font_list[font_index].identifier);*/ + + charset = calloc(1, sizeof *charset); + if (!charset) + return rufl_OUT_OF_MEMORY; + for (u = 0; u != 256; u++) + charset->index[u] = BLOCK_EMPTY; + + snprintf(font_name, sizeof font_name, "%s\\EUTF8", + rufl_font_list[font_index].identifier); + + rufl_fm_error = xfont_find_font(font_name, 160, 160, 0, 0, &font, 0, 0); + if (rufl_fm_error) { + LOG("xfont_find_font(\"%s\"): 0x%x: %s", font_name, + rufl_fm_error->errnum, rufl_fm_error->errmess); + free(charset); + return rufl_OK; + } + + /* Scan through mapped characters */ + for (u = 0; u != (unsigned int) -1; u = next) { + unsigned int internal; + + rufl_fm_error = xfont_enumerate_characters(font, u, + (int *) &next, (int *) &internal); + if (rufl_fm_error) { + LOG("xfont_enumerate_characters: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + xfont_lose_font(font); + free(charset); + return rufl_OK; + } + + /* Skip DELETE and C0/C1 controls */ + if (u < 0x0020 || (0x007f <= u && u <= 0x009f)) + continue; + + /* Skip astral characters */ + if (u > 0xffff) + continue; + + /* Skip unmapped characters */ + if (internal == (unsigned int) -1) + continue; + + if (u % 0x200 == 0) + rufl_init_status(0, 0); + + /* Character is mapped, let's see if it's really there */ + string[0] = u; + rufl_fm_error = xfont_scan_string(font, (char *) string, + font_RETURN_BBOX | font_GIVEN32_BIT | + font_GIVEN_FONT | font_GIVEN_LENGTH | + font_GIVEN_BLOCK, + 0x7fffffff, 0x7fffffff, + &block, 0, 4, + 0, &x_out, &y_out, 0); + if (rufl_fm_error) + break; + + if (block.bbox.x0 == 0x20000000) { + /* absent (no definition) */ + } else if (x_out == 0 && y_out == 0 && + block.bbox.x0 == 0 && block.bbox.y0 == 0 && + block.bbox.x1 == 0 && block.bbox.y1 == 0) { + /* absent (empty) */ + } else if (block.bbox.x0 == 0 && block.bbox.y0 == 0 && + block.bbox.x1 == 0 && block.bbox.y1 == 0 && + !rufl_is_space(u)) { + /* absent (space but not a space character - some + * fonts do this) */ + } else { + /* present */ + if (charset->index[u >> 8] == BLOCK_EMPTY) { + charset->index[u >> 8] = last_used; + last_used++; + if (last_used == 254) + /* too many characters */ + break; + } + + byte = (u >> 3) & 31; + bit = u & 7; + charset->block[charset->index[u >> 8]][byte] |= + 1 << bit; + } + } + + xfont_lose_font(font); + + if (rufl_fm_error) { + free(charset); + LOG("xfont_scan_string: 0x%x: %s", + rufl_fm_error->errnum, rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + /* Determine which blocks are full, and mark them as such */ + for (u = 0; u != 256; u++) { + if (charset->index[u] == BLOCK_EMPTY) + continue; + + bit = 0xff; + + for (byte = 0; byte != 32; byte++) + bit &= charset->block[u][byte]; + + if (bit == 0xff) { + /* Block is full */ + charset->index[u] = BLOCK_FULL; + + for (byte = 0; byte != 32; byte++) + charset->block[u][byte] = 0; + } + } + + /* shrink-wrap */ + charset->size = offsetof(struct rufl_character_set, block) + + 32 * last_used; + charset2 = realloc(charset, charset->size); + if (!charset2) { + free(charset); + return rufl_OUT_OF_MEMORY; + } + + rufl_font_list[font_index].charset = charset; + + return rufl_OK; +} + +/** + * Scan a font for available characters (version without character enumeration) + */ + +rufl_code rufl_init_scan_font_no_enumerate(unsigned int font_index) +{ + char font_name[80]; + int x_out, y_out; + unsigned int byte, bit; + unsigned int block_count = 0; + unsigned int last_used = 0; + unsigned int string[2] = { 0, 0 }; + unsigned int u; + struct rufl_character_set *charset; + struct rufl_character_set *charset2; + font_f font; + font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } }; + + /*LOG("font %u \"%s\"", font_index, + rufl_font_list[font_index].identifier);*/ + + charset = calloc(1, sizeof *charset); + if (!charset) + return rufl_OUT_OF_MEMORY; + + snprintf(font_name, sizeof font_name, "%s\\EUTF8", + rufl_font_list[font_index].identifier); + + rufl_fm_error = xfont_find_font(font_name, 160, 160, 0, 0, &font, 0, 0); + if (rufl_fm_error) { + LOG("xfont_find_font(\"%s\"): 0x%x: %s", font_name, + rufl_fm_error->errnum, rufl_fm_error->errmess); + free(charset); + return rufl_OK; + } + + /* scan through all characters */ + for (u = 0x0020; u != 0x10000; u++) { + if (u == 0x007f) { + /* skip DELETE and C1 controls */ + u = 0x009f; + continue; + } + + if (u % 0x200 == 0) + rufl_init_status(0, 0); + + string[0] = u; + rufl_fm_error = xfont_scan_string(font, (char *) string, + font_RETURN_BBOX | font_GIVEN32_BIT | + font_GIVEN_FONT | font_GIVEN_LENGTH | + font_GIVEN_BLOCK, + 0x7fffffff, 0x7fffffff, + &block, 0, 4, + 0, &x_out, &y_out, 0); + if (rufl_fm_error) + break; + + if (block.bbox.x0 == 0x20000000) { + /* absent (no definition) */ + } else if (x_out == 0 && y_out == 0 && + block.bbox.x0 == 0 && block.bbox.y0 == 0 && + block.bbox.x1 == 0 && block.bbox.y1 == 0) { + /* absent (empty) */ + } else if (block.bbox.x0 == 0 && block.bbox.y0 == 0 && + block.bbox.x1 == 0 && block.bbox.y1 == 0 && + !rufl_is_space(u)) { + /* absent (space but not a space character - some + * fonts do this) */ + } else { + /* present */ + byte = (u >> 3) & 31; + bit = u & 7; + charset->block[last_used][byte] |= 1 << bit; + + block_count++; + } + + if ((u + 1) % 256 == 0) { + /* end of block */ + if (block_count == 0) + charset->index[u >> 8] = BLOCK_EMPTY; + else if (block_count == 256) { + charset->index[u >> 8] = BLOCK_FULL; + for (byte = 0; byte != 32; byte++) + charset->block[last_used][byte] = 0; + } else { + charset->index[u >> 8] = last_used; + last_used++; + if (last_used == 254) + /* too many characters */ + break; + } + block_count = 0; + } + } + + xfont_lose_font(font); + + if (rufl_fm_error) { + free(charset); + LOG("xfont_scan_string: 0x%x: %s", + rufl_fm_error->errnum, rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + /* shrink-wrap */ + charset->size = offsetof(struct rufl_character_set, block) + + 32 * last_used; + charset2 = realloc(charset, charset->size); + if (!charset2) { + free(charset); + return rufl_OUT_OF_MEMORY; + } + + rufl_font_list[font_index].charset = charset; + + return rufl_OK; +} + +/** + * A character is one of the Unicode space characters. + */ + +bool rufl_is_space(unsigned int u) +{ + return u == 0x0020 || u == 0x00a0 || + (0x2000 <= u && u <= 0x200b) || + u == 0x202f || u == 0x3000; +} + + +/** + * Scan a font for available characters (old font manager version). + */ + +rufl_code rufl_init_scan_font_old(unsigned int font_index) +{ + const char *font_name = rufl_font_list[font_index].identifier; + struct rufl_character_set *charset; + struct rufl_character_set *charset2; + struct rufl_unicode_map *umap = NULL; + unsigned int num_umaps = 0; + unsigned int i; + unsigned int last_used = 0; + rufl_code code; + font_list_context context = 0; + char encoding[80]; + + /*LOG("font %u \"%s\"", font_index, font_name);*/ + + charset = calloc(1, sizeof *charset); + if (!charset) + return rufl_OUT_OF_MEMORY; + for (i = 0; i != 256; i++) + charset->index[i] = BLOCK_EMPTY; + + /* Firstly, search through available encodings (Symbol fonts fail) */ + while (context != -1) { + struct rufl_unicode_map *temp; + + rufl_fm_error = xfont_list_fonts((byte *) encoding, + font_RETURN_FONT_NAME | + 0x400000 /* Return encoding name, instead */ | + context, + sizeof(encoding), NULL, 0, NULL, + &context, NULL, NULL); + if (rufl_fm_error) { + LOG("xfont_list_fonts: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + free(charset); + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + return rufl_FONT_MANAGER_ERROR; + } + if (context == -1) + break; + + temp = realloc(umap, (num_umaps + 1) * sizeof *umap); + if (!temp) { + free(charset); + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + return rufl_OUT_OF_MEMORY; + } + + memset(temp + num_umaps, 0, sizeof *umap); + + umap = temp; + num_umaps++; + + code = rufl_init_scan_font_in_encoding(font_name, encoding, + charset, umap + (num_umaps - 1), &last_used); + if (code != rufl_OK) { + /* Not finding the font isn't fatal */ + if (code != rufl_FONT_MANAGER_ERROR || + (rufl_fm_error->errnum != + error_FONT_NOT_FOUND && + rufl_fm_error->errnum != + error_FILE_NOT_FOUND)) { + free(charset); + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + return code; + } + + /* Ensure we reuse the currently allocated umap */ + num_umaps--; + } else { + /* If this mapping is identical to an existing one, + * then we can discard it */ + for (i = 0; i != num_umaps - 1; i++) { + const struct rufl_unicode_map *a = (umap + i); + const struct rufl_unicode_map *b = + (umap + num_umaps - 1); + + if (a->entries == b->entries && + memcmp(a->map, b->map, + sizeof a->map) == 0) { + /* Found identical map; discard */ + num_umaps--; + break; + } + } + } + } + + if (num_umaps == 0) { + /* This is a symbol font and can only be used + * without an encoding */ + struct rufl_unicode_map *temp; + + temp = realloc(umap, (num_umaps + 1) * sizeof *umap); + if (!temp) { + free(charset); + free(umap); + return rufl_OUT_OF_MEMORY; + } + + memset(temp + num_umaps, 0, sizeof *umap); + + umap = temp; + num_umaps++; + + code = rufl_init_scan_font_in_encoding(font_name, NULL, + charset, umap, &last_used); + if (code != rufl_OK) { + /* Not finding the font isn't fatal */ + if (code != rufl_FONT_MANAGER_ERROR || + (rufl_fm_error->errnum != + error_FONT_NOT_FOUND && + rufl_fm_error->errnum != + error_FILE_NOT_FOUND)) { + free(charset); + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + return code; + } + + num_umaps--; + } + } + + /* shrink-wrap */ + charset->size = offsetof(struct rufl_character_set, block) + + 32 * last_used; + charset2 = realloc(charset, charset->size); + if (!charset2) { + for (i = 0; i < num_umaps; i++) + free((umap + i)->encoding); + free(umap); + free(charset); + return rufl_OUT_OF_MEMORY; + } + + rufl_font_list[font_index].charset = charset; + rufl_font_list[font_index].umap = umap; + rufl_font_list[font_index].num_umaps = num_umaps; + + return rufl_OK; +} + +/** + * Helper function for rufl_init_scan_font_old. + * Scans the given font using the given font encoding (or none, if NULL) + */ + +rufl_code rufl_init_scan_font_in_encoding(const char *font_name, + const char *encoding, struct rufl_character_set *charset, + struct rufl_unicode_map *umap, unsigned int *last) +{ + char string[2] = { 0, 0 }; + int x_out, y_out; + unsigned int byte, bit; + unsigned int i; + unsigned int last_used = *last; + unsigned int u; + rufl_code code; + font_f font; + font_scan_block block = { { 0, 0 }, { 0, 0 }, -1, { 0, 0, 0, 0 } }; + char buf[80]; + + if (encoding) + snprintf(buf, sizeof buf, "%s\\E%s", font_name, encoding); + else + snprintf(buf, sizeof buf, "%s", font_name); + + rufl_fm_error = xfont_find_font(buf, 160, 160, 0, 0, &font, 0, 0); + if (rufl_fm_error) { + LOG("xfont_find_font(\"%s\"): 0x%x: %s", buf, + rufl_fm_error->errnum, rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + code = rufl_init_read_encoding(font, umap); + if (code != rufl_OK) { + xfont_lose_font(font); + return code; + } + + for (i = 0; i != umap->entries; i++) { + u = umap->map[i].u; + string[0] = umap->map[i].c; + rufl_fm_error = xfont_scan_string(font, (char *) string, + font_RETURN_BBOX | font_GIVEN_FONT | + font_GIVEN_LENGTH | font_GIVEN_BLOCK, + 0x7fffffff, 0x7fffffff, + &block, 0, 1, + 0, &x_out, &y_out, 0); + if (rufl_fm_error) + break; + + if (block.bbox.x0 == 0x20000000) { + /* absent (no definition) */ + } else if (x_out == 0 && y_out == 0 && + block.bbox.x0 == 0 && block.bbox.y0 == 0 && + block.bbox.x1 == 0 && block.bbox.y1 == 0) { + /* absent (empty) */ + } else if (block.bbox.x0 == 0 && block.bbox.y0 == 0 && + block.bbox.x1 == 0 && block.bbox.y1 == 0 && + !rufl_is_space(u)) { + /* absent (space but not a space character - some + * fonts do this) */ + } else { + /* present */ + if (charset->index[u >> 8] == BLOCK_EMPTY) { + charset->index[u >> 8] = last_used; + last_used++; + if (last_used == 254) + /* too many characters */ + break; + } + + byte = (u >> 3) & 31; + bit = u & 7; + charset->block[charset->index[u >> 8]][byte] |= + 1 << bit; + } + } + + xfont_lose_font(font); + + if (rufl_fm_error) { + LOG("xfont_scan_string: 0x%x: %s", + rufl_fm_error->errnum, rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + if (encoding) { + umap->encoding = strdup(encoding); + if (!umap->encoding) + return rufl_OUT_OF_MEMORY; + } + + *last = last_used; + + return rufl_OK; +} + + +/** + * Parse an encoding file and fill in a rufl_unicode_map. + */ + +rufl_code rufl_init_read_encoding(font_f font, + struct rufl_unicode_map *umap) +{ + unsigned int u = 0; + unsigned int i = 0; + int c; + int n; + char filename[200]; + char s[200]; + struct rufl_glyph_map_entry *entry; + FILE *fp; + + rufl_fm_error = xfont_read_encoding_filename(font, filename, + sizeof filename, 0); + if (rufl_fm_error) { + LOG("xfont_read_encoding_filename: 0x%x: %s", + rufl_fm_error->errnum, rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + fp = fopen(filename, "r"); + if (!fp) + /* many "symbol" fonts have no encoding file: assume Latin 1 */ + fp = fopen("Resources:$.Fonts.Encodings.Latin1", "r"); + if (!fp) + return rufl_IO_ERROR; + + while (!feof(fp) && u != 256) { + c = fgetc(fp); + if (c == '%') { + /* comment line */ + fgets(s, sizeof s, fp); + } else if (c == '/') { + /* character definition */ + if (i++ < 32) + continue; + n = fscanf(fp, "%100s", s); + if (n != 1) + break; + entry = bsearch(s, rufl_glyph_map, + rufl_glyph_map_size, + sizeof rufl_glyph_map[0], + rufl_glyph_map_cmp); + if (entry) { + /* may be more than one unicode for the glyph + * sentinels stop overshooting array */ + while (strcmp(s, (entry - 1)->glyph_name) == 0) + entry--; + for (; strcmp(s, entry->glyph_name) == 0; + entry++) { + umap->map[u].u = entry->u; + umap->map[u].c = i - 1; + u++; + if (u == 256) + break; + } + } + } + } + + if (fclose(fp) == EOF) + return rufl_IO_ERROR; + + /* sort by unicode */ + qsort(umap->map, u, sizeof umap->map[0], rufl_unicode_map_cmp); + umap->entries = u; + + return rufl_OK; +} + + +int rufl_glyph_map_cmp(const void *keyval, const void *datum) +{ + const char *key = keyval; + const struct rufl_glyph_map_entry *entry = datum; + return strcmp(key, entry->glyph_name); +} + + +int rufl_unicode_map_cmp(const void *z1, const void *z2) +{ + const struct rufl_unicode_map_entry *entry1 = z1; + const struct rufl_unicode_map_entry *entry2 = z2; + if (entry1->u < entry2->u) + return -1; + else if (entry2->u < entry1->u) + return 1; + return 0; +} + + +/** + * Construct the font substitution table. + */ + +rufl_code rufl_init_substitution_table(void) +{ + unsigned char z; + unsigned int i; + unsigned int block, byte, bit; + unsigned int u; + unsigned int index; + const struct rufl_character_set *charset; + + rufl_substitution_table = malloc(65536 * + sizeof rufl_substitution_table[0]); + if (!rufl_substitution_table) { + LOG("malloc(%zu) failed", 65536 * + sizeof rufl_substitution_table[0]); + return rufl_OUT_OF_MEMORY; + } + + for (u = 0; u != 0x10000; u++) + rufl_substitution_table[u] = NOT_AVAILABLE; + + for (i = 0; i != rufl_font_list_entries; i++) { + charset = rufl_font_list[i].charset; + if (!charset) + continue; + for (block = 0; block != 256; block++) { + if (charset->index[block] == BLOCK_EMPTY) + continue; + if (charset->index[block] == BLOCK_FULL) { + for (u = block << 8; u != (block << 8) + 256; + u++) { + if (rufl_substitution_table[u] == + NOT_AVAILABLE) + rufl_substitution_table[u] = i; + } + continue; + } + index = charset->index[block]; + for (byte = 0; byte != 32; byte++) { + z = charset->block[index][byte]; + if (z == 0) + continue; + u = (block << 8) | (byte << 3); + for (bit = 0; bit != 8; bit++, u++) { + if (rufl_substitution_table[u] == + NOT_AVAILABLE && + z & (1 << bit)) + rufl_substitution_table[u] = i; + } + } + } + } + + return rufl_OK; +} + + +/** + * Save character sets to cache. + */ + +rufl_code rufl_save_cache(void) +{ + unsigned int i; + const unsigned int version = rufl_CACHE_VERSION; + size_t len; + FILE *fp; + + fp = fopen(rufl_CACHE, "wb"); + if (!fp) { + LOG("fopen: 0x%x: %s", errno, strerror(errno)); + return rufl_OK; + } + + /* cache format version */ + if (fwrite(&version, sizeof version, 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + /* font manager type flag */ + if (fwrite(&rufl_old_font_manager, sizeof rufl_old_font_manager, 1, + fp) != 1) { + LOG("fwrite: 0x%x: %s", errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + for (i = 0; i != rufl_font_list_entries; i++) { + if (!rufl_font_list[i].charset) + continue; + + /* length of font identifier */ + len = strlen(rufl_font_list[i].identifier); + if (fwrite(&len, sizeof len, 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + /* font identifier */ + if (fwrite(rufl_font_list[i].identifier, len, 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + /* character set */ + if (fwrite(rufl_font_list[i].charset, + rufl_font_list[i].charset->size, 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + /* unicode map */ + if (rufl_old_font_manager) { + unsigned int j; + + if (fwrite(&rufl_font_list[i].num_umaps, + sizeof rufl_font_list[i].num_umaps, 1, + fp) != 1) { + LOG("fwrite: 0x%x: %s", errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + for (j = 0; j < rufl_font_list[i].num_umaps; j++) { + const struct rufl_unicode_map *umap = + rufl_font_list[i].umap + j; + + len = umap->encoding ? + strlen(umap->encoding) : 0; + + if (fwrite(&len, sizeof len, 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", + errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + if (umap->encoding) { + if (fwrite(umap->encoding, len, 1, + fp) != 1) { + LOG("fwrite: 0x%x: %s", + errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + } + + if (fwrite(&umap->entries, sizeof umap->entries, + 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", + errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + + if (fwrite(umap->map, umap->entries * + sizeof(struct rufl_unicode_map_entry), + 1, fp) != 1) { + LOG("fwrite: 0x%x: %s", + errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + } + } + } + + if (fclose(fp) == EOF) { + LOG("fclose: 0x%x: %s", errno, strerror(errno)); + return rufl_OK; + } + + LOG("%u charsets saved", i); + + return rufl_OK; +} + + +/** + * Load character sets from cache. + */ + +rufl_code rufl_load_cache(void) +{ + unsigned int version; + unsigned int i = 0; + bool old_font_manager; + char *identifier; + size_t len, size; + FILE *fp; + struct rufl_font_list_entry *entry; + struct rufl_character_set *charset; + struct rufl_unicode_map *umap = NULL; + unsigned int num_umaps = 0; + + fp = fopen(rufl_CACHE, "rb"); + if (!fp) { + LOG("fopen: 0x%x: %s", errno, strerror(errno)); + return rufl_OK; + } + + /* cache format version */ + if (fread(&version, sizeof version, 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + if (version != rufl_CACHE_VERSION) { + /* incompatible cache format */ + LOG("cache version %u (now %u)", version, rufl_CACHE_VERSION); + fclose(fp); + return rufl_OK; + } + + /* font manager type flag */ + if (fread(&old_font_manager, sizeof old_font_manager, 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, strerror(errno)); + fclose(fp); + return rufl_OK; + } + if (old_font_manager != rufl_old_font_manager) { + /* font manager type has changed */ + LOG("font manager %u (now %u)", old_font_manager, + rufl_old_font_manager); + fclose(fp); + return rufl_OK; + } + + while (!feof(fp)) { + /* length of font identifier */ + if (fread(&len, sizeof len, 1, fp) != 1) { + /* eof at this point simply means that the whole cache + * file has been loaded */ + if (!feof(fp)) + LOG("fread: 0x%x: %s", errno, strerror(errno)); + break; + } + + identifier = malloc(len + 1); + if (!identifier) { + LOG("malloc(%zu) failed", len + 1); + fclose(fp); + return rufl_OUT_OF_MEMORY; + } + + /* font identifier */ + if (fread(identifier, len, 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, strerror(errno)); + free(identifier); + break; + } + identifier[len] = 0; + + /* character set */ + if (fread(&size, sizeof size, 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, strerror(errno)); + free(identifier); + break; + } + + charset = malloc(size); + if (!charset) { + LOG("malloc(%zu) failed", size); + free(identifier); + fclose(fp); + return rufl_OUT_OF_MEMORY; + } + + charset->size = size; + if (fread(charset->index, size - sizeof size, 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, strerror(errno)); + free(charset); + free(identifier); + break; + } + + /* unicode map */ + if (rufl_old_font_manager) { + rufl_code code = rufl_OK; + unsigned int entry; + + /* Number of maps */ + if (fread(&num_umaps, sizeof num_umaps, 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, + strerror(errno)); + free(charset); + free(identifier); + break; + } + + umap = calloc(num_umaps, sizeof *umap); + if (!umap) { + LOG("malloc(%zu) failed", sizeof *umap); + free(charset); + free(identifier); + fclose(fp); + return rufl_OUT_OF_MEMORY; + } + + /* Load them */ + for (entry = 0; entry < num_umaps; entry++) { + struct rufl_unicode_map *map = umap + entry; + + if (fread(&len, sizeof(len), 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", + "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, + strerror(errno)); + break; + } + + if (len > 0) { + map->encoding = malloc(len + 1); + if (!map->encoding) { + LOG("malloc(%zu) failed", + len + 1); + code = rufl_OUT_OF_MEMORY; + break; + } + + if (fread(map->encoding, len, 1, + fp) != 1) { + if (feof(fp)) + LOG("fread: %s", + "unexpected eof"); + else + LOG("fread: 0x%x: %s", + errno, + strerror(errno)); + break; + } + map->encoding[len] = 0; + } + + if (fread(&map->entries, sizeof(map->entries), + 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", + "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, + strerror(errno)); + break; + } + + if (fread(map->map, map->entries * + sizeof(struct rufl_unicode_map_entry), + 1, fp) != 1) { + if (feof(fp)) + LOG("fread: %s", + "unexpected eof"); + else + LOG("fread: 0x%x: %s", errno, + strerror(errno)); + break; + } + } + + /* Clean up if loading failed */ + if (entry != num_umaps) { + for (num_umaps = 0; num_umaps <= entry; + num_umaps++) { + struct rufl_unicode_map *map = + umap + num_umaps; + + free(map->encoding); + } + free(umap); + free(charset); + free(identifier); + + if (code != rufl_OK) + return code; + + break; + } + } + + /* put in rufl_font_list */ + entry = lfind(identifier, rufl_font_list, + &rufl_font_list_entries, + sizeof rufl_font_list[0], rufl_font_list_cmp); + if (entry) { + entry->charset = charset; + entry->umap = umap; + entry->num_umaps = num_umaps; + i++; + } else { + LOG("\"%s\" not in font list", identifier); + while (num_umaps > 0) { + struct rufl_unicode_map *map = + umap + num_umaps - 1; + + free(map->encoding); + + num_umaps--; + } + free(umap); + free(charset); + } + + free(identifier); + } + fclose(fp); + + LOG("%u charsets loaded", i); + + return rufl_OK; +} + + +int rufl_font_list_cmp(const void *keyval, const void *datum) +{ + const char *key = keyval; + const struct rufl_font_list_entry *entry = datum; + return strcasecmp(key, entry->identifier); +} + + +/** + * Create a menu of font families. + */ + +rufl_code rufl_init_family_menu(void) +{ + wimp_menu *menu; + unsigned int i; + + menu = malloc(wimp_SIZEOF_MENU(rufl_family_list_entries)); + if (!menu) + return rufl_OUT_OF_MEMORY; + menu->title_data.indirected_text.text = (char *) "Fonts"; + menu->title_fg = wimp_COLOUR_BLACK; + menu->title_bg = wimp_COLOUR_LIGHT_GREY; + menu->work_fg = wimp_COLOUR_BLACK; + menu->work_bg = wimp_COLOUR_WHITE; + menu->width = 200; + menu->height = wimp_MENU_ITEM_HEIGHT; + menu->gap = wimp_MENU_ITEM_GAP; + for (i = 0; i != rufl_family_list_entries; i++) { + menu->entries[i].menu_flags = 0; + menu->entries[i].sub_menu = wimp_NO_SUB_MENU; + menu->entries[i].icon_flags = wimp_ICON_TEXT | + wimp_ICON_INDIRECTED | + (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | + (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT); + menu->entries[i].data.indirected_text.text = + (char *) rufl_family_list[i]; + menu->entries[i].data.indirected_text.validation = (char *) -1; + menu->entries[i].data.indirected_text.size = + strlen(rufl_family_list[i]); + } + menu->entries[0].menu_flags = wimp_MENU_TITLE_INDIRECTED; + menu->entries[i - 1].menu_flags |= wimp_MENU_LAST; + + rufl_family_menu = menu; + + return rufl_OK; +} + + +/** + * Create and open the init status window. + */ + +void rufl_init_status_open(void) +{ + int xeig_factor, yeig_factor, xwind_limit, ywind_limit, width, height; + wimp_t task; + osbool window_task; + wimp_WINDOW(4) window = { { 0, 0, 0, 0 }, 0, 0, wimp_TOP, + wimp_WINDOW_AUTO_REDRAW | wimp_WINDOW_NEW_FORMAT, + wimp_COLOUR_BLACK, wimp_COLOUR_LIGHT_GREY, + wimp_COLOUR_BLACK, wimp_COLOUR_VERY_LIGHT_GREY, + wimp_COLOUR_DARK_GREY, wimp_COLOUR_LIGHT_GREY, + wimp_COLOUR_CREAM, 0, + { 0, -128, 800, 0 }, 0, 0, 0, 0, 0, { "" }, 4, + { { { 12, -56, 788, -12 }, wimp_ICON_TEXT | + wimp_ICON_HCENTRED | wimp_ICON_VCENTRED | + wimp_ICON_INDIRECTED | + wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT | + wimp_COLOUR_VERY_LIGHT_GREY <errnum, error->errmess); + return; + } + if (!task) + return; /* not a Wimp task */ + + error = xtaskwindowtaskinfo_window_task(&window_task); + if (error) { + LOG("xtaskwindowtaskinfo_window_task: 0x%x: %s", + error->errnum, error->errmess); + return; + } + if (window_task) + return; /* in a TaskWindow */ + + xwimp_create_window((const wimp_window *) &window, &rufl_status_w); + state.w = rufl_status_w; + xwimp_get_window_state(&state); + xwimp_open_window((wimp_open *) (void *) &state); +} + + +/** + * Update the status window and multitask. + */ + +void rufl_init_status(const char *status, float progress) +{ + wimp_block block; + static os_t last_t = 0; + os_t t; + + if (!rufl_status_w) + return; + + if (status) { + strncpy(rufl_status_buffer, status, sizeof rufl_status_buffer); + rufl_status_buffer[sizeof rufl_status_buffer - 1] = 0; + xwimp_set_icon_state(rufl_status_w, 3, 0, 0); + } + if (progress) + xwimp_resize_icon(rufl_status_w, 2, 16, -112, + 16 + 768 * progress, -68); + xos_read_monotonic_time(&t); + if (last_t == t) + return; + xwimp_poll(wimp_QUEUE_REDRAW | wimp_MASK_LEAVING | wimp_MASK_ENTERING | + wimp_MASK_LOSE | wimp_MASK_GAIN | wimp_MASK_MESSAGE | + wimp_MASK_RECORDED | wimp_MASK_ACKNOWLEDGE, + &block, 0, 0); + last_t = t; +} + + +/** + * Close and delete the status window. + */ + +void rufl_init_status_close(void) +{ + if (!rufl_status_w) + return; + + xwimp_delete_window(rufl_status_w); + rufl_status_w = 0; +} diff --git a/src/rufl_internal.h b/src/rufl_internal.h new file mode 100644 index 0000000..1c01e36 --- /dev/null +++ b/src/rufl_internal.h @@ -0,0 +1,194 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2006 James Bursa + */ + +#include +#include "oslib/font.h" +#include "rufl.h" +#ifdef __CC_NORCROFT +#include "strfuncs.h" +#endif + + +/** The available characters in a font. The range which can be represented is + * 0x0000 to 0xffff. The size of the structure is 4 + 256 + 32 * blocks. A + * typical * 200 glyph font might have characters in 10 blocks, giving 580 + * bytes. The maximum possible size of the structure is 8388 bytes. Note that + * since two index values are reserved, fonts with 65280-65024 glyphs may be + * unrepresentable, if there are no full blocks. This is unlikely. The primary + * aim of this structure is to make lookup fast. */ +struct rufl_character_set { + /** Size of structure / bytes. */ + size_t size; + + /** Index table. Each entry represents a block of 256 characters, so + * i[k] refers to characters [256*k, 256*(k+1)). The value is either + * BLOCK_EMPTY, BLOCK_FULL, or an offset into the block table. */ + unsigned char index[256]; + /** The block has no characters present. */ +# define BLOCK_EMPTY 254 + /** All characters in the block are present. */ +# define BLOCK_FULL 255 + + /** Block table. Each entry is a 256-bit bitmap indicating which + * characters in the block are present and absent. */ + unsigned char block[254][32]; +}; + + +/** Part of struct rufl_unicode_map. */ +struct rufl_unicode_map_entry { + /** Unicode value. */ + unsigned short u; + /** Corresponding character. */ + unsigned char c; +}; + + +/** Old font manager: mapping from Unicode to character code. This is simply + * an array sorted by Unicode value, suitable for bsearch(). If a font has + * support for multiple encodings, then it will have multiple unicode maps. + * The encoding field contains the name of the encoding to pass to the + * font manager. This will be NULL if the font is a Symbol font. */ +struct rufl_unicode_map { + /** Corresponding encoding name */ + char *encoding; + /** Number of valid entries in map. */ + unsigned int entries; + /** Map from Unicode to character code. */ + struct rufl_unicode_map_entry map[256]; +}; + + +/** An entry in rufl_font_list. */ +struct rufl_font_list_entry { + /** Font identifier (name). */ + char *identifier; + /** Character set of font. */ + struct rufl_character_set *charset; + /** Number of Unicode mapping tables */ + unsigned int num_umaps; + /** Mappings from Unicode to character code. */ + struct rufl_unicode_map *umap; + /** Family that this font belongs to (index in rufl_family_list and + * rufl_family_map). */ + unsigned int family; + /** Font weight (0 to 8). */ + unsigned int weight; + /** Font slant (0 or 1). */ + unsigned int slant; +}; +/** List of all available fonts. */ +extern struct rufl_font_list_entry *rufl_font_list; +/** Number of entries in rufl_font_list. */ +extern size_t rufl_font_list_entries; + + +/** An entry in rufl_family_map. */ +struct rufl_family_map_entry { + /** This style does not exist in this family. */ +# define NO_FONT UINT_MAX + /** Map from weight and slant to index in rufl_font_list, or NO_FONT. */ + unsigned int font[9][2]; +}; +/** Map from font family to fonts, rufl_family_list_entries entries. */ +extern struct rufl_family_map_entry *rufl_family_map; + + +/** No font contains this character. */ +#define NOT_AVAILABLE 65535 +/** Font substitution table. */ +extern unsigned short *rufl_substitution_table; + + +/** Number of slots in recent-use cache. This is the maximum number of RISC OS + * font handles that will be used at any time by the library. */ +#define rufl_CACHE_SIZE 10 + +/** An entry in rufl_cache. */ +struct rufl_cache_entry { + /** Font number (index in rufl_font_list), or rufl_CACHE_*. */ + unsigned int font; + /** No font cached in this slot. */ +#define rufl_CACHE_NONE UINT_MAX + /** Font for rendering hex substitutions in this slot. */ +#define rufl_CACHE_CORPUS (UINT_MAX - 1) + /** Font size. */ + unsigned int size; + /** Font encoding */ + const char *encoding; + /** Value of rufl_cache_time when last used. */ + unsigned int last_used; + /** RISC OS font handle. */ + font_f f; +}; +/** Cache of rufl_CACHE_SIZE most recently used font handles. */ +extern struct rufl_cache_entry rufl_cache[rufl_CACHE_SIZE]; +/** Counter for measuring age of cache entries. */ +extern int rufl_cache_time; + +/** Font manager does not support Unicode. */ +extern bool rufl_old_font_manager; + +/** Font manager supports background blending */ +extern bool rufl_can_background_blend; + +rufl_code rufl_find_font_family(const char *family, rufl_style font_style, + unsigned int *font, unsigned int *slanted, + struct rufl_character_set **charset); +rufl_code rufl_find_font(unsigned int font, unsigned int font_size, + const char *encoding, font_f *fhandle); +bool rufl_character_set_test(struct rufl_character_set *charset, + unsigned int c); + + +#define rufl_utf8_read(s, l, u) \ + if (4 <= l && ((s[0] & 0xf8) == 0xf0) && ((s[1] & 0xc0) == 0x80) && \ + ((s[2] & 0xc0) == 0x80) && ((s[3] & 0xc0) == 0x80)) { \ + u = ((s[0] & 0x7) << 18) | ((s[1] & 0x3f) << 12) | \ + ((s[2] & 0x3f) << 6) | (s[3] & 0x3f); \ + s += 4; l -= 4; \ + } else if (3 <= l && ((s[0] & 0xf0) == 0xe0) && \ + ((s[1] & 0xc0) == 0x80) && \ + ((s[2] & 0xc0) == 0x80)) { \ + u = ((s[0] & 0xf) << 12) | ((s[1] & 0x3f) << 6) | \ + (s[2] & 0x3f); \ + s += 3; l -= 3; \ + } else if (2 <= l && ((s[0] & 0xe0) == 0xc0) && \ + ((s[1] & 0xc0) == 0x80)) { \ + u = ((s[0] & 0x3f) << 6) | (s[1] & 0x3f); \ + s += 2; l -= 2; \ + } else if ((s[0] & 0x80) == 0) { \ + u = s[0]; \ + s++; l--; \ + } else { \ + u = 0xfffd; \ + s++; l--; \ + } + +#define rufl_CACHE ".RUfl_cache" +#define rufl_CACHE_VERSION 3 + + +struct rufl_glyph_map_entry { + const char *glyph_name; + unsigned short u; +}; + +extern const struct rufl_glyph_map_entry rufl_glyph_map[]; +extern const size_t rufl_glyph_map_size; + + +#ifndef NDEBUG +#ifdef __CC_NORCROFT +#define __PRETTY_FUNCTION__ __func__ +#endif +#define LOG(format, ...) (fprintf(stderr, __FILE__ " %s %i: ", \ + __PRETTY_FUNCTION__, __LINE__), fprintf(stderr, format, \ + __VA_ARGS__), fprintf(stderr, "\n")) +#else +#define LOG(format, ...) ((void) 0) +#endif diff --git a/src/rufl_invalidate_cache.c b/src/rufl_invalidate_cache.c new file mode 100644 index 0000000..65a3897 --- /dev/null +++ b/src/rufl_invalidate_cache.c @@ -0,0 +1,28 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2005 James Bursa + */ + +#include "oslib/font.h" +#include "rufl_internal.h" + + +/** + * Clear the internal font handle cache. + * + * Call this function on mode changes or output redirection changes. + */ + +void rufl_invalidate_cache(void) +{ + unsigned int i; + + for (i = 0; i != rufl_CACHE_SIZE; i++) { + if (rufl_cache[i].font != rufl_CACHE_NONE) { + xfont_lose_font(rufl_cache[i].f); + rufl_cache[i].font = rufl_CACHE_NONE; + } + } +} diff --git a/src/rufl_metrics.c b/src/rufl_metrics.c new file mode 100644 index 0000000..af4727f --- /dev/null +++ b/src/rufl_metrics.c @@ -0,0 +1,312 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2005 John-Mark Bell + */ + +#include +#include +#include + +#include "oslib/font.h" + +#include "rufl_internal.h" + +static int rufl_unicode_map_search_cmp(const void *keyval, const void *datum); + +/** + * Read a font's metrics (sized for a 1pt font) + */ +rufl_code rufl_font_metrics(const char *font_family, rufl_style font_style, + os_box *bbox, int *xkern, int *ykern, int *italic, + int *ascent, int *descent, + int *xheight, int *cap_height, + signed char *uline_position, unsigned char *uline_thickness) +{ + unsigned int font; + font_f f; + int misc_size; + font_metrics_misc_info *misc_info; + rufl_code code; + + code = rufl_find_font_family(font_family, font_style, &font, + NULL, NULL); + if (code != rufl_OK) + return code; + + code = rufl_find_font(font, 16 /* 1pt */, NULL, &f); + if (code != rufl_OK) + return code; + + rufl_fm_error = xfont_read_font_metrics(f, 0, 0, 0, 0, 0, + 0, 0, 0, 0, &misc_size, 0); + if (rufl_fm_error) { + LOG("xfont_read_font_metrics: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + if (misc_size == 0) { + LOG("no miscellaneous information in metrics for %s", + rufl_font_list[font].identifier); + /** \todo better error code */ + return rufl_FONT_NOT_FOUND; + } + + misc_info = (font_metrics_misc_info *)malloc(misc_size); + if (!misc_info) + return rufl_OUT_OF_MEMORY; + + rufl_fm_error = xfont_read_font_metrics(f, 0, 0, 0, misc_info, 0, + 0, 0, 0, 0, 0, 0); + if (rufl_fm_error) { + LOG("xfont_read_font_metrics: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + free(misc_info); + return rufl_FONT_MANAGER_ERROR; + } + + /* and fill in output */ + if (bbox) { + bbox->x0 = misc_info->x0; + bbox->y0 = misc_info->y0; + bbox->x1 = misc_info->x1; + bbox->y1 = misc_info->y1; + } + + if (xkern) + (*xkern) = misc_info->xkern; + + if (ykern) + (*ykern) = misc_info->ykern; + + if (italic) + (*italic) = misc_info->italic_correction; + + if (ascent) + (*ascent) = misc_info->ascender; + + if (descent) + (*descent) = misc_info->descender; + + if (xheight) + (*xheight) = misc_info->xheight; + + if (cap_height) + (*cap_height) = misc_info->cap_height; + + if (uline_position) + (*uline_position) = misc_info->underline_position; + + if (uline_thickness) + (*uline_thickness) = misc_info->underline_thickness; + + free(misc_info); + + return rufl_OK; +} + +/** + * Read a glyph's metrics + */ +rufl_code rufl_glyph_metrics(const char *font_family, + rufl_style font_style, unsigned int font_size, + const char *string, size_t length, + int *x_bearing, int *y_bearing, + int *width, int *height, + int *x_advance, int *y_advance) +{ + const char *font_encoding = NULL; + unsigned int font, font1, u; + unsigned short u1[2]; + struct rufl_character_set *charset; + struct rufl_unicode_map_entry *umap_entry = NULL; + font_f f; + rufl_code code; + font_scan_block block; + font_string_flags flags; + int xa, ya; + + /* Find font family containing glyph */ + code = rufl_find_font_family(font_family, font_style, + &font, NULL, &charset); + if (code != rufl_OK) + return code; + + rufl_utf8_read(string, length, u); + if (charset && rufl_character_set_test(charset, u)) + font1 = font; + else if (u < 0x10000) + font1 = rufl_substitution_table[u]; + else + font1 = rufl_CACHE_CORPUS; + + /* Old font managers need the font encoding, too */ + if (rufl_old_font_manager && font1 != rufl_CACHE_CORPUS) { + unsigned int i; + unsigned short u16 = (unsigned short) u; + + for (i = 0; i < rufl_font_list[font1].num_umaps; i++) { + struct rufl_unicode_map *map = + rufl_font_list[font1].umap + i; + + umap_entry = bsearch(&u16, map->map, map->entries, + sizeof map->map[0], + rufl_unicode_map_search_cmp); + if (umap_entry) { + font_encoding = map->encoding; + break; + } + } + + assert(umap_entry != NULL); + } + + code = rufl_find_font(font1, font_size, font_encoding, &f); + if (code != rufl_OK) + return code; + + /* + * Glyph Metrics for horizontal text: + * + * ^ x0 x1 ¦ + * | ¦ ¦ ¦ Xbearing : x0 - oX + * | +-----+---¦----- y1 Ybearing : y1 - oY + * | | | ¦ Xadvance : aX - oX + * | | | ¦ Yadvance : 0 + * o---|-----|---a--> Glyph width : x1 - x0 + * | | | ¦ Glyph height : y1 - y0 + * | +-----+---¦----- y0 Right side bearing: aX - x1 + * | ¦ + * + * The rectangle (x0,y0),(x1,y1) is the glyph bounding box. + * + * Glyph Metrics for vertical text: + * + * -------o---------> + * y1--+--|--+ Xbearing : x0 - oX + * | | | Ybearing : oY - y1 + * | | | Xadvance : 0 + * | | | Yadvance : aY - oY + * | | | Glyph width : x1 - x0 + * y0--+-----+ Glyph height : y1 - y0 + * ----¦--a--¦--------- Right side bearing: N/A + * x0 v x1 + * + * The rectangle (x0,y0),(x1,y1) is the glyph bounding box. + * + * + * In order to extract the information we want from the + * Font Manager, a little bit of hackery is required. + * + * Firstly, we can take the origin as being (0,0). This is an + * arbitrary choice but makes the maths simpler. + * + * Secondly, the bounding box returned by Font_CharBBox / + * Font_ScanString / Font_StringBBox represents the ink area of + * the glyph (i.e. the smallest box needed to contain all the + * glyph path segments). This means that, for glyphs with no + * displayed content (such as a space), the bounding box will be 0. + * These SWIs therefore allow us to retrieve the (x0,y0),(x1,y1) + * coordinates marked in the diagrams above. + * + * Finally, we need to retrieve the glyph advance distance. This is + * returned in R3/R4 on exit from Font_ScanString (providing bit 17 + * of the flags word on entry is clear). It is important to note, + * however, that the height will be returned as 0 for fonts with no + * Yadvance values in the font data file. Therefore, in order to + * achieve vertical layout of text, further work will be needed + * (We're also ignoring the fact that the X coordinates of all + * values will be in the wrong place and the Y coordinates will have + * the wrong sign due to the differing definitions of the Y axis for + * horizontal and vertical text.) + * + * Note that all values (that we're interested in, at least) + * returned by the SWIs mentioned above are in _millipoints_. + */ + + block.space.x = block.space.y = 0; + block.letter.x = block.letter.y = 0; + block.split_char = -1; + + flags = font_GIVEN_BLOCK | font_GIVEN_LENGTH | font_GIVEN_FONT | + font_RETURN_BBOX; + + u1[0] = (unsigned short)u; + u1[1] = 0; + + if (font1 == rufl_CACHE_CORPUS) { + /* Fallback Glyph */ + /** \todo implement this properly */ + xa = 1000 * font_size; + ya = 0; + block.bbox.x0 = block.bbox.y0 = 0; + block.bbox.x1 = block.bbox.y1 = xa; + } else if (rufl_old_font_manager) { + /* Old Font Manager */ + char s[2]; + + /* We found the correct umap entry when + * looking for the font encoding */ + s[0] = umap_entry->c; + s[1] = 0; + + rufl_fm_error = xfont_scan_string(f, s, flags, + 0x7fffffff, 0x7fffffff, &block, 0, 1, + 0, &xa, &ya, 0); + if (rufl_fm_error) { + LOG("xfont_scan_string: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + } else { + /* UCS Font Manager */ + rufl_fm_error = xfont_scan_string(f, (const char *)u1, + flags | font_GIVEN16_BIT, + 0x7fffffff, 0x7fffffff, &block, 0, 2, + 0, &xa, &ya, 0); + if (rufl_fm_error) { + LOG("xfont_scan_string: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + } + + /** \todo handle vertical text */ + if (x_bearing) + (*x_bearing) = block.bbox.x0; + + if (y_bearing) + (*y_bearing) = block.bbox.y1; + + if (width) + (*width) = block.bbox.x1 - block.bbox.x0; + + if (height) + (*height) = block.bbox.y1 - block.bbox.y0; + + if (x_advance) + (*x_advance) = xa; + + if (y_advance) + (*y_advance) = ya; + + return rufl_OK; +} + + +int rufl_unicode_map_search_cmp(const void *keyval, const void *datum) +{ + const unsigned short *key = keyval; + const struct rufl_unicode_map_entry *entry = datum; + if (*key < entry->u) + return -1; + else if (entry->u < *key) + return 1; + return 0; +} diff --git a/src/rufl_paint.c b/src/rufl_paint.c new file mode 100644 index 0000000..8b9edf1 --- /dev/null +++ b/src/rufl_paint.c @@ -0,0 +1,621 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2006 James Bursa + */ + +#include +#include +#include +#include +#include +#include "oslib/font.h" +#include "rufl_internal.h" + + +typedef enum { rufl_PAINT, rufl_WIDTH, rufl_X_TO_OFFSET, + rufl_SPLIT, rufl_PAINT_CALLBACK, rufl_FONT_BBOX } rufl_action; +#define rufl_PROCESS_CHUNK 200 + +bool rufl_can_background_blend = false; + +static const os_trfm trfm_oblique = + { { { 65536, 0 }, { 13930, 65536 }, { 0, 0 } } }; + + +static rufl_code rufl_process(rufl_action action, + const char *font_family, rufl_style font_style, + unsigned int font_size, + const char *string0, size_t length, + int x, int y, unsigned int flags, + int *width, int click_x, size_t *char_offset, int *actual_x, + rufl_callback_t callback, void *context); +static rufl_code rufl_process_span(rufl_action action, + unsigned short *s, unsigned int n, + unsigned int font, unsigned int font_size, unsigned int slant, + int *x, int y, unsigned int flags, + int click_x, size_t *offset, + rufl_callback_t callback, void *context); +static rufl_code rufl_process_span_old(rufl_action action, + unsigned short *s, unsigned int n, + unsigned int font, unsigned int font_size, unsigned int slant, + int *x, int y, unsigned int flags, + int click_x, size_t *offset, + rufl_callback_t callback, void *context); +static int rufl_unicode_map_search_cmp(const void *keyval, const void *datum); +static rufl_code rufl_process_not_available(rufl_action action, + unsigned short *s, unsigned int n, + unsigned int font_size, int *x, int y, + unsigned int flags, + int click_x, size_t *offset, + rufl_callback_t callback, void *context); + + +/** + * Render Unicode text. + */ + +rufl_code rufl_paint(const char *font_family, rufl_style font_style, + unsigned int font_size, + const char *string, size_t length, + int x, int y, unsigned int flags) +{ + return rufl_process(rufl_PAINT, + font_family, font_style, font_size, string, + length, x, y, flags, 0, 0, 0, 0, 0, 0); +} + + +/** + * Measure the width of Unicode text. + */ + +rufl_code rufl_width(const char *font_family, rufl_style font_style, + unsigned int font_size, + const char *string, size_t length, + int *width) +{ + return rufl_process(rufl_WIDTH, + font_family, font_style, font_size, string, + length, 0, 0, 0, width, 0, 0, 0, 0, 0); +} + + +/** + * Find the nearest character boundary in a string to where an x coordinate + * falls. + */ + +rufl_code rufl_x_to_offset(const char *font_family, rufl_style font_style, + unsigned int font_size, + const char *string, size_t length, + int click_x, + size_t *char_offset, int *actual_x) +{ + return rufl_process(rufl_X_TO_OFFSET, + font_family, font_style, font_size, string, + length, 0, 0, 0, 0, + click_x, char_offset, actual_x, 0, 0); +} + + +/** + * Find the prefix of a string that will fit in a specified width. + */ + +rufl_code rufl_split(const char *font_family, rufl_style font_style, + unsigned int font_size, + const char *string, size_t length, + int width, + size_t *char_offset, int *actual_x) +{ + return rufl_process(rufl_SPLIT, + font_family, font_style, font_size, string, + length, 0, 0, 0, 0, + width, char_offset, actual_x, 0, 0); +} + + +/** + * Render text, but call a callback instead of each call to Font_Paint. + */ + +rufl_code rufl_paint_callback(const char *font_family, rufl_style font_style, + unsigned int font_size, + const char *string, size_t length, + int x, int y, + rufl_callback_t callback, void *context) +{ + return rufl_process(rufl_PAINT_CALLBACK, + font_family, font_style, font_size, string, + length, x, y, 0, 0, 0, 0, 0, callback, context); +} + + +/** + * Determine the maximum bounding box of a font. + */ + +rufl_code rufl_font_bbox(const char *font_family, rufl_style font_style, + unsigned int font_size, + int *bbox) +{ + return rufl_process(rufl_FONT_BBOX, + font_family, font_style, font_size, 0, + 0, 0, 0, 0, bbox, 0, 0, 0, 0, 0); +} + + +/** + * Render, measure, or split Unicode text. + */ + +rufl_code rufl_process(rufl_action action, + const char *font_family, rufl_style font_style, + unsigned int font_size, + const char *string0, size_t length, + int x, int y, unsigned int flags, + int *width, int click_x, size_t *char_offset, int *actual_x, + rufl_callback_t callback, void *context) +{ + unsigned short s[rufl_PROCESS_CHUNK]; + unsigned int font; + unsigned int font0, font1; + unsigned int n; + unsigned int u; + size_t offset; + size_t offset_u; + size_t offset_map[rufl_PROCESS_CHUNK]; + unsigned int slant; + const char *string = string0; + struct rufl_character_set *charset; + rufl_code code; + + assert(action == rufl_PAINT || + (action == rufl_WIDTH && width) || + (action == rufl_X_TO_OFFSET && char_offset && + actual_x) || + (action == rufl_SPLIT && char_offset && + actual_x) || + (action == rufl_PAINT_CALLBACK && callback) || + (action == rufl_FONT_BBOX && width)); + + if ((flags & rufl_BLEND_FONT) && !rufl_can_background_blend) { + /* unsuitable FM => clear blending bit */ + flags &= ~rufl_BLEND_FONT; + } + + if (length == 0 && action != rufl_FONT_BBOX) { + if (action == rufl_WIDTH) + *width = 0; + else if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { + *char_offset = 0; + *actual_x = 0; + } + return rufl_OK; + } + if ((action == rufl_X_TO_OFFSET || action == rufl_SPLIT) && + click_x <= 0) { + *char_offset = 0; + *actual_x = 0; + return rufl_OK; + } + + code = rufl_find_font_family(font_family, font_style, + &font, &slant, &charset); + if (code != rufl_OK) + return code; + + if (action == rufl_FONT_BBOX) { + if (rufl_old_font_manager) + code = rufl_process_span_old(action, 0, 0, font, + font_size, slant, width, 0, 0, + 0, 0, 0, 0); + else + code = rufl_process_span(action, 0, 0, font, + font_size, slant, width, 0, 0, + 0, 0, 0, 0); + return code; + } + + offset_u = 0; + rufl_utf8_read(string, length, u); + if (u <= 0x001f || (0x007f <= u && u <= 0x009f)) + font1 = NOT_AVAILABLE; + else if (charset && rufl_character_set_test(charset, u)) + font1 = font; + else if (u < 0x10000) + font1 = rufl_substitution_table[u]; + else + font1 = NOT_AVAILABLE; + do { + s[0] = u; + offset_map[0] = offset_u; + n = 1; + font0 = font1; + /* invariant: s[0..n) is in font font0 */ + while (0 < length && n < rufl_PROCESS_CHUNK && font1 == font0) { + offset_u = string - string0; + rufl_utf8_read(string, length, u); + s[n] = u; + offset_map[n] = offset_u; + if (u <= 0x001f || (0x007f <= u && u <= 0x009f)) + font1 = NOT_AVAILABLE; + else if (charset && rufl_character_set_test(charset, u)) + font1 = font; + else if (u < 0x10000) + font1 = rufl_substitution_table[u]; + else + font1 = NOT_AVAILABLE; + if (font1 == font0) + n++; + } + if (n == rufl_PROCESS_CHUNK) + n--; + s[n] = 0; + offset_map[n] = offset_u; + if (length == 0 && font1 == font0) + offset_map[n] = string - string0; + + if (font0 == NOT_AVAILABLE) + code = rufl_process_not_available(action, s, n, + font_size, &x, y, flags, + click_x, &offset, callback, context); + else if (rufl_old_font_manager) + code = rufl_process_span_old(action, s, n, font0, + font_size, slant, &x, y, flags, + click_x, &offset, callback, context); + else + code = rufl_process_span(action, s, n, font0, + font_size, slant, &x, y, flags, + click_x, &offset, callback, context); + + if ((action == rufl_X_TO_OFFSET || action == rufl_SPLIT) && + (offset < n || click_x < x)) + break; + if (code != rufl_OK) + return code; + + } while (!(length == 0 && font1 == font0)); + + if (action == rufl_WIDTH) + *width = x; + else if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { + *char_offset = offset_map[offset]; + *actual_x = x; + } + + return rufl_OK; +} + + +/** + * Render a string of characters from a single RISC OS font. + */ + +rufl_code rufl_process_span(rufl_action action, + unsigned short *s, unsigned int n, + unsigned int font, unsigned int font_size, unsigned int slant, + int *x, int y, unsigned int flags, + int click_x, size_t *offset, + rufl_callback_t callback, void *context) +{ + unsigned short *split_point; + int x_out, y_out; + unsigned int i; + char font_name[80]; + bool oblique = slant && !rufl_font_list[font].slant; + font_f f; + rufl_code code; + + code = rufl_find_font(font, font_size, "UTF8", &f); + if (code != rufl_OK) + return code; + + if (action == rufl_FONT_BBOX) { + rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]); + if (rufl_fm_error) + return rufl_FONT_MANAGER_ERROR; + return rufl_OK; + } + + if (action == rufl_PAINT) { + /* paint span */ + rufl_fm_error = xfont_paint(f, (const char *) s, + font_OS_UNITS | + (oblique ? font_GIVEN_TRFM : 0) | + font_GIVEN_LENGTH | + font_GIVEN_FONT | font_KERN | + font_GIVEN16_BIT | + ((flags & rufl_BLEND_FONT) ? + font_BLEND_FONT : 0), + *x, y, 0, &trfm_oblique, n * 2); + if (rufl_fm_error) { + LOG("xfont_paint: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + for (i = 0; i != n; i++) + fprintf(stderr, "0x%x ", s[i]); + fprintf(stderr, " (%u)\n", n); + return rufl_FONT_MANAGER_ERROR; + } + } else if (action == rufl_PAINT_CALLBACK) { + snprintf(font_name, sizeof font_name, "%s\\EUTF8", + rufl_font_list[font].identifier); + callback(context, font_name, font_size, 0, s, n, *x, y); + } + + /* increment x by width of span */ + if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { + rufl_fm_error = xfont_scan_string(f, (const char *) s, + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN | font_GIVEN16_BIT | + ((action == rufl_X_TO_OFFSET) ? + font_RETURN_CARET_POS : 0), + (click_x - *x) * 400, 0x7fffffff, 0, 0, + n * 2, + (char **)(void *)&split_point, + &x_out, &y_out, 0); + *offset = split_point - s; + } else { + rufl_fm_error = xfont_scan_string(f, (const char *) s, + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN | font_GIVEN16_BIT, + 0x7fffffff, 0x7fffffff, 0, 0, n * 2, + 0, &x_out, &y_out, 0); + } + if (rufl_fm_error) { + LOG("xfont_scan_string: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + *x += x_out / 400; + + return rufl_OK; +} + + +/** + * Render a string of characters from a single RISC OS font (old font manager + * version). + */ + +rufl_code rufl_process_span_old(rufl_action action, + unsigned short *s, unsigned int n, + unsigned int font, unsigned int font_size, unsigned int slant, + int *x, int y, unsigned int flags, + int click_x, size_t *offset, + rufl_callback_t callback, void *context) +{ + char s2[rufl_PROCESS_CHUNK]; + char *split_point; + int x_out, y_out; + unsigned int i; + bool oblique = slant && !rufl_font_list[font].slant; + font_f f; + rufl_code code; + + if (action == rufl_FONT_BBOX) { + /* Don't need encoding for bounding box */ + code = rufl_find_font(font, font_size, NULL, &f); + if (code != rufl_OK) + return code; + + rufl_fm_error = xfont_read_info(f, &x[0], &x[1], &x[2], &x[3]); + if (rufl_fm_error) { + LOG("xfont_read_info: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + return rufl_OK; + } + + if (offset) + *offset = 0; + + /* Process the span in map-coherent chunks */ + do { + struct rufl_unicode_map *map = NULL; + struct rufl_unicode_map_entry *entry = NULL; + unsigned int j; + + i = 0; + + /* Find map for first character */ + for (j = 0; j < rufl_font_list[font].num_umaps; j++) { + map = rufl_font_list[font].umap + j; + + entry = bsearch(&s[i], map->map, map->entries, + sizeof map->map[0], + rufl_unicode_map_search_cmp); + if (entry) + break; + } + assert(map != NULL); + assert(entry != NULL); + + /* Collect characters: s[0..i) use map */ + do { + entry = bsearch(&s[i], map->map, map->entries, + sizeof map->map[0], + rufl_unicode_map_search_cmp); + + if (entry) + s2[i++] = entry->c; + } while (i != n && entry != NULL); + + s2[i] = 0; + + code = rufl_find_font(font, font_size, map->encoding, &f); + if (code != rufl_OK) + return code; + + if (action == rufl_PAINT) { + /* paint span */ + /* call Font_SetFont to work around broken PS printer + * driver, which doesn't use the font handle from + * Font_Paint */ + rufl_fm_error = xfont_set_font(f); + if (rufl_fm_error) { + LOG("xfont_set_font: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + + rufl_fm_error = xfont_paint(f, s2, font_OS_UNITS | + (oblique ? font_GIVEN_TRFM : 0) | + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN | + ((flags & rufl_BLEND_FONT) ? + font_BLEND_FONT : 0), + *x, y, 0, &trfm_oblique, i); + if (rufl_fm_error) { + LOG("xfont_paint: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + } else if (action == rufl_PAINT_CALLBACK) { + char font_name[80]; + + if (map->encoding) + snprintf(font_name, sizeof font_name, "%s\\E%s", + rufl_font_list[font].identifier, + map->encoding); + else + snprintf(font_name, sizeof font_name, "%s", + rufl_font_list[font].identifier); + + callback(context, font_name, font_size, + s2, 0, i, *x, y); + } + + /* increment x by width of span */ + if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { + rufl_fm_error = xfont_scan_string(f, s2, + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN | + ((action == rufl_X_TO_OFFSET) ? + font_RETURN_CARET_POS : 0), + (click_x - *x) * 400, 0x7fffffff, + 0, 0, i, + &split_point, &x_out, &y_out, 0); + *offset += split_point - s2; + } else { + rufl_fm_error = xfont_scan_string(f, s2, + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN, + 0x7fffffff, 0x7fffffff, 0, 0, i, + 0, &x_out, &y_out, 0); + } + if (rufl_fm_error) { + LOG("xfont_scan_string: 0x%x: %s", + rufl_fm_error->errnum, + rufl_fm_error->errmess); + return rufl_FONT_MANAGER_ERROR; + } + *x += x_out / 400; + + /* Now update s and n for the next chunk */ + s += i; + n -= i; + } while (n != 0); + + return rufl_OK; +} + + +int rufl_unicode_map_search_cmp(const void *keyval, const void *datum) +{ + const unsigned short *key = keyval; + const struct rufl_unicode_map_entry *entry = datum; + if (*key < entry->u) + return -1; + else if (entry->u < *key) + return 1; + return 0; +} + + +/** + * Render a string of characters not available in any font as their hex code. + */ + +rufl_code rufl_process_not_available(rufl_action action, + unsigned short *s, unsigned int n, + unsigned int font_size, int *x, int y, + unsigned int flags, + int click_x, size_t *offset, + rufl_callback_t callback, void *context) +{ + char missing[] = "0000"; + int dx = 7 * font_size / 64; + int top_y = y + 5 * font_size / 64; + unsigned int i; + font_f f; + rufl_code code; + + if (action == rufl_WIDTH) { + *x += n * dx; + return rufl_OK; + } else if (action == rufl_X_TO_OFFSET || action == rufl_SPLIT) { + if (click_x - *x < (int) (n * dx)) + *offset = (click_x - *x) / dx; + else + *offset = n; + *x += *offset * dx; + return rufl_OK; + } + + code = rufl_find_font(rufl_CACHE_CORPUS, font_size / 2, "Latin1", &f); + if (code != rufl_OK) + return code; + + for (i = 0; i != n; i++) { + missing[0] = "0123456789abcdef"[(s[i] >> 12) & 0xf]; + missing[1] = "0123456789abcdef"[(s[i] >> 8) & 0xf]; + missing[2] = "0123456789abcdef"[(s[i] >> 4) & 0xf]; + missing[3] = "0123456789abcdef"[(s[i] >> 0) & 0xf]; + + /* first two characters in top row */ + if (action == rufl_PAINT) { + rufl_fm_error = xfont_paint(f, missing, font_OS_UNITS | + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN | + ((flags & rufl_BLEND_FONT) ? + font_BLEND_FONT : 0), + *x, top_y, 0, 0, 2); + if (rufl_fm_error) + return rufl_FONT_MANAGER_ERROR; + } else { + callback(context, "Corpus.Medium\\ELatin1", + font_size / 2, missing, 0, 2, + *x, top_y); + } + + /* last two characters underneath */ + if (action == rufl_PAINT) { + rufl_fm_error = xfont_paint(f, missing + 2, + font_OS_UNITS | + font_GIVEN_LENGTH | font_GIVEN_FONT | + font_KERN | + ((flags & rufl_BLEND_FONT) ? + font_BLEND_FONT : 0), + *x, y, 0, 0, 2); + if (rufl_fm_error) + return rufl_FONT_MANAGER_ERROR; + } else { + callback(context, "Corpus.Medium\\ELatin1", + font_size / 2, missing + 2, 0, 2, + *x, y); + } + + *x += dx; + } + + return rufl_OK; +} diff --git a/src/rufl_quit.c b/src/rufl_quit.c new file mode 100644 index 0000000..fc429c0 --- /dev/null +++ b/src/rufl_quit.c @@ -0,0 +1,49 @@ +/* + * This file is part of RUfl + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license + * Copyright 2006 James Bursa + */ + +#include +#include "oslib/font.h" +#include "rufl_internal.h" + + +/** + * Free all resources used by the library. + */ + +void rufl_quit(void) +{ + unsigned int i; + + if (!rufl_font_list) + return; + + for (i = 0; i != rufl_font_list_entries; i++) { + free(rufl_font_list[i].identifier); + free(rufl_font_list[i].charset); + } + free(rufl_font_list); + rufl_font_list = 0; + + for (i = 0; i != rufl_family_list_entries; i++) + free((void *) rufl_family_list[i]); + free(rufl_family_list); + free(rufl_family_map); + rufl_family_list = 0; + + for (i = 0; i != rufl_CACHE_SIZE; i++) { + if (rufl_cache[i].font != rufl_CACHE_NONE) { + xfont_lose_font(rufl_cache[i].f); + rufl_cache[i].font = rufl_CACHE_NONE; + } + } + + free(rufl_family_menu); + rufl_family_menu = 0; + + free(rufl_substitution_table); + rufl_substitution_table = 0; +} diff --git a/src/strfuncs.c b/src/strfuncs.c new file mode 100644 index 0000000..08b43b2 --- /dev/null +++ b/src/strfuncs.c @@ -0,0 +1,37 @@ +#include +#include +#include + +#include "strfuncs.h" + +char *strdup(const char *s) +{ + size_t len = strlen(s); + char *new = malloc(len + 1); + if (!new) + return 0; + memcpy(new, s, len); + new[len] = '\0'; + return new; +} + +char *strndup(const char *s, size_t n) +{ + size_t len = strlen(s); + if (n < len) + len = n; + char *new = malloc(len + 1); + if (!new) + return 0; + memcpy(new, s, len); + new[len] = '\0'; + return new; +} + +int strcasecmp(const char *s1, const char *s2) +{ + int i; + while ((i = tolower(*s1)) && i == tolower(*s2)) + s1++, s2++; + return ((unsigned char) tolower(*s1) - (unsigned char) tolower(*s2)); +} diff --git a/src/strfuncs.h b/src/strfuncs.h new file mode 100644 index 0000000..495ea98 --- /dev/null +++ b/src/strfuncs.h @@ -0,0 +1,5 @@ +#include + +char *strdup(const char *s); +char *strndup(const char *s, size_t n); +int strcasecmp(const char *s1, const char *s2); -- cgit v1.2.3