summaryrefslogtreecommitdiff
path: root/vcl/unx/source/fontmanager
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/source/fontmanager')
-rw-r--r--vcl/unx/source/fontmanager/adobeenc.tab1090
-rwxr-xr-xvcl/unx/source/fontmanager/afm_hash.cpp245
-rwxr-xr-xvcl/unx/source/fontmanager/afm_keyword_list58
-rw-r--r--vcl/unx/source/fontmanager/fontcache.cxx821
-rw-r--r--vcl/unx/source/fontmanager/fontconfig.cxx1078
-rw-r--r--vcl/unx/source/fontmanager/fontmanager.cxx4008
-rw-r--r--vcl/unx/source/fontmanager/helper.cxx407
-rw-r--r--vcl/unx/source/fontmanager/makefile.mk76
-rw-r--r--vcl/unx/source/fontmanager/parseAFM.cxx1569
-rw-r--r--vcl/unx/source/fontmanager/parseAFM.hxx344
10 files changed, 9696 insertions, 0 deletions
diff --git a/vcl/unx/source/fontmanager/adobeenc.tab b/vcl/unx/source/fontmanager/adobeenc.tab
new file mode 100644
index 000000000000..e4005a87849f
--- /dev/null
+++ b/vcl/unx/source/fontmanager/adobeenc.tab
@@ -0,0 +1,1090 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: adobeenc.tab,v $
+ * $Revision: 1.4 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+struct AdobeEncEntry {
+ sal_Unicode aUnicode;
+ sal_uInt8 aAdobeStandardCode;
+ const char* const pAdobename;
+};
+
+static const AdobeEncEntry aAdobeCodes[]=
+{
+ { 0x0041, 0101, "A" },
+ { 0x00C6, 0341, "AE" },
+ { 0x01FC, 0, "AEacute" },
+ { 0xF7E6, 0, "AEsmall" },
+ { 0x00C1, 0, "Aacute" },
+ { 0xF7E1, 0, "Aacutesmall" },
+ { 0x0102, 0, "Abreve" },
+ { 0x00C2, 0, "Acircumflex" },
+ { 0xF7E2, 0, "Acircumflexsmall" },
+ { 0xF6C9, 0, "Acute" },
+ { 0xF7B4, 0, "Acutesmall" },
+ { 0x00C4, 0, "Adieresis" },
+ { 0xF7E4, 0, "Adieresissmall" },
+ { 0x00C0, 0, "Agrave" },
+ { 0xF7E0, 0, "Agravesmall" },
+ { 0x0391, 0, "Alpha" },
+ { 0x0386, 0, "Alphatonos" },
+ { 0x0100, 0, "Amacron" },
+ { 0x0104, 0, "Aogonek" },
+ { 0x00C5, 0, "Aring" },
+ { 0x01FA, 0, "Aringacute" },
+ { 0xF7E5, 0, "Aringsmall" },
+ { 0xF761, 0, "Asmall" },
+ { 0x00C3, 0, "Atilde" },
+ { 0xF7E3, 0, "Atildesmall" },
+ { 0x0042, 0102, "B" },
+ { 0x0392, 0, "Beta" },
+ { 0xF6F4, 0, "Brevesmall" },
+ { 0xF762, 0, "Bsmall" },
+ { 0x0043, 0103, "C" },
+ { 0x0106, 0, "Cacute" },
+ { 0xF6CA, 0, "Caron" },
+ { 0xF6F5, 0, "Caronsmall" },
+ { 0x010C, 0, "Ccaron" },
+ { 0x00C7, 0, "Ccedilla" },
+ { 0xF7E7, 0, "Ccedillasmall" },
+ { 0x0108, 0, "Ccircumflex" },
+ { 0x010A, 0, "Cdotaccent" },
+ { 0xF7B8, 0, "Cedillasmall" },
+ { 0x03A7, 0, "Chi" },
+ { 0xF6F6, 0, "Circumflexsmall" },
+ { 0xF763, 0, "Csmall" },
+ { 0x0044, 0104, "D" },
+ { 0x010E, 0, "Dcaron" },
+ { 0x0110, 0, "Dcroat" },
+ { 0x2206, 0, "Delta" },
+ { 0x0394, 0, "Delta" },
+ { 0xF6CB, 0, "Dieresis" },
+ { 0xF6CC, 0, "DieresisAcute" },
+ { 0xF6CD, 0, "DieresisGrave" },
+ { 0xF7A8, 0, "Dieresissmall" },
+ { 0xF6F7, 0, "Dotaccentsmall" },
+ { 0xF764, 0, "Dsmall" },
+ { 0x0045, 0105, "E" },
+ { 0x00C9, 0, "Eacute" },
+ { 0xF7E9, 0, "Eacutesmall" },
+ { 0x0114, 0, "Ebreve" },
+ { 0x011A, 0, "Ecaron" },
+ { 0x00CA, 0, "Ecircumflex" },
+ { 0xF7EA, 0, "Ecircumflexsmall" },
+ { 0x00CB, 0, "Edieresis" },
+ { 0xF7EB, 0, "Edieresissmall" },
+ { 0x0116, 0, "Edotaccent" },
+ { 0x00C8, 0, "Egrave" },
+ { 0xF7E8, 0, "Egravesmall" },
+ { 0x0112, 0, "Emacron" },
+ { 0x014A, 0, "Eng" },
+ { 0x0118, 0, "Eogonek" },
+ { 0x0395, 0, "Epsilon" },
+ { 0x0388, 0, "Epsilontonos" },
+ { 0xF765, 0, "Esmall" },
+ { 0x0397, 0, "Eta" },
+ { 0x0389, 0, "Etatonos" },
+ { 0x00D0, 0, "Eth" },
+ { 0xF7F0, 0, "Ethsmall" },
+ { 0x20AC, 0, "Euro" },
+ { 0x0046, 0106, "F" },
+ { 0xF766, 0, "Fsmall" },
+ { 0x0047, 0107, "G" },
+ { 0x0393, 0, "Gamma" },
+ { 0x011E, 0, "Gbreve" },
+ { 0x01E6, 0, "Gcaron" },
+ { 0x011C, 0, "Gcircumflex" },
+ { 0x0122, 0, "Gcommaaccent" },
+ { 0x0120, 0, "Gdotaccent" },
+ { 0xF6CE, 0, "Grave" },
+ { 0xF760, 0, "Gravesmall" },
+ { 0xF767, 0, "Gsmall" },
+ { 0x0048, 0110, "H" },
+ { 0x25CF, 0, "H18533" },
+ { 0x25AA, 0, "H18543" },
+ { 0x25AB, 0, "H18551" },
+ { 0x25A1, 0, "H22073" },
+ { 0x0126, 0, "Hbar" },
+ { 0x0124, 0, "Hcircumflex" },
+ { 0xF768, 0, "Hsmall" },
+ { 0xF6CF, 0, "Hungarumlaut" },
+ { 0xF6F8, 0, "Hungarumlautsmall" },
+ { 0x0049, 0111, "I" },
+ { 0x0132, 0, "IJ" },
+ { 0x00CD, 0, "Iacute" },
+ { 0xF7ED, 0, "Iacutesmall" },
+ { 0x012C, 0, "Ibreve" },
+ { 0x00CE, 0, "Icircumflex" },
+ { 0xF7EE, 0, "Icircumflexsmall" },
+ { 0x00CF, 0, "Idieresis" },
+ { 0xF7EF, 0, "Idieresissmall" },
+ { 0x0130, 0, "Idotaccent" },
+ { 0x2111, 0, "Ifraktur" },
+ { 0x00CC, 0, "Igrave" },
+ { 0xF7EC, 0, "Igravesmall" },
+ { 0x012A, 0, "Imacron" },
+ { 0x012E, 0, "Iogonek" },
+ { 0x0399, 0, "Iota" },
+ { 0x03AA, 0, "Iotadieresis" },
+ { 0x038A, 0, "Iotatonos" },
+ { 0xF769, 0, "Ismall" },
+ { 0x0128, 0, "Itilde" },
+ { 0x004A, 0112, "J" },
+ { 0x0134, 0, "Jcircumflex" },
+ { 0xF76A, 0, "Jsmall" },
+ { 0x004B, 0113, "K" },
+ { 0x039A, 0, "Kappa" },
+ { 0x0136, 0, "Kcommaaccent" },
+ { 0xF76B, 0, "Ksmall" },
+ { 0x004C, 0114, "L" },
+ { 0xF6BF, 0, "LL" },
+ { 0x0139, 0, "Lacute" },
+ { 0x039B, 0, "Lambda" },
+ { 0x013D, 0, "Lcaron" },
+ { 0x013B, 0, "Lcommaaccent" },
+ { 0x013F, 0, "Ldot" },
+ { 0x0141, 0350, "Lslash" },
+ { 0xF6F9, 0, "Lslashsmall" },
+ { 0xF76C, 0, "Lsmall" },
+ { 0x004D, 0115, "M" },
+ { 0xF6D0, 0, "Macron" },
+ { 0xF7AF, 0, "Macronsmall" },
+ { 0xF76D, 0, "Msmall" },
+ { 0x039C, 0, "Mu" },
+ { 0x004E, 0116, "N" },
+ { 0x0143, 0, "Nacute" },
+ { 0x0147, 0, "Ncaron" },
+ { 0x0145, 0, "Ncommaaccent" },
+ { 0xF76E, 0, "Nsmall" },
+ { 0x00D1, 0, "Ntilde" },
+ { 0xF7F1, 0, "Ntildesmall" },
+ { 0x039D, 0, "Nu" },
+ { 0x004F, 0117, "O" },
+ { 0x0152, 0, "OE" },
+ { 0xF6FA, 0, "OEsmall" },
+ { 0x00D3, 0, "Oacute" },
+ { 0xF7F3, 0, "Oacutesmall" },
+ { 0x014E, 0, "Obreve" },
+ { 0x00D4, 0, "Ocircumflex" },
+ { 0xF7F4, 0, "Ocircumflexsmall" },
+ { 0x00D6, 0, "Odieresis" },
+ { 0xF7F6, 0, "Odieresissmall" },
+ { 0xF6FB, 0, "Ogoneksmall" },
+ { 0x00D2, 0, "Ograve" },
+ { 0xF7F2, 0, "Ogravesmall" },
+ { 0x01A0, 0, "Ohorn" },
+ { 0x0150, 0, "Ohungarumlaut" },
+ { 0x014C, 0, "Omacron" },
+ { 0x2126, 0, "Omega" },
+ { 0x03A9, 0, "Omega" },
+ { 0x038F, 0, "Omegatonos" },
+ { 0x039F, 0, "Omicron" },
+ { 0x038C, 0, "Omicrontonos" },
+ { 0x00D8, 0351, "Oslash" },
+ { 0x01FE, 0, "Oslashacute" },
+ { 0xF7F8, 0, "Oslashsmall" },
+ { 0xF76F, 0, "Osmall" },
+ { 0x00D5, 0, "Otilde" },
+ { 0xF7F5, 0, "Otildesmall" },
+ { 0x0050, 0120, "P" },
+ { 0x03A6, 0, "Phi" },
+ { 0x03A0, 0, "Pi" },
+ { 0x03A8, 0, "Psi" },
+ { 0xF770, 0, "Psmall" },
+ { 0x0051, 0121, "Q" },
+ { 0xF771, 0, "Qsmall" },
+ { 0x0052, 0122, "R" },
+ { 0x0154, 0, "Racute" },
+ { 0x0158, 0, "Rcaron" },
+ { 0x0156, 0, "Rcommaaccent" },
+ { 0x211C, 0, "Rfraktur" },
+ { 0x03A1, 0, "Rho" },
+ { 0xF6FC, 0, "Ringsmall" },
+ { 0xF772, 0, "Rsmall" },
+ { 0x0053, 0123, "S" },
+ { 0x250C, 0, "SF010000" },
+ { 0x2514, 0, "SF020000" },
+ { 0x2510, 0, "SF030000" },
+ { 0x2518, 0, "SF040000" },
+ { 0x253C, 0, "SF050000" },
+ { 0x252C, 0, "SF060000" },
+ { 0x2534, 0, "SF070000" },
+ { 0x251C, 0, "SF080000" },
+ { 0x2524, 0, "SF090000" },
+ { 0x2500, 0, "SF100000" },
+ { 0x2502, 0, "SF110000" },
+ { 0x2561, 0, "SF190000" },
+ { 0x2562, 0, "SF200000" },
+ { 0x2556, 0, "SF210000" },
+ { 0x2555, 0, "SF220000" },
+ { 0x2563, 0, "SF230000" },
+ { 0x2551, 0, "SF240000" },
+ { 0x2557, 0, "SF250000" },
+ { 0x255D, 0, "SF260000" },
+ { 0x255C, 0, "SF270000" },
+ { 0x255B, 0, "SF280000" },
+ { 0x255E, 0, "SF360000" },
+ { 0x255F, 0, "SF370000" },
+ { 0x255A, 0, "SF380000" },
+ { 0x2554, 0, "SF390000" },
+ { 0x2569, 0, "SF400000" },
+ { 0x2566, 0, "SF410000" },
+ { 0x2560, 0, "SF420000" },
+ { 0x2550, 0, "SF430000" },
+ { 0x256C, 0, "SF440000" },
+ { 0x2567, 0, "SF450000" },
+ { 0x2568, 0, "SF460000" },
+ { 0x2564, 0, "SF470000" },
+ { 0x2565, 0, "SF480000" },
+ { 0x2559, 0, "SF490000" },
+ { 0x2558, 0, "SF500000" },
+ { 0x2552, 0, "SF510000" },
+ { 0x2553, 0, "SF520000" },
+ { 0x256B, 0, "SF530000" },
+ { 0x256A, 0, "SF540000" },
+ { 0x015A, 0, "Sacute" },
+ { 0x0160, 0, "Scaron" },
+ { 0xF6FD, 0, "Scaronsmall" },
+ { 0x015E, 0, "Scedilla" },
+ { 0xF6C1, 0, "Scedilla" },
+ { 0x015C, 0, "Scircumflex" },
+ { 0x0218, 0, "Scommaaccent" },
+ { 0x03A3, 0, "Sigma" },
+ { 0xF773, 0, "Ssmall" },
+ { 0x0054, 0124, "T" },
+ { 0x03A4, 0, "Tau" },
+ { 0x0166, 0, "Tbar" },
+ { 0x0164, 0, "Tcaron" },
+ { 0x0162, 0, "Tcommaaccent" },
+ { 0x021A, 0, "Tcommaaccent" },
+ { 0x0398, 0, "Theta" },
+ { 0x00DE, 0, "Thorn" },
+ { 0xF7FE, 0, "Thornsmall" },
+ { 0xF6FE, 0, "Tildesmall" },
+ { 0xF774, 0, "Tsmall" },
+ { 0x0055, 0125, "U" },
+ { 0x00DA, 0, "Uacute" },
+ { 0xF7FA, 0, "Uacutesmall" },
+ { 0x016C, 0, "Ubreve" },
+ { 0x00DB, 0, "Ucircumflex" },
+ { 0xF7FB, 0, "Ucircumflexsmall" },
+ { 0x00DC, 0, "Udieresis" },
+ { 0xF7FC, 0, "Udieresissmall" },
+ { 0x00D9, 0, "Ugrave" },
+ { 0xF7F9, 0, "Ugravesmall" },
+ { 0x01AF, 0, "Uhorn" },
+ { 0x0170, 0, "Uhungarumlaut" },
+ { 0x016A, 0, "Umacron" },
+ { 0x0172, 0, "Uogonek" },
+ { 0x03A5, 0, "Upsilon" },
+ { 0x03D2, 0, "Upsilon1" },
+ { 0x03AB, 0, "Upsilondieresis" },
+ { 0x038E, 0, "Upsilontonos" },
+ { 0x016E, 0, "Uring" },
+ { 0xF775, 0, "Usmall" },
+ { 0x0168, 0, "Utilde" },
+ { 0x0056, 0126, "V" },
+ { 0xF776, 0, "Vsmall" },
+ { 0x0057, 0127, "W" },
+ { 0x1E82, 0, "Wacute" },
+ { 0x0174, 0, "Wcircumflex" },
+ { 0x1E84, 0, "Wdieresis" },
+ { 0x1E80, 0, "Wgrave" },
+ { 0xF777, 0, "Wsmall" },
+ { 0x0058, 0130, "X" },
+ { 0x039E, 0, "Xi" },
+ { 0xF778, 0, "Xsmall" },
+ { 0x0059, 0131, "Y" },
+ { 0x00DD, 0, "Yacute" },
+ { 0xF7FD, 0, "Yacutesmall" },
+ { 0x0176, 0, "Ycircumflex" },
+ { 0x0178, 0, "Ydieresis" },
+ { 0xF7FF, 0, "Ydieresissmall" },
+ { 0x1EF2, 0, "Ygrave" },
+ { 0xF779, 0, "Ysmall" },
+ { 0x005A, 0132, "Z" },
+ { 0x0179, 0, "Zacute" },
+ { 0x017D, 0, "Zcaron" },
+ { 0xF6FF, 0, "Zcaronsmall" },
+ { 0x017B, 0, "Zdotaccent" },
+ { 0x0396, 0, "Zeta" },
+ { 0xF77A, 0, "Zsmall" },
+ { 0x0061, 0141, "a" },
+ { 0x00E1, 0, "aacute" },
+ { 0x0103, 0, "abreve" },
+ { 0x00E2, 0, "acircumflex" },
+ { 0x00B4, 0302, "acute" },
+ { 0x0301, 0, "acutecomb" },
+ { 0x00E4, 0, "adieresis" },
+ { 0x00E6, 0361, "ae" },
+ { 0x01FD, 0, "aeacute" },
+ { 0x2015, 0, "afii00208" },
+ { 0x0410, 0, "afii10017" },
+ { 0x0411, 0, "afii10018" },
+ { 0x0412, 0, "afii10019" },
+ { 0x0413, 0, "afii10020" },
+ { 0x0414, 0, "afii10021" },
+ { 0x0415, 0, "afii10022" },
+ { 0x0401, 0, "afii10023" },
+ { 0x0416, 0, "afii10024" },
+ { 0x0417, 0, "afii10025" },
+ { 0x0418, 0, "afii10026" },
+ { 0x0419, 0, "afii10027" },
+ { 0x041A, 0, "afii10028" },
+ { 0x041B, 0, "afii10029" },
+ { 0x041C, 0, "afii10030" },
+ { 0x041D, 0, "afii10031" },
+ { 0x041E, 0, "afii10032" },
+ { 0x041F, 0, "afii10033" },
+ { 0x0420, 0, "afii10034" },
+ { 0x0421, 0, "afii10035" },
+ { 0x0422, 0, "afii10036" },
+ { 0x0423, 0, "afii10037" },
+ { 0x0424, 0, "afii10038" },
+ { 0x0425, 0, "afii10039" },
+ { 0x0426, 0, "afii10040" },
+ { 0x0427, 0, "afii10041" },
+ { 0x0428, 0, "afii10042" },
+ { 0x0429, 0, "afii10043" },
+ { 0x042A, 0, "afii10044" },
+ { 0x042B, 0, "afii10045" },
+ { 0x042C, 0, "afii10046" },
+ { 0x042D, 0, "afii10047" },
+ { 0x042E, 0, "afii10048" },
+ { 0x042F, 0, "afii10049" },
+ { 0x0490, 0, "afii10050" },
+ { 0x0402, 0, "afii10051" },
+ { 0x0403, 0, "afii10052" },
+ { 0x0404, 0, "afii10053" },
+ { 0x0405, 0, "afii10054" },
+ { 0x0406, 0, "afii10055" },
+ { 0x0407, 0, "afii10056" },
+ { 0x0408, 0, "afii10057" },
+ { 0x0409, 0, "afii10058" },
+ { 0x040A, 0, "afii10059" },
+ { 0x040B, 0, "afii10060" },
+ { 0x040C, 0, "afii10061" },
+ { 0x040E, 0, "afii10062" },
+ { 0xF6C4, 0, "afii10063" },
+ { 0xF6C5, 0, "afii10064" },
+ { 0x0430, 0, "afii10065" },
+ { 0x0431, 0, "afii10066" },
+ { 0x0432, 0, "afii10067" },
+ { 0x0433, 0, "afii10068" },
+ { 0x0434, 0, "afii10069" },
+ { 0x0435, 0, "afii10070" },
+ { 0x0451, 0, "afii10071" },
+ { 0x0436, 0, "afii10072" },
+ { 0x0437, 0, "afii10073" },
+ { 0x0438, 0, "afii10074" },
+ { 0x0439, 0, "afii10075" },
+ { 0x043A, 0, "afii10076" },
+ { 0x043B, 0, "afii10077" },
+ { 0x043C, 0, "afii10078" },
+ { 0x043D, 0, "afii10079" },
+ { 0x043E, 0, "afii10080" },
+ { 0x043F, 0, "afii10081" },
+ { 0x0440, 0, "afii10082" },
+ { 0x0441, 0, "afii10083" },
+ { 0x0442, 0, "afii10084" },
+ { 0x0443, 0, "afii10085" },
+ { 0x0444, 0, "afii10086" },
+ { 0x0445, 0, "afii10087" },
+ { 0x0446, 0, "afii10088" },
+ { 0x0447, 0, "afii10089" },
+ { 0x0448, 0, "afii10090" },
+ { 0x0449, 0, "afii10091" },
+ { 0x044A, 0, "afii10092" },
+ { 0x044B, 0, "afii10093" },
+ { 0x044C, 0, "afii10094" },
+ { 0x044D, 0, "afii10095" },
+ { 0x044E, 0, "afii10096" },
+ { 0x044F, 0, "afii10097" },
+ { 0x0491, 0, "afii10098" },
+ { 0x0452, 0, "afii10099" },
+ { 0x0453, 0, "afii10100" },
+ { 0x0454, 0, "afii10101" },
+ { 0x0455, 0, "afii10102" },
+ { 0x0456, 0, "afii10103" },
+ { 0x0457, 0, "afii10104" },
+ { 0x0458, 0, "afii10105" },
+ { 0x0459, 0, "afii10106" },
+ { 0x045A, 0, "afii10107" },
+ { 0x045B, 0, "afii10108" },
+ { 0x045C, 0, "afii10109" },
+ { 0x045E, 0, "afii10110" },
+ { 0x040F, 0, "afii10145" },
+ { 0x0462, 0, "afii10146" },
+ { 0x0472, 0, "afii10147" },
+ { 0x0474, 0, "afii10148" },
+ { 0xF6C6, 0, "afii10192" },
+ { 0x045F, 0, "afii10193" },
+ { 0x0463, 0, "afii10194" },
+ { 0x0473, 0, "afii10195" },
+ { 0x0475, 0, "afii10196" },
+ { 0xF6C7, 0, "afii10831" },
+ { 0xF6C8, 0, "afii10832" },
+ { 0x04D9, 0, "afii10846" },
+ { 0x200E, 0, "afii299" },
+ { 0x200F, 0, "afii300" },
+ { 0x200D, 0, "afii301" },
+ { 0x066A, 0, "afii57381" },
+ { 0x060C, 0, "afii57388" },
+ { 0x0660, 0, "afii57392" },
+ { 0x0661, 0, "afii57393" },
+ { 0x0662, 0, "afii57394" },
+ { 0x0663, 0, "afii57395" },
+ { 0x0664, 0, "afii57396" },
+ { 0x0665, 0, "afii57397" },
+ { 0x0666, 0, "afii57398" },
+ { 0x0667, 0, "afii57399" },
+ { 0x0668, 0, "afii57400" },
+ { 0x0669, 0, "afii57401" },
+ { 0x061B, 0, "afii57403" },
+ { 0x061F, 0, "afii57407" },
+ { 0x0621, 0, "afii57409" },
+ { 0x0622, 0, "afii57410" },
+ { 0x0623, 0, "afii57411" },
+ { 0x0624, 0, "afii57412" },
+ { 0x0625, 0, "afii57413" },
+ { 0x0626, 0, "afii57414" },
+ { 0x0627, 0, "afii57415" },
+ { 0x0628, 0, "afii57416" },
+ { 0x0629, 0, "afii57417" },
+ { 0x062A, 0, "afii57418" },
+ { 0x062B, 0, "afii57419" },
+ { 0x062C, 0, "afii57420" },
+ { 0x062D, 0, "afii57421" },
+ { 0x062E, 0, "afii57422" },
+ { 0x062F, 0, "afii57423" },
+ { 0x0630, 0, "afii57424" },
+ { 0x0631, 0, "afii57425" },
+ { 0x0632, 0, "afii57426" },
+ { 0x0633, 0, "afii57427" },
+ { 0x0634, 0, "afii57428" },
+ { 0x0635, 0, "afii57429" },
+ { 0x0636, 0, "afii57430" },
+ { 0x0637, 0, "afii57431" },
+ { 0x0638, 0, "afii57432" },
+ { 0x0639, 0, "afii57433" },
+ { 0x063A, 0, "afii57434" },
+ { 0x0640, 0, "afii57440" },
+ { 0x0641, 0, "afii57441" },
+ { 0x0642, 0, "afii57442" },
+ { 0x0643, 0, "afii57443" },
+ { 0x0644, 0, "afii57444" },
+ { 0x0645, 0, "afii57445" },
+ { 0x0646, 0, "afii57446" },
+ { 0x0648, 0, "afii57448" },
+ { 0x0649, 0, "afii57449" },
+ { 0x064A, 0, "afii57450" },
+ { 0x064B, 0, "afii57451" },
+ { 0x064C, 0, "afii57452" },
+ { 0x064D, 0, "afii57453" },
+ { 0x064E, 0, "afii57454" },
+ { 0x064F, 0, "afii57455" },
+ { 0x0650, 0, "afii57456" },
+ { 0x0651, 0, "afii57457" },
+ { 0x0652, 0, "afii57458" },
+ { 0x0647, 0, "afii57470" },
+ { 0x06A4, 0, "afii57505" },
+ { 0x067E, 0, "afii57506" },
+ { 0x0686, 0, "afii57507" },
+ { 0x0698, 0, "afii57508" },
+ { 0x06AF, 0, "afii57509" },
+ { 0x0679, 0, "afii57511" },
+ { 0x0688, 0, "afii57512" },
+ { 0x0691, 0, "afii57513" },
+ { 0x06BA, 0, "afii57514" },
+ { 0x06D2, 0, "afii57519" },
+ { 0x06D5, 0, "afii57534" },
+ { 0x20AA, 0, "afii57636" },
+ { 0x05BE, 0, "afii57645" },
+ { 0x05C3, 0, "afii57658" },
+ { 0x05D0, 0, "afii57664" },
+ { 0x05D1, 0, "afii57665" },
+ { 0x05D2, 0, "afii57666" },
+ { 0x05D3, 0, "afii57667" },
+ { 0x05D4, 0, "afii57668" },
+ { 0x05D5, 0, "afii57669" },
+ { 0x05D6, 0, "afii57670" },
+ { 0x05D7, 0, "afii57671" },
+ { 0x05D8, 0, "afii57672" },
+ { 0x05D9, 0, "afii57673" },
+ { 0x05DA, 0, "afii57674" },
+ { 0x05DB, 0, "afii57675" },
+ { 0x05DC, 0, "afii57676" },
+ { 0x05DD, 0, "afii57677" },
+ { 0x05DE, 0, "afii57678" },
+ { 0x05DF, 0, "afii57679" },
+ { 0x05E0, 0, "afii57680" },
+ { 0x05E1, 0, "afii57681" },
+ { 0x05E2, 0, "afii57682" },
+ { 0x05E3, 0, "afii57683" },
+ { 0x05E4, 0, "afii57684" },
+ { 0x05E5, 0, "afii57685" },
+ { 0x05E6, 0, "afii57686" },
+ { 0x05E7, 0, "afii57687" },
+ { 0x05E8, 0, "afii57688" },
+ { 0x05E9, 0, "afii57689" },
+ { 0x05EA, 0, "afii57690" },
+ { 0xFB2A, 0, "afii57694" },
+ { 0xFB2B, 0, "afii57695" },
+ { 0xFB4B, 0, "afii57700" },
+ { 0xFB1F, 0, "afii57705" },
+ { 0x05F0, 0, "afii57716" },
+ { 0x05F1, 0, "afii57717" },
+ { 0x05F2, 0, "afii57718" },
+ { 0xFB35, 0, "afii57723" },
+ { 0x05B4, 0, "afii57793" },
+ { 0x05B5, 0, "afii57794" },
+ { 0x05B6, 0, "afii57795" },
+ { 0x05BB, 0, "afii57796" },
+ { 0x05B8, 0, "afii57797" },
+ { 0x05B7, 0, "afii57798" },
+ { 0x05B0, 0, "afii57799" },
+ { 0x05B2, 0, "afii57800" },
+ { 0x05B1, 0, "afii57801" },
+ { 0x05B3, 0, "afii57802" },
+ { 0x05C2, 0, "afii57803" },
+ { 0x05C1, 0, "afii57804" },
+ { 0x05B9, 0, "afii57806" },
+ { 0x05BC, 0, "afii57807" },
+ { 0x05BD, 0, "afii57839" },
+ { 0x05BF, 0, "afii57841" },
+ { 0x05C0, 0, "afii57842" },
+ { 0x02BC, 0, "afii57929" },
+ { 0x2105, 0, "afii61248" },
+ { 0x2113, 0, "afii61289" },
+ { 0x2116, 0, "afii61352" },
+ { 0x202C, 0, "afii61573" },
+ { 0x202D, 0, "afii61574" },
+ { 0x202E, 0, "afii61575" },
+ { 0x200C, 0, "afii61664" },
+ { 0x066D, 0, "afii63167" },
+ { 0x02BD, 0, "afii64937" },
+ { 0x00E0, 0, "agrave" },
+ { 0x2135, 0, "aleph" },
+ { 0x03B1, 0, "alpha" },
+ { 0x03AC, 0, "alphatonos" },
+ { 0x0101, 0, "amacron" },
+ { 0x0026, 046, "ampersand" },
+ { 0xF726, 0, "ampersandsmall" },
+ { 0x2220, 0, "angle" },
+ { 0x2329, 0, "angleleft" },
+ { 0x232A, 0, "angleright" },
+ { 0x0387, 0, "anoteleia" },
+ { 0x0105, 0, "aogonek" },
+ { 0x2248, 0, "approxequal" },
+ { 0x00E5, 0, "aring" },
+ { 0x01FB, 0, "aringacute" },
+ { 0x2194, 0, "arrowboth" },
+ { 0x21D4, 0, "arrowdblboth" },
+ { 0x21D3, 0, "arrowdbldown" },
+ { 0x21D0, 0, "arrowdblleft" },
+ { 0x21D2, 0, "arrowdblright" },
+ { 0x21D1, 0, "arrowdblup" },
+ { 0x2193, 0, "arrowdown" },
+ { 0xF8E7, 0, "arrowhorizex" },
+ { 0x2190, 0, "arrowleft" },
+ { 0x2192, 0, "arrowright" },
+ { 0x2191, 0, "arrowup" },
+ { 0x2195, 0, "arrowupdn" },
+ { 0x21A8, 0, "arrowupdnbse" },
+ { 0xF8E6, 0, "arrowvertex" },
+ { 0x005E, 0136, "asciicircum" },
+ { 0x007E, 0176, "asciitilde" },
+ { 0x002A, 052, "asterisk" },
+ { 0x2217, 0, "asteriskmath" },
+ { 0xF6E9, 0, "asuperior" },
+ { 0x0040, 0100, "at" },
+ { 0x00E3, 0, "atilde" },
+ { 0x0062, 0142, "b" },
+ { 0x005C, 0134, "backslash" },
+ { 0x007C, 0174, "bar" },
+ { 0x03B2, 0, "beta" },
+ { 0x2588, 0, "block" },
+ { 0xF8F4, 0, "braceex" },
+ { 0x007B, 0173, "braceleft" },
+ { 0xF8F3, 0, "braceleftbt" },
+ { 0xF8F2, 0, "braceleftmid" },
+ { 0xF8F1, 0, "bracelefttp" },
+ { 0x007D, 0175, "braceright" },
+ { 0xF8FE, 0, "bracerightbt" },
+ { 0xF8FD, 0, "bracerightmid" },
+ { 0xF8FC, 0, "bracerighttp" },
+ { 0x005B, 0133, "bracketleft" },
+ { 0xF8F0, 0, "bracketleftbt" },
+ { 0xF8EF, 0, "bracketleftex" },
+ { 0xF8EE, 0, "bracketlefttp" },
+ { 0x005D, 0135, "bracketright" },
+ { 0xF8FB, 0, "bracketrightbt" },
+ { 0xF8FA, 0, "bracketrightex" },
+ { 0xF8F9, 0, "bracketrighttp" },
+ { 0x02D8, 0306, "breve" },
+ { 0x00A6, 0, "brokenbar" },
+ { 0xF6EA, 0, "bsuperior" },
+ { 0x2022, 0267, "bullet" },
+ { 0x0063, 0143, "c" },
+ { 0x0107, 0, "cacute" },
+ { 0x02C7, 0317, "caron" },
+ { 0x21B5, 0, "carriagereturn" },
+ { 0x010D, 0, "ccaron" },
+ { 0x00E7, 0, "ccedilla" },
+ { 0x0109, 0, "ccircumflex" },
+ { 0x010B, 0, "cdotaccent" },
+ { 0x00B8, 0313, "cedilla" },
+ { 0x00A2, 0242, "cent" },
+ { 0xF6DF, 0, "centinferior" },
+ { 0xF7A2, 0, "centoldstyle" },
+ { 0xF6E0, 0, "centsuperior" },
+ { 0x03C7, 0, "chi" },
+ { 0x25CB, 0, "circle" },
+ { 0x2297, 0, "circlemultiply" },
+ { 0x2295, 0, "circleplus" },
+ { 0x02C6, 0303, "circumflex" },
+ { 0x2663, 0, "club" },
+ { 0x003A, 072, "colon" },
+ { 0x20A1, 0, "colonmonetary" },
+ { 0x002C, 054, "comma" },
+ { 0xF6C3, 0, "commaaccent" },
+ { 0xF6E1, 0, "commainferior" },
+ { 0xF6E2, 0, "commasuperior" },
+ { 0x2245, 0, "congruent" },
+ { 0x00A9, 0, "copyright" },
+ { 0xF8E9, 0, "copyrightsans" },
+ { 0xF6D9, 0, "copyrightserif" },
+ { 0x00A4, 0250, "currency" },
+ { 0xF6D1, 0, "cyrBreve" },
+ { 0xF6D2, 0, "cyrFlex" },
+ { 0xF6D4, 0, "cyrbreve" },
+ { 0xF6D5, 0, "cyrflex" },
+ { 0x0064, 0144, "d" },
+ { 0x2020, 0262, "dagger" },
+ { 0x2021, 0263, "daggerdbl" },
+ { 0xF6D3, 0, "dblGrave" },
+ { 0xF6D6, 0, "dblgrave" },
+ { 0x010F, 0, "dcaron" },
+ { 0x0111, 0, "dcroat" },
+ { 0x00B0, 0, "degree" },
+ { 0x03B4, 0, "delta" },
+ { 0x2666, 0, "diamond" },
+ { 0x00A8, 0310, "dieresis" },
+ { 0xF6D7, 0, "dieresisacute" },
+ { 0xF6D8, 0, "dieresisgrave" },
+ { 0x0385, 0, "dieresistonos" },
+ { 0x00F7, 0, "divide" },
+ { 0x2593, 0, "dkshade" },
+ { 0x2584, 0, "dnblock" },
+ { 0x0024, 044, "dollar" },
+ { 0xF6E3, 0, "dollarinferior" },
+ { 0xF724, 0, "dollaroldstyle" },
+ { 0xF6E4, 0, "dollarsuperior" },
+ { 0x20AB, 0, "dong" },
+ { 0x02D9, 0307, "dotaccent" },
+ { 0x0323, 0, "dotbelowcomb" },
+ { 0x0131, 0365, "dotlessi" },
+ { 0xF6BE, 0, "dotlessj" },
+ { 0x22C5, 0, "dotmath" },
+ { 0xF6EB, 0, "dsuperior" },
+ { 0x0065, 0145, "e" },
+ { 0x00E9, 0, "eacute" },
+ { 0x0115, 0, "ebreve" },
+ { 0x011B, 0, "ecaron" },
+ { 0x00EA, 0, "ecircumflex" },
+ { 0x00EB, 0, "edieresis" },
+ { 0x0117, 0, "edotaccent" },
+ { 0x00E8, 0, "egrave" },
+ { 0x0038, 070, "eight" },
+ { 0x2088, 0, "eightinferior" },
+ { 0xF738, 0, "eightoldstyle" },
+ { 0x2078, 0, "eightsuperior" },
+ { 0x2208, 0, "element" },
+ { 0x2026, 0274, "ellipsis" },
+ { 0x0113, 0, "emacron" },
+ { 0x2014, 0320, "emdash" },
+ { 0x2205, 0, "emptyset" },
+ { 0x2013, 0261, "endash" },
+ { 0x014B, 0, "eng" },
+ { 0x0119, 0, "eogonek" },
+ { 0x03B5, 0, "epsilon" },
+ { 0x03AD, 0, "epsilontonos" },
+ { 0x003D, 075, "equal" },
+ { 0x2261, 0, "equivalence" },
+ { 0x212E, 0, "estimated" },
+ { 0xF6EC, 0, "esuperior" },
+ { 0x03B7, 0, "eta" },
+ { 0x03AE, 0, "etatonos" },
+ { 0x00F0, 0, "eth" },
+ { 0x0021, 041, "exclam" },
+ { 0x203C, 0, "exclamdbl" },
+ { 0x00A1, 0241, "exclamdown" },
+ { 0xF7A1, 0, "exclamdownsmall" },
+ { 0xF721, 0, "exclamsmall" },
+ { 0x2203, 0, "existential" },
+ { 0x0066, 0146, "f" },
+ { 0x2640, 0, "female" },
+ { 0xFB00, 0, "ff" },
+ { 0xFB03, 0, "ffi" },
+ { 0xFB04, 0, "ffl" },
+ { 0xFB01, 0256, "fi" },
+ { 0x2012, 0, "figuredash" },
+ { 0x25A0, 0, "filledbox" },
+ { 0x25AC, 0, "filledrect" },
+ { 0x0035, 065, "five" },
+ { 0x215D, 0, "fiveeighths" },
+ { 0x2085, 0, "fiveinferior" },
+ { 0xF735, 0, "fiveoldstyle" },
+ { 0x2075, 0, "fivesuperior" },
+ { 0xFB02, 0257, "fl" },
+ { 0x0192, 0246, "florin" },
+ { 0x0034, 064, "four" },
+ { 0x2084, 0, "fourinferior" },
+ { 0xF734, 0, "fouroldstyle" },
+ { 0x2074, 0, "foursuperior" },
+ { 0x2044, 0244, "fraction" },
+ { 0x2215, 0244, "fraction" },
+ { 0x20A3, 0, "franc" },
+ { 0x0067, 0147, "g" },
+ { 0x03B3, 0, "gamma" },
+ { 0x011F, 0, "gbreve" },
+ { 0x01E7, 0, "gcaron" },
+ { 0x011D, 0, "gcircumflex" },
+ { 0x0123, 0, "gcommaaccent" },
+ { 0x0121, 0, "gdotaccent" },
+ { 0x00DF, 0373, "germandbls" },
+ { 0x2207, 0, "gradient" },
+ { 0x0060, 0301, "grave" },
+ { 0x0300, 0, "gravecomb" },
+ { 0x003E, 076, "greater" },
+ { 0x2265, 0, "greaterequal" },
+ { 0x00AB, 0253, "guillemotleft" },
+ { 0x00BB, 0273, "guillemotright" },
+ { 0x2039, 0254, "guilsinglleft" },
+ { 0x203A, 0255, "guilsinglright" },
+ { 0x0068, 0150, "h" },
+ { 0x0127, 0, "hbar" },
+ { 0x0125, 0, "hcircumflex" },
+ { 0x2665, 0, "heart" },
+ { 0x0309, 0, "hookabovecomb" },
+ { 0x2302, 0, "house" },
+ { 0x02DD, 0315, "hungarumlaut" },
+ { 0x002D, 055, "hyphen" },
+ { 0x00AD, 0, "hyphen" },
+ { 0xF6E5, 0, "hypheninferior" },
+ { 0xF6E6, 0, "hyphensuperior" },
+ { 0x0069, 0151, "i" },
+ { 0x00ED, 0, "iacute" },
+ { 0x012D, 0, "ibreve" },
+ { 0x00EE, 0, "icircumflex" },
+ { 0x00EF, 0, "idieresis" },
+ { 0x00EC, 0, "igrave" },
+ { 0x0133, 0, "ij" },
+ { 0x012B, 0, "imacron" },
+ { 0x221E, 0, "infinity" },
+ { 0x222B, 0, "integral" },
+ { 0x2321, 0, "integralbt" },
+ { 0xF8F5, 0, "integralex" },
+ { 0x2320, 0, "integraltp" },
+ { 0x2229, 0, "intersection" },
+ { 0x25D8, 0, "invbullet" },
+ { 0x25D9, 0, "invcircle" },
+ { 0x263B, 0, "invsmileface" },
+ { 0x012F, 0, "iogonek" },
+ { 0x03B9, 0, "iota" },
+ { 0x03CA, 0, "iotadieresis" },
+ { 0x0390, 0, "iotadieresistonos" },
+ { 0x03AF, 0, "iotatonos" },
+ { 0xF6ED, 0, "isuperior" },
+ { 0x0129, 0, "itilde" },
+ { 0x006A, 0152, "j" },
+ { 0x0135, 0, "jcircumflex" },
+ { 0x006B, 0153, "k" },
+ { 0x03BA, 0, "kappa" },
+ { 0x0137, 0, "kcommaaccent" },
+ { 0x0138, 0, "kgreenlandic" },
+ { 0x006C, 0154, "l" },
+ { 0x013A, 0, "lacute" },
+ { 0x03BB, 0, "lambda" },
+ { 0x013E, 0, "lcaron" },
+ { 0x013C, 0, "lcommaaccent" },
+ { 0x0140, 0, "ldot" },
+ { 0x003C, 074, "less" },
+ { 0x2264, 0, "lessequal" },
+ { 0x258C, 0, "lfblock" },
+ { 0x20A4, 0, "lira" },
+ { 0xF6C0, 0, "ll" },
+ { 0x2227, 0, "logicaland" },
+ { 0x00AC, 0, "logicalnot" },
+ { 0x2228, 0, "logicalor" },
+ { 0x017F, 0, "longs" },
+ { 0x25CA, 0, "lozenge" },
+ { 0x0142, 0370, "lslash" },
+ { 0xF6EE, 0, "lsuperior" },
+ { 0x2591, 0, "ltshade" },
+ { 0x006D, 0155, "m" },
+ { 0x00AF, 0305, "macron" },
+ { 0x02C9, 0305, "macron" },
+ { 0x2642, 0, "male" },
+ { 0x2212, 0, "minus" },
+ { 0x2032, 0, "minute" },
+ { 0xF6EF, 0, "msuperior" },
+ { 0x00B5, 0, "mu" },
+ { 0x03BC, 0, "mu" },
+ { 0x00D7, 0, "multiply" },
+ { 0x266A, 0, "musicalnote" },
+ { 0x266B, 0, "musicalnotedbl" },
+ { 0x006E, 0156, "n" },
+ { 0x0144, 0, "nacute" },
+ { 0x0149, 0, "napostrophe" },
+ { 0x0148, 0, "ncaron" },
+ { 0x0146, 0, "ncommaaccent" },
+ { 0x0039, 071, "nine" },
+ { 0x2089, 0, "nineinferior" },
+ { 0xF739, 0, "nineoldstyle" },
+ { 0x2079, 0, "ninesuperior" },
+ { 0x2209, 0, "notelement" },
+ { 0x2260, 0, "notequal" },
+ { 0x2284, 0, "notsubset" },
+ { 0x207F, 0, "nsuperior" },
+ { 0x00F1, 0, "ntilde" },
+ { 0x03BD, 0, "nu" },
+ { 0x0023, 043, "numbersign" },
+ { 0x006F, 0157, "o" },
+ { 0x00F3, 0, "oacute" },
+ { 0x014F, 0, "obreve" },
+ { 0x00F4, 0, "ocircumflex" },
+ { 0x00F6, 0, "odieresis" },
+ { 0x0153, 0372, "oe" },
+ { 0x02DB, 0316, "ogonek" },
+ { 0x00F2, 0, "ograve" },
+ { 0x01A1, 0, "ohorn" },
+ { 0x0151, 0, "ohungarumlaut" },
+ { 0x014D, 0, "omacron" },
+ { 0x03C9, 0, "omega" },
+ { 0x03D6, 0, "omega1" },
+ { 0x03CE, 0, "omegatonos" },
+ { 0x03BF, 0, "omicron" },
+ { 0x03CC, 0, "omicrontonos" },
+ { 0x0031, 061, "one" },
+ { 0x2024, 0, "onedotenleader" },
+ { 0x215B, 0, "oneeighth" },
+ { 0xF6DC, 0, "onefitted" },
+ { 0x00BD, 0, "onehalf" },
+ { 0x2081, 0, "oneinferior" },
+ { 0xF731, 0, "oneoldstyle" },
+ { 0x00BC, 0, "onequarter" },
+ { 0x00B9, 0, "onesuperior" },
+ { 0x2153, 0, "onethird" },
+ { 0x25E6, 0, "openbullet" },
+ { 0x00AA, 0343, "ordfeminine" },
+ { 0x00BA, 0353, "ordmasculine" },
+ { 0x221F, 0, "orthogonal" },
+ { 0x00F8, 0371, "oslash" },
+ { 0x01FF, 0, "oslashacute" },
+ { 0xF6F0, 0, "osuperior" },
+ { 0x00F5, 0, "otilde" },
+ { 0x0070, 0160, "p" },
+ { 0x00B6, 0266, "paragraph" },
+ { 0x0028, 050, "parenleft" },
+ { 0xF8ED, 0, "parenleftbt" },
+ { 0xF8EC, 0, "parenleftex" },
+ { 0x208D, 0, "parenleftinferior" },
+ { 0x207D, 0, "parenleftsuperior" },
+ { 0xF8EB, 0, "parenlefttp" },
+ { 0x0029, 051, "parenright" },
+ { 0xF8F8, 0, "parenrightbt" },
+ { 0xF8F7, 0, "parenrightex" },
+ { 0x208E, 0, "parenrightinferior" },
+ { 0x207E, 0, "parenrightsuperior" },
+ { 0xF8F6, 0, "parenrighttp" },
+ { 0x2202, 0, "partialdiff" },
+ { 0x0025, 045, "percent" },
+ { 0x002E, 056, "period" },
+ { 0x00B7, 0264, "periodcentered" },
+ { 0x2219, 0, "periodcentered" },
+ { 0xF6E7, 0, "periodinferior" },
+ { 0xF6E8, 0, "periodsuperior" },
+ { 0x22A5, 0, "perpendicular" },
+ { 0x2030, 0275, "perthousand" },
+ { 0x20A7, 0, "peseta" },
+ { 0x03C6, 0, "phi" },
+ { 0x03D5, 0, "phi1" },
+ { 0x03C0, 0, "pi" },
+ { 0x002B, 053, "plus" },
+ { 0x00B1, 0, "plusminus" },
+ { 0x211E, 0, "prescription" },
+ { 0x220F, 0, "product" },
+ { 0x2282, 0, "propersubset" },
+ { 0x2283, 0, "propersuperset" },
+ { 0x221D, 0, "proportional" },
+ { 0x03C8, 0, "psi" },
+ { 0x0071, 0161, "q" },
+ { 0x003F, 077, "question" },
+ { 0x00BF, 0277, "questiondown" },
+ { 0xF7BF, 0, "questiondownsmall" },
+ { 0xF73F, 0, "questionsmall" },
+ { 0x0022, 042, "quotedbl" },
+ { 0x201E, 0271, "quotedblbase" },
+ { 0x201C, 0252, "quotedblleft" },
+ { 0x201D, 0272, "quotedblright" },
+ { 0x2018, 0140, "quoteleft" },
+ { 0x201B, 0, "quotereversed" },
+ { 0x2019, 047, "quoteright" },
+ { 0x201A, 0270, "quotesinglbase" },
+ { 0x0027, 0251, "quotesingle" },
+ { 0x0072, 0162, "r" },
+ { 0x0155, 0, "racute" },
+ { 0x221A, 0, "radical" },
+ { 0xF8E5, 0, "radicalex" },
+ { 0x0159, 0, "rcaron" },
+ { 0x0157, 0, "rcommaaccent" },
+ { 0x2286, 0, "reflexsubset" },
+ { 0x2287, 0, "reflexsuperset" },
+ { 0x00AE, 0, "registered" },
+ { 0xF8E8, 0, "registersans" },
+ { 0xF6DA, 0, "registerserif" },
+ { 0x2310, 0, "revlogicalnot" },
+ { 0x03C1, 0, "rho" },
+ { 0x02DA, 0312, "ring" },
+ { 0xF6F1, 0, "rsuperior" },
+ { 0x2590, 0, "rtblock" },
+ { 0xF6DD, 0, "rupiah" },
+ { 0x0073, 0163, "s" },
+ { 0x015B, 0, "sacute" },
+ { 0x0161, 0, "scaron" },
+ { 0x015F, 0, "scedilla" },
+ { 0xF6C2, 0, "scedilla" },
+ { 0x015D, 0, "scircumflex" },
+ { 0x0219, 0, "scommaaccent" },
+ { 0x2033, 0, "second" },
+ { 0x00A7, 0247, "section" },
+ { 0x003B, 073, "semicolon" },
+ { 0x0037, 067, "seven" },
+ { 0x215E, 0, "seveneighths" },
+ { 0x2087, 0, "seveninferior" },
+ { 0xF737, 0, "sevenoldstyle" },
+ { 0x2077, 0, "sevensuperior" },
+ { 0x2592, 0, "shade" },
+ { 0x03C3, 0, "sigma" },
+ { 0x03C2, 0, "sigma1" },
+ { 0x223C, 0, "similar" },
+ { 0x0036, 066, "six" },
+ { 0x2086, 0, "sixinferior" },
+ { 0xF736, 0, "sixoldstyle" },
+ { 0x2076, 0, "sixsuperior" },
+ { 0x002F, 057, "slash" },
+ { 0x263A, 0, "smileface" },
+ { 0x0020, 040, "space" },
+ { 0x00A0, 040, "space" },
+ { 0x2660, 0, "spade" },
+ { 0xF6F2, 0, "ssuperior" },
+ { 0x00A3, 0243, "sterling" },
+ { 0x220B, 0, "suchthat" },
+ { 0x2211, 0, "summation" },
+ { 0x263C, 0, "sun" },
+ { 0x0074, 0164, "t" },
+ { 0x03C4, 0, "tau" },
+ { 0x0167, 0, "tbar" },
+ { 0x0165, 0, "tcaron" },
+ { 0x0163, 0, "tcommaaccent" },
+ { 0x021B, 0, "tcommaaccent" },
+ { 0x2234, 0, "therefore" },
+ { 0x03B8, 0, "theta" },
+ { 0x03D1, 0, "theta1" },
+ { 0x00FE, 0, "thorn" },
+ { 0x0033, 063, "three" },
+ { 0x215C, 0, "threeeighths" },
+ { 0x2083, 0, "threeinferior" },
+ { 0xF733, 0, "threeoldstyle" },
+ { 0x00BE, 0, "threequarters" },
+ { 0xF6DE, 0, "threequartersemdash" },
+ { 0x00B3, 0, "threesuperior" },
+ { 0x02DC, 0304, "tilde" },
+ { 0x0303, 0, "tildecomb" },
+ { 0x0384, 0, "tonos" },
+ { 0x2122, 0, "trademark" },
+ { 0xF8EA, 0, "trademarksans" },
+ { 0xF6DB, 0, "trademarkserif" },
+ { 0x25BC, 0, "triagdn" },
+ { 0x25C4, 0, "triaglf" },
+ { 0x25BA, 0, "triagrt" },
+ { 0x25B2, 0, "triagup" },
+ { 0xF6F3, 0, "tsuperior" },
+ { 0x0032, 062, "two" },
+ { 0x2025, 0, "twodotenleader" },
+ { 0x2082, 0, "twoinferior" },
+ { 0xF732, 0, "twooldstyle" },
+ { 0x00B2, 0, "twosuperior" },
+ { 0x2154, 0, "twothirds" },
+ { 0x0075, 0165, "u" },
+ { 0x00FA, 0, "uacute" },
+ { 0x016D, 0, "ubreve" },
+ { 0x00FB, 0, "ucircumflex" },
+ { 0x00FC, 0, "udieresis" },
+ { 0x00F9, 0, "ugrave" },
+ { 0x01B0, 0, "uhorn" },
+ { 0x0171, 0, "uhungarumlaut" },
+ { 0x016B, 0, "umacron" },
+ { 0x005F, 0137, "underscore" },
+ { 0x2017, 0, "underscoredbl" },
+ { 0x222A, 0, "union" },
+ { 0x2200, 0, "universal" },
+ { 0x0173, 0, "uogonek" },
+ { 0x2580, 0, "upblock" },
+ { 0x03C5, 0, "upsilon" },
+ { 0x03CB, 0, "upsilondieresis" },
+ { 0x03B0, 0, "upsilondieresistonos" },
+ { 0x03CD, 0, "upsilontonos" },
+ { 0x016F, 0, "uring" },
+ { 0x0169, 0, "utilde" },
+ { 0x0076, 0166, "v" },
+ { 0x0077, 0167, "w" },
+ { 0x1E83, 0, "wacute" },
+ { 0x0175, 0, "wcircumflex" },
+ { 0x1E85, 0, "wdieresis" },
+ { 0x2118, 0, "weierstrass" },
+ { 0x1E81, 0, "wgrave" },
+ { 0x0078, 0170, "x" },
+ { 0x03BE, 0, "xi" },
+ { 0x0079, 0171, "y" },
+ { 0x00FD, 0, "yacute" },
+ { 0x0177, 0, "ycircumflex" },
+ { 0x00FF, 0, "ydieresis" },
+ { 0x00A5, 0245, "yen" },
+ { 0x1EF3, 0, "ygrave" },
+ { 0x007A, 0172, "z" },
+ { 0x017A, 0, "zacute" },
+ { 0x017E, 0, "zcaron" },
+ { 0x017C, 0, "zdotaccent" },
+ { 0x0030, 060, "zero" },
+ { 0x2080, 0, "zeroinferior" },
+ { 0xF730, 0, "zerooldstyle" },
+ { 0x2070, 0, "zerosuperior" },
+ { 0x03B6, 0, "zeta" }
+};
diff --git a/vcl/unx/source/fontmanager/afm_hash.cpp b/vcl/unx/source/fontmanager/afm_hash.cpp
new file mode 100755
index 000000000000..de01d8cd0434
--- /dev/null
+++ b/vcl/unx/source/fontmanager/afm_hash.cpp
@@ -0,0 +1,245 @@
+/* C++ code produced by gperf version 3.0.1 */
+/* Command-line: gperf -C -t -l -L C++ -m 20 -Z AfmKeywordHash afm_keyword_list */
+/* Computed positions: -k'1,4,6,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
+#endif
+
+#line 1 "afm_keyword_list"
+struct hash_entry { const char* name; enum parseKey eKey; };
+
+#define TOTAL_KEYWORDS 56
+#define MIN_WORD_LENGTH 1
+#define MAX_WORD_LENGTH 18
+#define MIN_HASH_VALUE 1
+#define MAX_HASH_VALUE 57
+/* maximum key range = 57, duplicates = 0 */
+
+class AfmKeywordHash
+{
+private:
+ static inline unsigned int hash (const char *str, unsigned int len);
+public:
+ static const struct hash_entry *in_word_set (const char *str, unsigned int len);
+};
+
+inline unsigned int
+AfmKeywordHash::hash (register const char *str, register unsigned int len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 28, 1, 0, 9, 0,
+ 19, 58, 2, 10, 58, 0, 28, 0, 20, 58,
+ 44, 58, 58, 0, 16, 10, 24, 2, 3, 58,
+ 58, 58, 58, 58, 58, 58, 58, 6, 58, 0,
+ 19, 0, 58, 25, 14, 6, 58, 58, 17, 11,
+ 0, 17, 39, 58, 0, 0, 10, 58, 58, 58,
+ 13, 4, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58
+ };
+ register int hval = len;
+
+ switch (hval)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[5]];
+ /*FALLTHROUGH*/
+ case 5:
+ case 4:
+ hval += asso_values[(unsigned char)str[3]];
+ /*FALLTHROUGH*/
+ case 3:
+ case 2:
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval + asso_values[(unsigned char)str[len - 1]];
+}
+
+const struct hash_entry *
+AfmKeywordHash::in_word_set (register const char *str, register unsigned int len)
+{
+ static const unsigned char lengthtable[] =
+ {
+ 0, 1, 2, 1, 2, 1, 3, 2, 3, 5, 10, 11, 12, 2,
+ 14, 15, 16, 11, 9, 13, 14, 12, 12, 14, 13, 9, 7, 9,
+ 7, 9, 14, 5, 6, 14, 12, 16, 10, 14, 11, 10, 7, 1,
+ 12, 8, 17, 18, 2, 3, 7, 1, 8, 8, 13, 6, 6, 8,
+ 0, 1
+ };
+ static const struct hash_entry wordlist[] =
+ {
+ {"",NOPE},
+#line 6 "afm_keyword_list"
+ {"C",CODE},
+#line 7 "afm_keyword_list"
+ {"CC",COMPCHAR},
+#line 5 "afm_keyword_list"
+ {"B",CHARBBOX},
+#line 8 "afm_keyword_list"
+ {"CH",CODEHEX},
+#line 54 "afm_keyword_list"
+ {"W",XYWIDTH},
+#line 33 "afm_keyword_list"
+ {"KPX",KERNPAIRXAMT},
+#line 56 "afm_keyword_list"
+ {"WX",XWIDTH},
+#line 55 "afm_keyword_list"
+ {"W0X",X0WIDTH},
+#line 47 "afm_keyword_list"
+ {"StdHW",STDHW},
+#line 12 "afm_keyword_list"
+ {"Characters",CHARACTERS},
+#line 36 "afm_keyword_list"
+ {"MetricsSets",METRICSSETS},
+#line 23 "afm_keyword_list"
+ {"EndKernPairs",ENDKERNPAIRS},
+#line 16 "afm_keyword_list"
+ {"Em",EM},
+#line 45 "afm_keyword_list"
+ {"StartKernPairs",STARTKERNPAIRS},
+#line 41 "afm_keyword_list"
+ {"StartComposites",STARTCOMPOSITES},
+#line 40 "afm_keyword_list"
+ {"StartCharMetrics",STARTCHARMETRICS},
+#line 22 "afm_keyword_list"
+ {"EndKernData",ENDKERNDATA},
+#line 14 "afm_keyword_list"
+ {"Descender",DESCENDER},
+#line 44 "afm_keyword_list"
+ {"StartKernData",STARTKERNDATA},
+#line 18 "afm_keyword_list"
+ {"EndCharMetrics",ENDCHARMETRICS},
+#line 20 "afm_keyword_list"
+ {"EndDirection",ENDDIRECTION},
+#line 11 "afm_keyword_list"
+ {"CharacterSet",CHARACTERSET},
+#line 42 "afm_keyword_list"
+ {"StartDirection",STARTDIRECTION},
+#line 19 "afm_keyword_list"
+ {"EndComposites",ENDCOMPOSITES},
+#line 49 "afm_keyword_list"
+ {"TrackKern",TRACKKERN},
+#line 15 "afm_keyword_list"
+ {"Descent",DESCENT},
+#line 9 "afm_keyword_list"
+ {"CapHeight",CAPHEIGHT},
+#line 13 "afm_keyword_list"
+ {"Comment",COMMENT},
+#line 10 "afm_keyword_list"
+ {"CharWidth",CHARWIDTH},
+#line 46 "afm_keyword_list"
+ {"StartTrackKern",STARTTRACKKERN},
+#line 48 "afm_keyword_list"
+ {"StdVW",STDVW},
+#line 38 "afm_keyword_list"
+ {"Notice",NOTICE},
+#line 21 "afm_keyword_list"
+ {"EndFontMetrics",ENDFONTMETRICS},
+#line 24 "afm_keyword_list"
+ {"EndTrackKern",ENDTRACKKERN},
+#line 43 "afm_keyword_list"
+ {"StartFontMetrics",STARTFONTMETRICS},
+#line 29 "afm_keyword_list"
+ {"IsBaseFont",ISBASEFONT},
+#line 17 "afm_keyword_list"
+ {"EncodingScheme",ENCODINGSCHEME},
+#line 31 "afm_keyword_list"
+ {"ItalicAngle",ITALICANGLE},
+#line 25 "afm_keyword_list"
+ {"FamilyName",FAMILYNAME},
+#line 58 "afm_keyword_list"
+ {"XHeight",XHEIGHT},
+#line 37 "afm_keyword_list"
+ {"N",CHARNAME},
+#line 30 "afm_keyword_list"
+ {"IsFixedPitch",ISFIXEDPITCH},
+#line 27 "afm_keyword_list"
+ {"FontName",FONTNAME},
+#line 50 "afm_keyword_list"
+ {"UnderlinePosition",UNDERLINEPOSITION},
+#line 51 "afm_keyword_list"
+ {"UnderlineThickness",UNDERLINETHICKNESS},
+#line 32 "afm_keyword_list"
+ {"KP",KERNPAIR},
+#line 39 "afm_keyword_list"
+ {"PCC",COMPCHARPIECE},
+#line 53 "afm_keyword_list"
+ {"Version",VERSION},
+#line 52 "afm_keyword_list"
+ {"V",VVECTOR},
+#line 28 "afm_keyword_list"
+ {"FullName",FULLNAME},
+#line 26 "afm_keyword_list"
+ {"FontBBox",FONTBBOX},
+#line 35 "afm_keyword_list"
+ {"MappingScheme",MAPPINGSCHEME},
+#line 57 "afm_keyword_list"
+ {"Weight",WEIGHT},
+#line 4 "afm_keyword_list"
+ {"Ascent",ASCENT},
+#line 3 "afm_keyword_list"
+ {"Ascender",ASCENDER},
+ {"",NOPE},
+#line 34 "afm_keyword_list"
+ {"L",LIGATURE}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE && key >= 0)
+ if (len == lengthtable[key])
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !memcmp (str + 1, s + 1, len - 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/vcl/unx/source/fontmanager/afm_keyword_list b/vcl/unx/source/fontmanager/afm_keyword_list
new file mode 100755
index 000000000000..263d76bca4d3
--- /dev/null
+++ b/vcl/unx/source/fontmanager/afm_keyword_list
@@ -0,0 +1,58 @@
+struct hash_entry { char* name; enum parseKey eKey; };
+%%
+Ascender,ASCENDER
+Ascent,ASCENT
+B,CHARBBOX
+C,CODE
+CC,COMPCHAR
+CH,CODEHEX
+CapHeight,CAPHEIGHT
+CharWidth,CHARWIDTH
+CharacterSet,CHARACTERSET
+Characters,CHARACTERS
+Comment,COMMENT
+Descender,DESCENDER
+Descent,DESCENT
+Em,EM
+EncodingScheme,ENCODINGSCHEME
+EndCharMetrics,ENDCHARMETRICS
+EndComposites,ENDCOMPOSITES
+EndDirection,ENDDIRECTION
+EndFontMetrics,ENDFONTMETRICS
+EndKernData,ENDKERNDATA
+EndKernPairs,ENDKERNPAIRS
+EndTrackKern,ENDTRACKKERN
+FamilyName,FAMILYNAME
+FontBBox,FONTBBOX
+FontName,FONTNAME
+FullName,FULLNAME
+IsBaseFont,ISBASEFONT
+IsFixedPitch,ISFIXEDPITCH
+ItalicAngle,ITALICANGLE
+KP,KERNPAIR
+KPX,KERNPAIRXAMT
+L,LIGATURE
+MappingScheme,MAPPINGSCHEME
+MetricsSets,METRICSSETS
+N,CHARNAME
+Notice,NOTICE
+PCC,COMPCHARPIECE
+StartCharMetrics,STARTCHARMETRICS
+StartComposites,STARTCOMPOSITES
+StartDirection,STARTDIRECTION
+StartFontMetrics,STARTFONTMETRICS
+StartKernData,STARTKERNDATA
+StartKernPairs,STARTKERNPAIRS
+StartTrackKern,STARTTRACKKERN
+StdHW,STDHW
+StdVW,STDVW
+TrackKern,TRACKKERN
+UnderlinePosition,UNDERLINEPOSITION
+UnderlineThickness,UNDERLINETHICKNESS
+V,VVECTOR
+Version,VERSION
+W,XYWIDTH
+W0X,X0WIDTH
+WX,XWIDTH
+Weight,WEIGHT
+XHeight,XHEIGHT
diff --git a/vcl/unx/source/fontmanager/fontcache.cxx b/vcl/unx/source/fontmanager/fontcache.cxx
new file mode 100644
index 000000000000..4932f7a771e0
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontcache.cxx
@@ -0,0 +1,821 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: fontcache.cxx,v $
+ * $Revision: 1.26 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <cstdlib>
+#include <cstring>
+
+#include "vcl/fontcache.hxx"
+
+#include "osl/thread.h"
+
+#include "unotools/atom.hxx"
+
+#include "tools/stream.hxx"
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#if OSL_DEBUG_LEVEL >1
+#include <cstdio>
+#endif
+
+#define FONTCACHEFILE "/user/psprint/pspfontcache"
+#define CACHE_MAGIC "PspFontCacheFile format 3"
+
+using namespace std;
+using namespace rtl;
+using namespace psp;
+using namespace utl;
+
+/*
+ * static helpers
+ */
+
+/*
+ * FontCache constructor
+ */
+
+FontCache::FontCache()
+{
+ m_bDoFlush = false;
+ m_aCacheFile = getOfficePath( UserPath );
+ if( m_aCacheFile.Len() )
+ {
+ m_aCacheFile.AppendAscii( FONTCACHEFILE );
+ read();
+ }
+}
+
+/*
+ * FontCache destructor
+ */
+
+FontCache::~FontCache()
+{
+ clearCache();
+}
+
+/*
+ * FontCache::clearCache
+ */
+void FontCache::clearCache()
+{
+ for( FontCacheData::iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++dir_it )
+ {
+ for( FontDirMap::iterator entry_it = dir_it->second.m_aEntries.begin(); entry_it != dir_it->second.m_aEntries.end(); ++entry_it )
+ {
+ for( FontCacheEntry::iterator font_it = entry_it->second.m_aEntry.begin(); font_it != entry_it->second.m_aEntry.end(); ++font_it )
+ delete *font_it;
+ }
+ }
+ m_aCache.clear();
+}
+
+/*
+ * FontCache::Commit
+ */
+
+void FontCache::flush()
+{
+ if( ! m_bDoFlush || ! m_aCacheFile.Len() )
+ return;
+
+ SvFileStream aStream;
+ aStream.Open( m_aCacheFile, STREAM_WRITE | STREAM_TRUNC );
+ if( ! (aStream.IsOpen() && aStream.IsWritable()) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FontCache::flush: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+#endif
+ return;
+ }
+
+ aStream.SetLineDelimiter( LINEEND_LF );
+ aStream.WriteLine( ByteString( CACHE_MAGIC ) );
+
+ PrintFontManager& rManager( PrintFontManager::get() );
+ MultiAtomProvider* pAtoms = rManager.m_pAtoms;
+
+ for( FontCacheData::const_iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++ dir_it )
+ {
+ const FontDirMap& rDir( dir_it->second.m_aEntries );
+
+ ByteString aDirectory( rManager.getDirectory( dir_it->first ) );
+ ByteString aLine( "FontCacheDirectory:" );
+ aLine.Append( ByteString::CreateFromInt64( dir_it->second.m_nTimestamp ) );
+ aLine.Append( ':' );
+ aLine.Append( aDirectory );
+ if( rDir.empty() && dir_it->second.m_bNoFiles )
+ aLine.Insert( "Empty", 0 );
+ aStream.WriteLine( aLine );
+
+ for( FontDirMap::const_iterator entry_it = rDir.begin(); entry_it != rDir.end(); ++entry_it )
+ {
+ // insert cache entries
+ const FontCacheEntry& rEntry( entry_it->second.m_aEntry );
+ if( rEntry.begin() == rEntry.end() )
+ continue;
+
+ aLine = "File:";
+ aLine.Append( ByteString( entry_it->first ) );
+ aStream.WriteLine( aLine );
+
+ int nEntrySize = entry_it->second.m_aEntry.size();
+ // write: type;nfonts
+ aLine = ByteString::CreateFromInt32( rEntry.front()->m_eType );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( nEntrySize ) );
+ aStream.WriteLine( aLine );
+
+ sal_Int32 nSubEntry = 0;
+ for( FontCacheEntry::const_iterator it = rEntry.begin(); it != rEntry.end(); ++it, nSubEntry++ )
+ {
+ /*
+ * for each font entry write:
+ * name[;name[;name]]
+ * fontnr;PSName;italic;weight;width;pitch;encoding;ascend;descend;leading;vsubst;gxw;gxh;gyw;gyh;useroverrride;embed;antialias[;{metricfile,typeflags}][;stylename]
+ */
+ if( nEntrySize > 1 )
+ nSubEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nCollectionEntry;
+ else
+ nSubEntry = -1;
+
+ aLine = OUStringToOString( pAtoms->getString( ATOM_FAMILYNAME, (*it)->m_nFamilyName ), RTL_TEXTENCODING_UTF8 );
+ for( ::std::list< int >::const_iterator name_it = (*it)->m_aAliases.begin(); name_it != (*it)->m_aAliases.end(); ++name_it )
+ {
+ const OUString& rAdd( pAtoms->getString( ATOM_FAMILYNAME, *name_it ) );
+ if( rAdd.getLength() )
+ {
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( rAdd ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ }
+ aStream.WriteLine( aLine );
+
+ const OUString& rPSName( pAtoms->getString( ATOM_PSNAME, (*it)->m_nPSName ) );
+ aLine = ByteString::CreateFromInt32( nSubEntry );
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( rPSName ), RTL_TEXTENCODING_UTF8 ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eItalic ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWeight ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWidth ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_ePitch ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aEncoding ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nAscend ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nDescend ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_nLeading ) );
+ aLine.Append( ';' );
+ aLine.Append( (*it)->m_bHaveVerticalSubstitutedGlyphs ? "1" : "0" );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.width ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.height ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.width ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.height ) );
+ aLine.Append( ';' );
+ aLine.Append( (*it)->m_bUserOverride ? "1" : "0" );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eEmbeddedbitmap ) );
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( (*it)->m_eAntialias ) );
+
+ switch( (*it)->m_eType )
+ {
+ case fonttype::Type1:
+ aLine.Append( ';' );
+ aLine.Append( ByteString( static_cast<const PrintFontManager::Type1FontFile*>(*it)->m_aMetricFile ) );
+ break;
+ case fonttype::TrueType:
+ aLine.Append( ';' );
+ aLine.Append( ByteString::CreateFromInt32( static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nTypeFlags ) );
+ break;
+ default: break;
+ }
+ if( (*it)->m_aStyleName.getLength() )
+ {
+ aLine.Append( ';' );
+ aLine.Append( ByteString( String( (*it)->m_aStyleName ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ aStream.WriteLine( aLine );
+ }
+ aStream.WriteLine( ByteString() );
+ }
+ }
+ m_bDoFlush = false;
+}
+
+/*
+ * FontCache::read
+ */
+
+void FontCache::read()
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ MultiAtomProvider* pAtoms = rManager.m_pAtoms;
+
+ SvFileStream aStream( m_aCacheFile, STREAM_READ );
+ if( ! aStream.IsOpen() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FontCache::read: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+#endif
+ return;
+ }
+
+
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+ if( !aLine.Equals( CACHE_MAGIC ) )
+ {
+ #if OSL_DEBUG_LEVEL >1
+ fprintf( stderr, "FontCache::read: cache file %s fails magic test\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
+ #endif
+ return;
+ }
+
+ int nDir = 0;
+ FontDirMap* pDir = NULL;
+ xub_StrLen nIndex;
+ bool bKeepOnlyUserOverridden = false;
+ do
+ {
+ aStream.ReadLine( aLine );
+ if( aLine.CompareTo( "FontCacheDirectory:", 19 ) == COMPARE_EQUAL ||
+ aLine.CompareTo( "EmptyFontCacheDirectory:", 24 ) == COMPARE_EQUAL )
+ {
+ bool bEmpty = (aLine.CompareTo( "Empty", 5 ) == COMPARE_EQUAL);
+ xub_StrLen nSearchIndex = bEmpty ? 24 : 19;
+
+ OString aDir;
+ sal_Int64 nTimestamp = 0;
+ xub_StrLen nTEnd = aLine.Search( ':', nSearchIndex );
+ if( nTEnd != STRING_NOTFOUND )
+ {
+ nTimestamp = aLine.Copy( nSearchIndex, nTEnd - nSearchIndex ).ToInt64();
+ aDir = aLine.Copy( nTEnd+1 );
+ }
+ else
+ {
+ // invalid format, remove
+ pDir = NULL;
+ nDir = 0;
+ m_bDoFlush = true;
+ continue;
+ }
+
+ // is the directory modified ?
+ struct stat aStat;
+ if( stat( aDir.getStr(), &aStat ) ||
+ ! S_ISDIR(aStat.st_mode) )
+ {
+ // remove outdated cache data
+ pDir = NULL;
+ nDir = 0;
+ m_bDoFlush = true;
+ continue;
+ }
+ else
+ {
+ nDir = rManager.getDirectoryAtom( aDir, true );
+ m_aCache[ nDir ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+ m_aCache[ nDir ].m_bNoFiles = bEmpty;
+ pDir = bEmpty ? NULL : &m_aCache[ nDir ].m_aEntries;
+ bKeepOnlyUserOverridden = ((sal_Int64)aStat.st_mtime != nTimestamp);
+ m_aCache[ nDir ].m_bUserOverrideOnly = bKeepOnlyUserOverridden;
+ }
+ }
+ else if( pDir && aLine.CompareTo( "File:", 5 ) == COMPARE_EQUAL )
+ {
+ OString aFile( aLine.Copy( 5 ) );
+ aStream.ReadLine( aLine );
+
+ const char* pLine = aLine.GetBuffer();
+
+ fonttype::type eType = (fonttype::type)atoi( pLine );
+ if( eType != fonttype::TrueType &&
+ eType != fonttype::Type1 &&
+ eType != fonttype::Builtin
+ )
+ continue;
+ while( *pLine && *pLine != ';' )
+ pLine++;
+ if( *pLine != ';' )
+ continue;
+
+ pLine++;
+ sal_Int32 nFonts = atoi( pLine );
+ for( int n = 0; n < nFonts; n++ )
+ {
+ aStream.ReadLine( aLine );
+ pLine = aLine.GetBuffer();
+ int nLen = aLine.Len();
+
+ PrintFontManager::PrintFont* pFont = NULL;
+ switch( eType )
+ {
+ case fonttype::TrueType:
+ pFont = new PrintFontManager::TrueTypeFontFile();
+ break;
+ case fonttype::Type1:
+ pFont = new PrintFontManager::Type1FontFile();
+ break;
+ case fonttype::Builtin:
+ pFont = new PrintFontManager::BuiltinFont();
+ break;
+ default: break;
+ }
+
+ for( nIndex = 0; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
+ ;
+
+ pFont->m_nFamilyName = pAtoms->getAtom( ATOM_FAMILYNAME,
+ OUString( pLine, nIndex, RTL_TEXTENCODING_UTF8 ),
+ sal_True );
+ while( nIndex < nLen )
+ {
+ xub_StrLen nLastIndex = nIndex+1;
+ for( nIndex = nLastIndex ; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
+ ;
+ if( nIndex - nLastIndex > 1 )
+ {
+ OUString aAlias( pLine+nLastIndex, nIndex-nLastIndex-1, RTL_TEXTENCODING_UTF8 );
+ pFont->m_aAliases.push_back( pAtoms->getAtom( ATOM_FAMILYNAME, aAlias, sal_True ) );
+ }
+ }
+ aStream.ReadLine( aLine );
+ pLine = aLine.GetBuffer();
+ nLen = aLine.Len();
+
+ // get up to 20 token positions
+ const int nMaxTokens = 20;
+ int nTokenPos[nMaxTokens];
+ nTokenPos[0] = 0;
+ int nTokens = 1;
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( pLine[i] == ';' )
+ {
+ nTokenPos[nTokens++] = i+1;
+ if( nTokens == nMaxTokens )
+ break;
+ }
+ }
+ if( nTokens < 18 )
+ {
+ delete pFont;
+ continue;
+ }
+ int nCollEntry = atoi( pLine );
+ pFont->m_nPSName = pAtoms->getAtom( ATOM_PSNAME, OUString( pLine + nTokenPos[1], nTokenPos[2]-nTokenPos[1]-1, RTL_TEXTENCODING_UTF8 ), sal_True );
+ pFont->m_eItalic = (italic::type)atoi( pLine+nTokenPos[2] );
+ pFont->m_eWeight = (weight::type)atoi( pLine+nTokenPos[3] );
+ pFont->m_eWidth = (width::type)atoi( pLine+nTokenPos[4] );
+ pFont->m_ePitch = (pitch::type)atoi( pLine+nTokenPos[5] );
+ pFont->m_aEncoding = (rtl_TextEncoding)atoi( pLine+nTokenPos[6] );
+ pFont->m_nAscend = atoi( pLine + nTokenPos[7] );
+ pFont->m_nDescend = atoi( pLine + nTokenPos[8] );
+ pFont->m_nLeading = atoi( pLine + nTokenPos[9] );
+ pFont->m_bHaveVerticalSubstitutedGlyphs
+ = (atoi( pLine + nTokenPos[10] ) != 0);
+ pFont->m_aGlobalMetricX.width
+ = atoi( pLine + nTokenPos[11] );
+ pFont->m_aGlobalMetricX.height
+ = atoi( pLine + nTokenPos[12] );
+ pFont->m_aGlobalMetricY.width
+ = atoi( pLine + nTokenPos[13] );
+ pFont->m_aGlobalMetricY.height
+ = atoi( pLine + nTokenPos[14] );
+ pFont->m_bUserOverride
+ = (atoi( pLine + nTokenPos[15] ) != 0);
+ pFont->m_eEmbeddedbitmap
+ = (fcstatus::type)atoi(pLine+nTokenPos[16]);
+ pFont->m_eAntialias = (fcstatus::type)atoi(pLine+nTokenPos[17]);
+ int nStyleTokenNr = 18;
+ switch( eType )
+ {
+ case fonttype::TrueType:
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nTypeFlags = atoi( pLine + nTokenPos[18] );
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry = nCollEntry;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile = aFile;
+ nStyleTokenNr++;
+ break;
+ case fonttype::Type1:
+ {
+ int nTokLen = (nTokens > 19 ) ? nTokenPos[19]-nTokenPos[18]-1 : nLen - nTokenPos[18];
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aMetricFile = OString( pLine + nTokenPos[18], nTokLen );
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile = aFile;
+ nStyleTokenNr++;
+ }
+ break;
+ case fonttype::Builtin:
+ static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory = nDir;
+ static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile = aFile;
+ break;
+ default: break;
+ }
+ if( nTokens > nStyleTokenNr )
+ pFont->m_aStyleName = OUString::intern( pLine + nTokenPos[nStyleTokenNr],
+ nLen - nTokenPos[nStyleTokenNr],
+ RTL_TEXTENCODING_UTF8 );
+
+ bool bObsolete = false;
+ if( bKeepOnlyUserOverridden )
+ {
+ if( pFont->m_bUserOverride )
+ {
+ ByteString aFilePath = rManager.getDirectory( nDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString(aFile) );
+ struct stat aStat;
+ if( stat( aFilePath.GetBuffer(), &aStat ) ||
+ ! S_ISREG( aStat.st_mode ) ||
+ aStat.st_size < 16 )
+ {
+ bObsolete = true;
+ }
+ #if OSL_DEBUG_LEVEL > 2
+ else
+ fprintf( stderr, "keeping file %s in outdated cache entry due to user override\n",
+ aFilePath.GetBuffer() );
+ #endif
+ }
+ else
+ bObsolete = true;
+ }
+ if( bObsolete )
+ {
+ m_bDoFlush = true;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "removing obsolete font %s\n", aFile.getStr() );
+#endif
+ delete pFont;
+ continue;
+ }
+
+ FontCacheEntry& rEntry = (*pDir)[aFile].m_aEntry;
+ rEntry.push_back( pFont );
+ }
+ }
+ } while( ! aStream.IsEof() );
+}
+
+/*
+ * FontCache::updateDirTimestamp
+ */
+void FontCache::updateDirTimestamp( int nDirID )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ const OString& rDir = rManager.getDirectory( nDirID );
+
+ struct stat aStat;
+ if( ! stat( rDir.getStr(), &aStat ) )
+ m_aCache[ nDirID ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+}
+
+
+/*
+ * FontCache::copyPrintFont
+ */
+void FontCache::copyPrintFont( const PrintFontManager::PrintFont* pFrom, PrintFontManager::PrintFont* pTo ) const
+{
+ if( pFrom->m_eType != pTo->m_eType )
+ return;
+ switch( pFrom->m_eType )
+ {
+ case fonttype::TrueType:
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_aFontFile;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nCollectionEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nCollectionEntry;
+ static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nTypeFlags = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nTypeFlags;
+ break;
+ case fonttype::Type1:
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aFontFile;
+ static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aMetricFile;
+ break;
+ case fonttype::Builtin:
+ static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_nDirectory;
+ static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_aMetricFile;
+ break;
+ default: break;
+ }
+ pTo->m_nFamilyName = pFrom->m_nFamilyName;
+ pTo->m_aStyleName = pFrom->m_aStyleName;
+ pTo->m_aAliases = pFrom->m_aAliases;
+ pTo->m_nPSName = pFrom->m_nPSName;
+ pTo->m_eItalic = pFrom->m_eItalic;
+ pTo->m_eWeight = pFrom->m_eWeight;
+ pTo->m_eWidth = pFrom->m_eWidth;
+ pTo->m_ePitch = pFrom->m_ePitch;
+ pTo->m_aEncoding = pFrom->m_aEncoding;
+ pTo->m_aGlobalMetricX = pFrom->m_aGlobalMetricX;
+ pTo->m_aGlobalMetricY = pFrom->m_aGlobalMetricY;
+ pTo->m_nAscend = pFrom->m_nAscend;
+ pTo->m_nDescend = pFrom->m_nDescend;
+ pTo->m_nLeading = pFrom->m_nLeading;
+ pTo->m_nXMin = pFrom->m_nXMin;
+ pTo->m_nYMin = pFrom->m_nYMin;
+ pTo->m_nXMax = pFrom->m_nXMax;
+ pTo->m_nYMax = pFrom->m_nYMax;
+ pTo->m_bHaveVerticalSubstitutedGlyphs = pFrom->m_bHaveVerticalSubstitutedGlyphs;
+ pTo->m_bUserOverride = pFrom->m_bUserOverride;
+ pTo->m_eEmbeddedbitmap = pFrom->m_eEmbeddedbitmap;
+ pTo->m_eAntialias = pFrom->m_eAntialias;
+}
+
+/*
+ * FontCache::equalsPrintFont
+ */
+bool FontCache::equalsPrintFont( const PrintFontManager::PrintFont* pLeft, PrintFontManager::PrintFont* pRight ) const
+{
+ if( pLeft->m_eType != pRight->m_eType )
+ return false;
+ switch( pLeft->m_eType )
+ {
+ case fonttype::TrueType:
+ {
+ const PrintFontManager::TrueTypeFontFile* pLT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pLeft);
+ const PrintFontManager::TrueTypeFontFile* pRT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aFontFile != pLT->m_aFontFile ||
+ pRT->m_nCollectionEntry != pLT->m_nCollectionEntry ||
+ pRT->m_nTypeFlags != pLT->m_nTypeFlags )
+ return false;
+ }
+ break;
+ case fonttype::Type1:
+ {
+ const PrintFontManager::Type1FontFile* pLT = static_cast<const PrintFontManager::Type1FontFile*>(pLeft);
+ const PrintFontManager::Type1FontFile* pRT = static_cast<const PrintFontManager::Type1FontFile*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aFontFile != pLT->m_aFontFile ||
+ pRT->m_aMetricFile != pLT->m_aMetricFile )
+ return false;
+ }
+ break;
+ case fonttype::Builtin:
+ {
+ const PrintFontManager::BuiltinFont* pLT = static_cast<const PrintFontManager::BuiltinFont*>(pLeft);
+ const PrintFontManager::BuiltinFont* pRT = static_cast<const PrintFontManager::BuiltinFont*>(pRight);
+ if( pRT->m_nDirectory != pLT->m_nDirectory ||
+ pRT->m_aMetricFile != pLT->m_aMetricFile )
+ return false;
+ }
+ break;
+ default: break;
+ }
+ if( pRight->m_nFamilyName != pLeft->m_nFamilyName ||
+ pRight->m_aStyleName != pLeft->m_aStyleName ||
+ pRight->m_nPSName != pLeft->m_nPSName ||
+ pRight->m_eItalic != pLeft->m_eItalic ||
+ pRight->m_eWeight != pLeft->m_eWeight ||
+ pRight->m_eWidth != pLeft->m_eWidth ||
+ pRight->m_ePitch != pLeft->m_ePitch ||
+ pRight->m_aEncoding != pLeft->m_aEncoding ||
+ pRight->m_aGlobalMetricX != pLeft->m_aGlobalMetricX ||
+ pRight->m_aGlobalMetricY != pLeft->m_aGlobalMetricY ||
+ pRight->m_nAscend != pLeft->m_nAscend ||
+ pRight->m_nDescend != pLeft->m_nDescend ||
+ pRight->m_nLeading != pLeft->m_nLeading ||
+ pRight->m_nXMin != pLeft->m_nXMin ||
+ pRight->m_nYMin != pLeft->m_nYMin ||
+ pRight->m_nXMax != pLeft->m_nXMax ||
+ pRight->m_nYMax != pLeft->m_nYMax ||
+ pRight->m_bHaveVerticalSubstitutedGlyphs != pLeft->m_bHaveVerticalSubstitutedGlyphs ||
+ pRight->m_bUserOverride != pLeft->m_bUserOverride ||
+ pRight->m_eEmbeddedbitmap != pLeft->m_eEmbeddedbitmap ||
+ pRight->m_eAntialias != pLeft->m_eAntialias
+ )
+ return false;
+ std::list< int >::const_iterator lit, rit;
+ for( lit = pLeft->m_aAliases.begin(), rit = pRight->m_aAliases.begin();
+ lit != pLeft->m_aAliases.end() && rit != pRight->m_aAliases.end() && (*lit) == (*rit);
+ ++lit, ++rit )
+ ;
+ return lit == pLeft->m_aAliases.end() && rit == pRight->m_aAliases.end();
+}
+
+/*
+ * FontCache::clonePrintFont
+ */
+PrintFontManager::PrintFont* FontCache::clonePrintFont( const PrintFontManager::PrintFont* pOldFont ) const
+{
+ PrintFontManager::PrintFont* pFont = NULL;
+ switch( pOldFont->m_eType )
+ {
+ case fonttype::TrueType:
+ pFont = new PrintFontManager::TrueTypeFontFile();
+ break;
+ case fonttype::Type1:
+ pFont = new PrintFontManager::Type1FontFile();
+ break;
+ case fonttype::Builtin:
+ pFont = new PrintFontManager::BuiltinFont();
+ break;
+ default: break;
+ }
+ if( pFont )
+ {
+ copyPrintFont( pOldFont, pFont );
+ }
+ return pFont;
+ }
+
+/*
+ * FontCache::getFontCacheFile
+ */
+bool FontCache::getFontCacheFile( int nDirID, const OString& rFile, list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ bool bSuccess = false;
+
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ if( dir != m_aCache.end() )
+ {
+ FontDirMap::const_iterator entry = dir->second.m_aEntries.find( rFile );
+ if( entry != dir->second.m_aEntries.end() )
+ {
+ for( FontCacheEntry::const_iterator font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
+ {
+ bSuccess = true;
+ PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
+ rNewFonts.push_back( pFont );
+ }
+ }
+ }
+ return bSuccess;
+}
+
+/*
+ * FontCache::updateFontCacheEntry
+ */
+void FontCache::updateFontCacheEntry( const PrintFontManager::PrintFont* pFont, bool bFlush )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ OString aFile;
+ int nDirID = 0;
+ switch( pFont->m_eType )
+ {
+ case fonttype::TrueType:
+ nDirID = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile;
+ break;
+ case fonttype::Type1:
+ nDirID = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile;
+ break;
+ case fonttype::Builtin:
+ nDirID = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory;
+ aFile = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile;
+ break;
+ default:
+ return;
+ }
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ FontDirMap::const_iterator entry;
+ FontCacheEntry::const_iterator font;
+ PrintFontManager::PrintFont* pCacheFont = NULL;
+
+ if( dir != m_aCache.end() )
+ {
+ entry = dir->second.m_aEntries.find( aFile );
+ if( entry != dir->second.m_aEntries.end() )
+ {
+ for( font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
+ {
+ if( (*font)->m_eType == pFont->m_eType &&
+ ( (*font)->m_eType != fonttype::TrueType ||
+ static_cast<const PrintFontManager::TrueTypeFontFile*>(*font)->m_nCollectionEntry == static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry
+ ) )
+ break;
+ }
+ if( font != entry->second.m_aEntry.end() )
+ pCacheFont = *font;
+ }
+ }
+ else
+ createCacheDir( nDirID );
+
+ if( pCacheFont )
+ {
+ if( ! equalsPrintFont( pFont, pCacheFont ) )
+ {
+ copyPrintFont( pFont, pCacheFont );
+ m_bDoFlush = true;
+ }
+ }
+ else
+ {
+ pCacheFont = clonePrintFont( pFont );
+ m_aCache[nDirID].m_aEntries[aFile].m_aEntry.push_back( pCacheFont );
+
+ ByteString aPath = rManager.getDirectory( nDirID );
+ aPath.Append( '/' );
+ aPath.Append( ByteString( aFile ) );
+ m_bDoFlush = true;
+ }
+ if( bFlush )
+ flush();
+}
+
+/*
+ * FontCache::listDirectory
+ */
+bool FontCache::listDirectory( const OString& rDir, std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ int nDirID = rManager.getDirectoryAtom( rDir );
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ bool bFound = (dir != m_aCache.end());
+
+ if( bFound && !dir->second.m_bNoFiles )
+ {
+ for( FontDirMap::const_iterator file = dir->second.m_aEntries.begin(); file != dir->second.m_aEntries.end(); ++file )
+ {
+ for( FontCacheEntry::const_iterator font = file->second.m_aEntry.begin(); font != file->second.m_aEntry.end(); ++font )
+ {
+ PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
+ rNewFonts.push_back( pFont );
+ }
+ }
+ }
+ return bFound;
+}
+
+/*
+ * FontCache::listDirectory
+ */
+bool FontCache::scanAdditionalFiles( const OString& rDir )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+ int nDirID = rManager.getDirectoryAtom( rDir );
+ FontCacheData::const_iterator dir = m_aCache.find( nDirID );
+ bool bFound = (dir != m_aCache.end());
+
+ return (bFound && dir->second.m_bUserOverrideOnly);
+}
+
+/*
+ * FontCache::createCacheDir
+ */
+void FontCache::createCacheDir( int nDirID )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ const OString& rDir = rManager.getDirectory( nDirID );
+ struct stat aStat;
+ if( ! stat( rDir.getStr(), &aStat ) )
+ m_aCache[nDirID].m_nTimestamp = (sal_Int64)aStat.st_mtime;
+}
+
+/*
+ * FontCache::markEmptyDir
+ */
+void FontCache::markEmptyDir( int nDirID, bool bNoFiles )
+{
+ createCacheDir( nDirID );
+ m_aCache[nDirID].m_bNoFiles = bNoFiles;
+ m_bDoFlush = true;
+}
diff --git a/vcl/unx/source/fontmanager/fontconfig.cxx b/vcl/unx/source/fontmanager/fontconfig.cxx
new file mode 100644
index 000000000000..c44e082f91bd
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontconfig.cxx
@@ -0,0 +1,1078 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: fontconfig.cxx,v $
+ * $Revision: 1.30.24.2 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "vcl/fontmanager.hxx"
+#include "vcl/fontcache.hxx"
+
+using namespace psp;
+
+#ifdef ENABLE_FONTCONFIG
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include <fontconfig/fcfreetype.h>
+// be compatible with fontconfig 2.2.0 release
+#ifndef FC_WEIGHT_BOOK
+ #define FC_WEIGHT_BOOK 75
+#endif
+#ifndef FC_EMBEDDED_BITMAP
+ #define FC_EMBEDDED_BITMAP "embeddedbitmap"
+#endif
+#ifndef FC_FAMILYLANG
+ #define FC_FAMILYLANG "familylang"
+#endif
+#else
+typedef void FcConfig;
+typedef void FcObjectSet;
+typedef void FcPattern;
+typedef void FcFontSet;
+typedef void FcCharSet;
+typedef int FcResult;
+typedef int FcBool;
+typedef int FcMatchKind;
+typedef char FcChar8;
+typedef int FcChar32;
+typedef unsigned int FT_UInt;
+typedef void* FT_Face;
+typedef int FcSetName;
+#endif
+
+#include <cstdio>
+#include <cstdarg>
+
+#include "unotools/atom.hxx"
+
+#include "osl/module.h"
+#include "osl/thread.h"
+#include "osl/process.h"
+
+#include "rtl/ustrbuf.hxx"
+#include "rtl/locale.hxx"
+
+#include "sal/alloca.h"
+
+#include <utility>
+#include <algorithm>
+
+using namespace osl;
+using namespace rtl;
+
+class FontCfgWrapper
+{
+ oslModule m_pLib;
+ FcFontSet* m_pOutlineSet;
+
+ FcBool (*m_pFcInit)();
+ int (*m_pFcGetVersion)();
+ FcConfig* (*m_pFcConfigGetCurrent)();
+ FcObjectSet* (*m_pFcObjectSetVaBuild)(const char*,va_list);
+ void (*m_pFcObjectSetDestroy)(FcObjectSet* pSet);
+ FcPattern* (*m_pFcPatternCreate)();
+ void (*m_pFcPatternDestroy)(FcPattern*);
+ FcFontSet* (*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*);
+ FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName);
+ FcFontSet* (*m_pFcFontSetCreate)();
+ FcCharSet* (*m_pFcCharSetCreate)();
+ FcBool (*m_pFcCharSetAddChar)(FcCharSet *, FcChar32);
+ FcBool (*m_pFcCharSetHasChar)(FcCharSet *, FcChar32);
+ void (*m_pFcCharSetDestroy)(FcCharSet*);
+ void (*m_pFcFontSetDestroy)(FcFontSet*);
+ FcBool (*m_pFcFontSetAdd)(FcFontSet*,FcPattern*);
+ void (*m_pFcPatternReference)(FcPattern*);
+ FcResult (*m_pFcPatternGetCharSet)(const FcPattern*,const char*,int,FcCharSet**);
+ FcResult (*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**);
+ FcResult (*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*);
+ FcResult (*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*);
+ FcResult (*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*);
+ void (*m_pFcDefaultSubstitute)(FcPattern *);
+ FcPattern* (*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*);
+ FcBool (*m_pFcConfigAppFontAddFile)(FcConfig*, const FcChar8*);
+ FcBool (*m_pFcConfigAppFontAddDir)(FcConfig*, const FcChar8*);
+ FcBool (*m_pFcConfigSubstitute)(FcConfig*,FcPattern*,FcMatchKind);
+ FcBool (*m_pFcPatternAddInteger)(FcPattern*,const char*,int);
+ FcBool (*m_pFcPatternAddBool)(FcPattern*,const char*,FcBool);
+ FcBool (*m_pFcPatternAddCharSet)(FcPattern*,const char*,const FcCharSet*);
+ FcBool (*m_pFcPatternAddString)(FcPattern*,const char*,const FcChar8*);
+ FT_UInt (*m_pFcFreeTypeCharIndex)(FT_Face,FcChar32);
+
+ oslGenericFunction loadSymbol( const char* );
+ void addFontSet( FcSetName );
+
+ FontCfgWrapper();
+ ~FontCfgWrapper();
+
+public:
+ static FontCfgWrapper& get();
+ static void release();
+
+ bool isValid() const
+ { return m_pLib != NULL;}
+
+ FcFontSet* getFontSet();
+
+ FcBool FcInit()
+ { return m_pFcInit(); }
+
+ int FcGetVersion()
+ { return m_pFcGetVersion(); }
+
+ FcConfig* FcConfigGetCurrent()
+ { return m_pFcConfigGetCurrent(); }
+
+ FcObjectSet* FcObjectSetBuild( const char* first, ... )
+ {
+ va_list ap;
+ va_start( ap, first );
+ FcObjectSet* pSet = m_pFcObjectSetVaBuild( first, ap );
+ va_end( ap );
+ return pSet;
+ }
+
+ void FcObjectSetDestroy( FcObjectSet* pSet )
+ { m_pFcObjectSetDestroy( pSet ); }
+
+ FcPattern* FcPatternCreate()
+ { return m_pFcPatternCreate(); }
+
+ void FcPatternDestroy( FcPattern* pPattern )
+ { m_pFcPatternDestroy( pPattern ); }
+
+ FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet )
+ { return m_pFcFontList( pConfig, pPattern, pSet ); }
+
+ FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet)
+ { return m_pFcConfigGetFonts( pConfig, eSet ); }
+
+ FcFontSet* FcFontSetCreate()
+ { return m_pFcFontSetCreate(); }
+
+ FcCharSet* FcCharSetCreate()
+ { return m_pFcCharSetCreate(); }
+
+ FcBool FcCharSetAddChar(FcCharSet *fcs, FcChar32 ucs4)
+ { return m_pFcCharSetAddChar(fcs, ucs4); }
+
+ FcBool FcCharSetHasChar(FcCharSet *fcs, FcChar32 ucs4)
+ { return m_pFcCharSetHasChar(fcs, ucs4); }
+
+ void FcCharSetDestroy( FcCharSet* pSet )
+ { m_pFcCharSetDestroy( pSet );}
+
+ void FcFontSetDestroy( FcFontSet* pSet )
+ { m_pFcFontSetDestroy( pSet );}
+
+ FcBool FcFontSetAdd( FcFontSet* pSet, FcPattern* pPattern )
+ { return m_pFcFontSetAdd( pSet, pPattern ); }
+
+ void FcPatternReference( FcPattern* pPattern )
+ { m_pFcPatternReference( pPattern ); }
+
+ FcResult FcPatternGetCharSet( const FcPattern* pPattern, const char* object, int n, FcCharSet** s )
+ { return m_pFcPatternGetCharSet( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetString( const FcPattern* pPattern, const char* object, int n, FcChar8** s )
+ { return m_pFcPatternGetString( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetInteger( const FcPattern* pPattern, const char* object, int n, int* s )
+ { return m_pFcPatternGetInteger( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s )
+ { return m_pFcPatternGetDouble( pPattern, object, n, s ); }
+
+ FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s )
+ { return m_pFcPatternGetBool( pPattern, object, n, s ); }
+ FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName )
+ { return m_pFcConfigAppFontAddFile( pConfig, pFileName ); }
+ FcBool FcConfigAppFontAddDir(FcConfig* pConfig, const FcChar8* pDirName )
+ { return m_pFcConfigAppFontAddDir( pConfig, pDirName ); }
+ void FcDefaultSubstitute( FcPattern* pPattern )
+ { m_pFcDefaultSubstitute( pPattern ); }
+ FcPattern* FcFontSetMatch( FcConfig* pConfig, FcFontSet **ppFontSet, int nset, FcPattern* pPattern, FcResult* pResult )
+ { return m_pFcFontSetMatch ? m_pFcFontSetMatch( pConfig, ppFontSet, nset, pPattern, pResult ) : 0; }
+ FcBool FcConfigSubstitute( FcConfig* pConfig, FcPattern* pPattern, FcMatchKind eKind )
+ { return m_pFcConfigSubstitute( pConfig, pPattern, eKind ); }
+ FcBool FcPatternAddInteger( FcPattern* pPattern, const char* pObject, int nValue )
+ { return m_pFcPatternAddInteger( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddString( FcPattern* pPattern, const char* pObject, const FcChar8* pString )
+ { return m_pFcPatternAddString( pPattern, pObject, pString ); }
+ FcBool FcPatternAddBool( FcPattern* pPattern, const char* pObject, bool nValue )
+ { return m_pFcPatternAddBool( pPattern, pObject, nValue ); }
+ FcBool FcPatternAddCharSet(FcPattern* pPattern,const char* pObject,const FcCharSet*pCharSet)
+ { return m_pFcPatternAddCharSet(pPattern,pObject,pCharSet); }
+
+ FT_UInt FcFreeTypeCharIndex( FT_Face face, FcChar32 ucs4 )
+ { return m_pFcFreeTypeCharIndex ? m_pFcFreeTypeCharIndex( face, ucs4 ) : 0; }
+
+public: // TODO: cleanup
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > m_aFontconfigNameToLocalized;
+};
+
+oslGenericFunction FontCfgWrapper::loadSymbol( const char* pSymbol )
+{
+ OUString aSym( OUString::createFromAscii( pSymbol ) );
+ oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
+#endif
+ return pSym;
+}
+
+FontCfgWrapper::FontCfgWrapper()
+ : m_pLib( NULL ),
+ m_pOutlineSet( NULL )
+{
+ OUString aLib( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so.1" ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ if( !m_pLib )
+ {
+ aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( "libfontconfig.so" ) );
+ m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
+ }
+
+ if( ! m_pLib )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "no libfontconfig\n" );
+#endif
+ return;
+ }
+
+ m_pFcInit = (FcBool(*)())
+ loadSymbol( "FcInit" );
+ m_pFcGetVersion = (int(*)())
+ loadSymbol( "FcGetVersion" );
+ m_pFcConfigGetCurrent = (FcConfig *(*)())
+ loadSymbol( "FcConfigGetCurrent" );
+ m_pFcObjectSetVaBuild = (FcObjectSet*(*)(const char*,va_list))
+ loadSymbol( "FcObjectSetVaBuild" );
+ m_pFcObjectSetDestroy = (void(*)(FcObjectSet*))
+ loadSymbol( "FcObjectSetDestroy" );
+ m_pFcPatternCreate = (FcPattern*(*)())
+ loadSymbol( "FcPatternCreate" );
+ m_pFcPatternDestroy = (void(*)(FcPattern*))
+ loadSymbol( "FcPatternDestroy" );
+ m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*))
+ loadSymbol( "FcFontList" );
+ m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName))
+ loadSymbol( "FcConfigGetFonts" );
+ m_pFcFontSetCreate = (FcFontSet*(*)())
+ loadSymbol( "FcFontSetCreate" );
+ m_pFcCharSetCreate = (FcCharSet*(*)())
+ loadSymbol( "FcCharSetCreate" );
+ m_pFcCharSetAddChar = (FcBool(*)(FcCharSet*, FcChar32))
+ loadSymbol( "FcCharSetAddChar" );
+ m_pFcCharSetHasChar = (FcBool(*)(FcCharSet*, FcChar32))
+ loadSymbol( "FcCharSetHasChar" );
+ m_pFcCharSetDestroy = (void(*)(FcCharSet*))
+ loadSymbol( "FcCharSetDestroy" );
+ m_pFcFontSetDestroy = (void(*)(FcFontSet*))
+ loadSymbol( "FcFontSetDestroy" );
+ m_pFcFontSetAdd = (FcBool(*)(FcFontSet*,FcPattern*))
+ loadSymbol( "FcFontSetAdd" );
+ m_pFcPatternReference = (void(*)(FcPattern*))
+ loadSymbol( "FcPatternReference" );
+ m_pFcPatternGetCharSet = (FcResult(*)(const FcPattern*,const char*,int,FcCharSet**))
+ loadSymbol( "FcPatternGetCharSet" );
+ m_pFcPatternGetString = (FcResult(*)(const FcPattern*,const char*,int,FcChar8**))
+ loadSymbol( "FcPatternGetString" );
+ m_pFcPatternGetInteger = (FcResult(*)(const FcPattern*,const char*,int,int*))
+ loadSymbol( "FcPatternGetInteger" );
+ m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*))
+ loadSymbol( "FcPatternGetDouble" );
+ m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*))
+ loadSymbol( "FcPatternGetBool" );
+ m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*))
+ loadSymbol( "FcConfigAppFontAddFile" );
+ m_pFcConfigAppFontAddDir = (FcBool(*)(FcConfig*, const FcChar8*))
+ loadSymbol( "FcConfigAppFontAddDir" );
+ m_pFcDefaultSubstitute = (void(*)(FcPattern *))
+ loadSymbol( "FcDefaultSubstitute" );
+ m_pFcFontSetMatch = (FcPattern*(*)(FcConfig*,FcFontSet**,int,FcPattern*,FcResult*))
+ loadSymbol( "FcFontSetMatch" );
+ m_pFcConfigSubstitute = (FcBool(*)(FcConfig*,FcPattern*,FcMatchKind))
+ loadSymbol( "FcConfigSubstitute" );
+ m_pFcPatternAddInteger = (FcBool(*)(FcPattern*,const char*,int))
+ loadSymbol( "FcPatternAddInteger" );
+ m_pFcPatternAddBool = (FcBool(*)(FcPattern*,const char*,FcBool))
+ loadSymbol( "FcPatternAddBool" );
+ m_pFcPatternAddCharSet = (FcBool(*)(FcPattern*,const char*,const FcCharSet *))
+ loadSymbol( "FcPatternAddCharSet" );
+ m_pFcPatternAddString = (FcBool(*)(FcPattern*,const char*,const FcChar8*))
+ loadSymbol( "FcPatternAddString" );
+ m_pFcFreeTypeCharIndex = (FT_UInt(*)(FT_Face,FcChar32))
+ loadSymbol( "FcFreeTypeCharIndex" );
+
+ if( ! (
+ m_pFcInit &&
+ m_pFcGetVersion &&
+ m_pFcConfigGetCurrent &&
+ m_pFcObjectSetVaBuild &&
+ m_pFcObjectSetDestroy &&
+ m_pFcPatternCreate &&
+ m_pFcPatternDestroy &&
+ m_pFcFontList &&
+ m_pFcConfigGetFonts &&
+ m_pFcFontSetCreate &&
+ m_pFcCharSetCreate &&
+ m_pFcCharSetAddChar &&
+ m_pFcCharSetHasChar &&
+ m_pFcCharSetDestroy &&
+ m_pFcFontSetDestroy &&
+ m_pFcFontSetAdd &&
+ m_pFcPatternReference &&
+ m_pFcPatternGetCharSet &&
+ m_pFcPatternGetString &&
+ m_pFcPatternGetInteger &&
+ m_pFcPatternGetDouble &&
+ m_pFcPatternGetBool &&
+ m_pFcConfigAppFontAddFile &&
+ m_pFcConfigAppFontAddDir &&
+ m_pFcDefaultSubstitute &&
+ m_pFcConfigSubstitute &&
+ m_pFcPatternAddInteger &&
+ m_pFcPatternAddCharSet &&
+ m_pFcPatternAddBool &&
+ m_pFcPatternAddString
+ ) )
+ {
+ osl_unloadModule( (oslModule)m_pLib );
+ m_pLib = NULL;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "not all needed symbols were found in libfontconfig\n" );
+#endif
+ return;
+ }
+
+
+ FcInit();
+ if( ! FcConfigGetCurrent() )
+ {
+ osl_unloadModule( (oslModule)m_pLib );
+ m_pLib = NULL;
+ }
+}
+
+void FontCfgWrapper::addFontSet( FcSetName eSetName )
+{
+ #ifdef ENABLE_FONTCONFIG
+ /*
+ add only acceptable outlined fonts to our config,
+ for future fontconfig use
+ */
+ FcFontSet* pOrig = FcConfigGetFonts( FcConfigGetCurrent(), eSetName );
+ if( !pOrig )
+ return;
+
+ for( int i = 0; i < pOrig->nfont; ++i )
+ {
+ FcBool outline = false;
+ FcPattern *pOutlinePattern = pOrig->fonts[i];
+ FcResult eOutRes =
+ FcPatternGetBool( pOutlinePattern, FC_OUTLINE, 0, &outline );
+ if( (eOutRes != FcResultMatch) || (outline != FcTrue) )
+ continue;
+ FcPatternReference(pOutlinePattern);
+ FcFontSetAdd(m_pOutlineSet, pOutlinePattern);
+ }
+ // TODO: FcFontSetDestroy( pOrig );
+ #else
+ (void)eSetName; // prevent compiler warning about unused parameter
+ #endif
+}
+
+FcFontSet* FontCfgWrapper::getFontSet()
+{
+ #ifdef ENABLE_FONTCONFIG
+ if( !m_pOutlineSet )
+ {
+ m_pOutlineSet = FcFontSetCreate();
+ addFontSet( FcSetSystem );
+ const int nVersion = FcGetVersion();
+ if( nVersion > 20400 )
+ addFontSet( FcSetApplication );
+ }
+ #endif
+
+ return m_pOutlineSet;
+}
+
+FontCfgWrapper::~FontCfgWrapper()
+{
+ if( m_pOutlineSet )
+ FcFontSetDestroy( m_pOutlineSet );
+ if( m_pLib )
+ osl_unloadModule( (oslModule)m_pLib );
+}
+
+static FontCfgWrapper* pOneInstance = NULL;
+
+FontCfgWrapper& FontCfgWrapper::get()
+{
+ if( ! pOneInstance )
+ pOneInstance = new FontCfgWrapper();
+ return *pOneInstance;
+}
+
+void FontCfgWrapper::release()
+{
+ if( pOneInstance )
+ {
+ delete pOneInstance;
+ pOneInstance = NULL;
+ }
+}
+
+#ifdef ENABLE_FONTCONFIG
+namespace
+{
+ typedef std::pair<FcChar8*, FcChar8*> lang_and_family;
+
+ class localizedsorter
+ {
+ rtl::OLocale maLoc;
+ public:
+ localizedsorter(rtl_Locale* pLoc) : maLoc(pLoc) {}
+ FcChar8* bestname(const std::vector<lang_and_family> &families);
+ };
+
+ FcChar8* localizedsorter::bestname(const std::vector<lang_and_family> &families)
+ {
+ FcChar8* candidate = families.begin()->second;
+ rtl::OString sLangMatch(rtl::OUStringToOString(maLoc.getLanguage().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8));
+ rtl::OString sFullMatch = sLangMatch;
+ sFullMatch += OString('-');
+ sFullMatch += rtl::OUStringToOString(maLoc.getCountry().toAsciiLowerCase(), RTL_TEXTENCODING_UTF8);
+
+ std::vector<lang_and_family>::const_iterator aEnd = families.end();
+ bool alreadyclosematch = false;
+ for (std::vector<lang_and_family>::const_iterator aIter = families.begin(); aIter != aEnd; ++aIter)
+ {
+ const char *pLang = (const char*)aIter->first;
+ //perfect
+ if( rtl_str_compare(pLang,sFullMatch.getStr() ) == 0)
+ {
+ candidate = aIter->second;
+ break;
+ }
+ else if( (rtl_str_compare(pLang,sLangMatch.getStr()) == 0) && (!alreadyclosematch))
+ {
+ candidate = aIter->second;
+ alreadyclosematch = true;
+ }
+ }
+
+ return candidate;
+ }
+
+
+ FcResult lcl_FamilyFromPattern(FontCfgWrapper& rWrapper, FcPattern* pPattern, FcChar8 **family,
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash > &aFontconfigNameToLocalized)
+ {
+ FcChar8 *origfamily;
+ FcResult eFamilyRes = rWrapper.FcPatternGetString( pPattern, FC_FAMILY, 0, &origfamily );
+ *family = origfamily;
+
+ if( eFamilyRes == FcResultMatch)
+ {
+ FcChar8* familylang = NULL;
+ if (rWrapper.FcPatternGetString( pPattern, FC_FAMILYLANG, 0, &familylang ) == FcResultMatch)
+ {
+ std::vector< lang_and_family > lang_and_families;
+ lang_and_families.push_back(lang_and_family(familylang, *family));
+ int k = 1;
+ while (1)
+ {
+ if (rWrapper.FcPatternGetString( pPattern, FC_FAMILYLANG, k, &familylang ) != FcResultMatch)
+ break;
+ if (rWrapper.FcPatternGetString( pPattern, FC_FAMILY, k, family ) != FcResultMatch)
+ break;
+ lang_and_families.push_back(lang_and_family(familylang, *family));
+ ++k;
+ }
+
+ //possible to-do, sort by UILocale instead of process locale
+ rtl_Locale* pLoc;
+ osl_getProcessLocale(&pLoc);
+ localizedsorter aSorter(pLoc);
+ *family = aSorter.bestname(lang_and_families);
+
+ std::vector<lang_and_family>::const_iterator aEnd = lang_and_families.end();
+ for (std::vector<lang_and_family>::const_iterator aIter = lang_and_families.begin(); aIter != aEnd; ++aIter)
+ {
+ const char *candidate = (const char*)(aIter->second);
+ if (rtl_str_compare(candidate, (const char*)(*family)) != 0)
+ aFontconfigNameToLocalized[OString(candidate)] = OString((const char*)(*family));
+ }
+ }
+ }
+
+ return eFamilyRes;
+ }
+}
+
+
+/*
+ * PrintFontManager::initFontconfig
+ */
+bool PrintFontManager::initFontconfig()
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+ return true;
+}
+
+int PrintFontManager::countFontconfigFonts()
+{
+ int nFonts = 0;
+
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( !rWrapper.isValid() )
+ return 0;
+
+ FcFontSet* pFSet = rWrapper.getFontSet();
+ if( pFSet )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %d entries in fontconfig fontset\n", pFSet->nfont );
+#endif
+ for( int i = 0; i < pFSet->nfont; i++ )
+ {
+ FcChar8* file = NULL;
+ FcChar8* family = NULL;
+ FcChar8* style = NULL;
+ int slant = 0;
+ int weight = 0;
+ int spacing = 0;
+ int nCollectionEntry = -1;
+ FcBool outline = false, embitmap = true, antialias = true;
+
+ FcResult eFileRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_FILE, 0, &file );
+ FcResult eFamilyRes = lcl_FamilyFromPattern(rWrapper, pFSet->fonts[i], &family, rWrapper.m_aFontconfigNameToLocalized );
+ FcResult eStyleRes = rWrapper.FcPatternGetString( pFSet->fonts[i], FC_STYLE, 0, &style );
+ FcResult eSlantRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SLANT, 0, &slant );
+ FcResult eWeightRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_WEIGHT, 0, &weight );
+ FcResult eSpacRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_SPACING, 0, &spacing );
+ FcResult eOutRes = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_OUTLINE, 0, &outline );
+ FcResult eIndexRes = rWrapper.FcPatternGetInteger( pFSet->fonts[i], FC_INDEX, 0, &nCollectionEntry );
+ FcResult eEmbeddedBitmap = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_EMBEDDED_BITMAP, 0, &embitmap );
+ FcResult eAntialias = rWrapper.FcPatternGetBool( pFSet->fonts[i], FC_ANTIALIAS, 0, &antialias );
+
+ if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eOutRes != FcResultMatch )
+ continue;
+
+#if (OSL_DEBUG_LEVEL > 2)
+ fprintf( stderr, "found font \"%s\" in file %s\n"
+ " weight = %d, slant = %d, style = \"%s\"\n"
+ " spacing = %d, outline = %d\n"
+ , family, file
+ , eWeightRes == FcResultMatch ? weight : -1
+ , eSpacRes == FcResultMatch ? slant : -1
+ , eStyleRes == FcResultMatch ? (const char*) style : "<nil>"
+ , eSpacRes == FcResultMatch ? spacing : -1
+ , eOutRes == FcResultMatch ? outline : -1
+ );
+#endif
+
+ OSL_ASSERT(eOutRes != FcResultMatch || outline);
+
+ // only outline fonts are usable to psprint anyway
+ if( eOutRes == FcResultMatch && ! outline )
+ continue;
+
+ // see if this font is already cached
+ // update attributes
+ std::list< PrintFont* > aFonts;
+ OString aDir, aBase, aOrgPath( (sal_Char*)file );
+ splitPath( aOrgPath, aDir, aBase );
+ int nDirID = getDirectoryAtom( aDir, true );
+ if( ! m_pFontCache->getFontCacheFile( nDirID, aBase, aFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "file %s not cached\n", aBase.getStr() );
+#endif
+ // not known, analyze font file to get attributes
+ // not described by fontconfig (e.g. alias names, PSName)
+ std::list< OString > aDummy;
+ analyzeFontFile( nDirID, aBase, aDummy, aFonts );
+#if OSL_DEBUG_LEVEL > 1
+ if( aFonts.empty() )
+ fprintf( stderr, "Warning: file \"%s\" is unusable to psprint\n", aOrgPath.getStr() );
+#endif
+ }
+ if( aFonts.empty() )
+ continue;
+
+ int nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( OString( (sal_Char*)family ), RTL_TEXTENCODING_UTF8 ), sal_True );
+ PrintFont* pUpdate = aFonts.front();
+ std::list<PrintFont*>::const_iterator second_font = aFonts.begin();
+ ++second_font;
+ if( second_font != aFonts.end() ) // more than one font
+ {
+ // a collection entry, get the correct index
+ if( eIndexRes == FcResultMatch && nCollectionEntry != -1 )
+ {
+ for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( (*it)->m_eType == fonttype::TrueType &&
+ static_cast<TrueTypeFontFile*>(*it)->m_nCollectionEntry == nCollectionEntry )
+ {
+ pUpdate = *it;
+ break;
+ }
+ }
+ // update collection entry
+ // additional entries will be created in the cache
+ // if this is a new index (that is if the loop above
+ // ran to the end of the list)
+ if( pUpdate->m_eType == fonttype::TrueType ) // sanity check, this should always be the case here
+ static_cast<TrueTypeFontFile*>(pUpdate)->m_nCollectionEntry = nCollectionEntry;
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "multiple fonts for file, but no index in fontconfig pattern ! (index res = %d collection entry = %d\nfile will not be used\n", eIndexRes, nCollectionEntry );
+#endif
+ // we have found more than one font in this file
+ // but fontconfig will not tell us which index is meant
+ // -> something is in disorder, do not use this font
+ pUpdate = NULL;
+ }
+ }
+
+ if( pUpdate )
+ {
+ // set family name
+ if( pUpdate->m_nFamilyName != nFamilyName )
+ {
+ pUpdate->m_aAliases.remove( pUpdate->m_nFamilyName );
+ pUpdate->m_aAliases.push_back( pUpdate->m_nFamilyName );
+ pUpdate->m_aAliases.remove( nFamilyName );
+ pUpdate->m_nFamilyName = nFamilyName;
+ }
+ if( eWeightRes == FcResultMatch )
+ {
+ // set weight
+ if( weight <= FC_WEIGHT_THIN )
+ pUpdate->m_eWeight = weight::Thin;
+ else if( weight <= FC_WEIGHT_ULTRALIGHT )
+ pUpdate->m_eWeight = weight::UltraLight;
+ else if( weight <= FC_WEIGHT_LIGHT )
+ pUpdate->m_eWeight = weight::Light;
+ else if( weight <= FC_WEIGHT_BOOK )
+ pUpdate->m_eWeight = weight::SemiLight;
+ else if( weight <= FC_WEIGHT_NORMAL )
+ pUpdate->m_eWeight = weight::Normal;
+ else if( weight <= FC_WEIGHT_MEDIUM )
+ pUpdate->m_eWeight = weight::Medium;
+ else if( weight <= FC_WEIGHT_SEMIBOLD )
+ pUpdate->m_eWeight = weight::SemiBold;
+ else if( weight <= FC_WEIGHT_BOLD )
+ pUpdate->m_eWeight = weight::Bold;
+ else if( weight <= FC_WEIGHT_ULTRABOLD )
+ pUpdate->m_eWeight = weight::UltraBold;
+ else
+ pUpdate->m_eWeight = weight::Black;
+ }
+ if( eSpacRes == FcResultMatch )
+ {
+ // set pitch
+ if( spacing == FC_PROPORTIONAL )
+ pUpdate->m_ePitch = pitch::Variable;
+ else if( spacing == FC_MONO || spacing == FC_CHARCELL )
+ pUpdate->m_ePitch = pitch::Fixed;
+ }
+ if( eSlantRes == FcResultMatch )
+ {
+ // set italic
+ if( slant == FC_SLANT_ROMAN )
+ pUpdate->m_eItalic = italic::Upright;
+ else if( slant == FC_SLANT_ITALIC )
+ pUpdate->m_eItalic = italic::Italic;
+ else if( slant == FC_SLANT_OBLIQUE )
+ pUpdate->m_eItalic = italic::Oblique;
+ }
+ if( eStyleRes == FcResultMatch )
+ {
+ pUpdate->m_aStyleName = OStringToOUString( OString( (sal_Char*)style ), RTL_TEXTENCODING_UTF8 );
+ }
+ if( eEmbeddedBitmap == FcResultMatch )
+ {
+ pUpdate->m_eEmbeddedbitmap = embitmap ? fcstatus::istrue : fcstatus::isfalse;
+ }
+ if( eAntialias == FcResultMatch )
+ {
+ pUpdate->m_eAntialias = antialias ? fcstatus::istrue : fcstatus::isfalse;
+ }
+
+
+ // update font cache
+ m_pFontCache->updateFontCacheEntry( pUpdate, false );
+ // sort into known fonts
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = pUpdate;
+ m_aFontFileToFontID[ aBase ].insert( aFont );
+ nFonts++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "inserted font %s as fontID %d\n", family, aFont );
+#endif
+ }
+ // clean up the fonts we did not put into the list
+ for( std::list< PrintFont* >::iterator it = aFonts.begin(); it != aFonts.end(); ++it )
+ {
+ if( *it != pUpdate )
+ {
+ m_pFontCache->updateFontCacheEntry( *it, false ); // prepare a cache entry for a collection item
+ delete *it;
+ }
+ }
+ }
+ }
+
+ // how does one get rid of the config ?
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "inserted %d fonts from fontconfig\n", nFonts );
+#endif
+ return nFonts;
+}
+
+void PrintFontManager::deinitFontconfig()
+{
+ FontCfgWrapper::release();
+}
+
+int PrintFontManager::FreeTypeCharIndex( void *pFace, sal_uInt32 aChar )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ return rWrapper.isValid() ? rWrapper.FcFreeTypeCharIndex( (FT_Face)pFace, aChar ) : 0;
+}
+
+bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ // workaround for a stability problems in older FC versions
+ // when handling application specifc fonts
+ const int nVersion = rWrapper.FcGetVersion();
+ if( nVersion <= 20400 )
+ return false;
+ const char* pDirName = (const char*)rDirName.getStr();
+ bool bRet = (rWrapper.FcConfigAppFontAddDir( rWrapper.FcConfigGetCurrent(), (FcChar8*)pDirName ) == FcTrue);
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bRet );
+#endif
+
+ return bRet;
+}
+
+static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern,
+ italic::type eItalic, weight::type eWeight, width::type eWidth, pitch::type ePitch)
+{
+ if( eItalic != italic::Unknown )
+ {
+ int nSlant = FC_SLANT_ROMAN;
+ switch( eItalic )
+ {
+ case italic::Italic: nSlant = FC_SLANT_ITALIC;break;
+ case italic::Oblique: nSlant = FC_SLANT_OBLIQUE;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_SLANT, nSlant );
+ }
+ if( eWeight != weight::Unknown )
+ {
+ int nWeight = FC_WEIGHT_NORMAL;
+ switch( eWeight )
+ {
+ case weight::Thin: nWeight = FC_WEIGHT_THIN;break;
+ case weight::UltraLight: nWeight = FC_WEIGHT_ULTRALIGHT;break;
+ case weight::Light: nWeight = FC_WEIGHT_LIGHT;break;
+ case weight::SemiLight: nWeight = FC_WEIGHT_BOOK;break;
+ case weight::Normal: nWeight = FC_WEIGHT_NORMAL;break;
+ case weight::Medium: nWeight = FC_WEIGHT_MEDIUM;break;
+ case weight::SemiBold: nWeight = FC_WEIGHT_SEMIBOLD;break;
+ case weight::Bold: nWeight = FC_WEIGHT_BOLD;break;
+ case weight::UltraBold: nWeight = FC_WEIGHT_ULTRABOLD;break;
+ case weight::Black: nWeight = FC_WEIGHT_BLACK;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_WEIGHT, nWeight );
+ }
+ if( eWidth != width::Unknown )
+ {
+ int nWidth = FC_WIDTH_NORMAL;
+ switch( eWidth )
+ {
+ case width::UltraCondensed: nWidth = FC_WIDTH_ULTRACONDENSED;break;
+ case width::ExtraCondensed: nWidth = FC_WIDTH_EXTRACONDENSED;break;
+ case width::Condensed: nWidth = FC_WIDTH_CONDENSED;break;
+ case width::SemiCondensed: nWidth = FC_WIDTH_SEMICONDENSED;break;
+ case width::Normal: nWidth = FC_WIDTH_NORMAL;break;
+ case width::SemiExpanded: nWidth = FC_WIDTH_SEMIEXPANDED;break;
+ case width::Expanded: nWidth = FC_WIDTH_EXPANDED;break;
+ case width::ExtraExpanded: nWidth = FC_WIDTH_EXTRAEXPANDED;break;
+ case width::UltraExpanded: nWidth = FC_WIDTH_ULTRACONDENSED;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_WIDTH, nWidth );
+ }
+ if( ePitch != pitch::Unknown )
+ {
+ int nSpacing = FC_PROPORTIONAL;
+ switch( ePitch )
+ {
+ case pitch::Fixed: nSpacing = FC_MONO;break;
+ case pitch::Variable: nSpacing = FC_PROPORTIONAL;break;
+ default:
+ break;
+ }
+ rWrapper.FcPatternAddInteger( pPattern, FC_SPACING, nSpacing );
+ if (nSpacing == FC_MONO)
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)"monospace");
+ }
+}
+
+rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
+ rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
+ italic::type eItalic, weight::type eWeight,
+ width::type eWidth, pitch::type ePitch) const
+{
+ rtl::OUString aName;
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return aName;
+
+ // build pattern argument for fontconfig query
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ // Prefer scalable fonts
+ rWrapper.FcPatternAddBool( pPattern, FC_SCALABLE, FcTrue );
+
+ const rtl::OString aTargetName = rtl::OUStringToOString( rFontName, RTL_TEXTENCODING_UTF8 );
+ const FcChar8* pTargetNameUtf8 = (FcChar8*)aTargetName.getStr();
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, pTargetNameUtf8 );
+
+ const FcChar8* pLangAttribUtf8 = (FcChar8*)rLangAttrib.getStr();
+ if( rLangAttrib.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_LANG, pLangAttribUtf8 );
+
+ // Add required Unicode characters, if any
+ if ( rMissingCodes.getLength() )
+ {
+ FcCharSet *unicodes = rWrapper.FcCharSetCreate();
+ for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ // also handle unicode surrogates
+ const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
+ rWrapper.FcCharSetAddChar( unicodes, nCode );
+ }
+ rWrapper.FcPatternAddCharSet( pPattern, FC_CHARSET, unicodes);
+ rWrapper.FcCharSetDestroy( unicodes );
+ }
+
+ addtopattern(rWrapper, pPattern, eItalic, eWeight, eWidth, ePitch);
+
+ // query fontconfig for a substitute
+ rWrapper.FcConfigSubstitute( rWrapper.FcConfigGetCurrent(), pPattern, FcMatchPattern );
+ rWrapper.FcDefaultSubstitute( pPattern );
+
+ // process the result of the fontconfig query
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet* pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( rWrapper.FcConfigGetCurrent(), &pFontSet, 1, pPattern, &eResult );
+ rWrapper.FcPatternDestroy( pPattern );
+
+ FcFontSet* pSet = NULL;
+ if( pResult )
+ {
+ pSet = rWrapper.FcFontSetCreate();
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ }
+
+ if( pSet )
+ {
+ if( pSet->nfont > 0 )
+ {
+ //extract the closest match
+ FcChar8* family = NULL;
+ FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FAMILY, 0, &family );
+
+ // get the family name
+ if( eFileRes == FcResultMatch )
+ {
+ OString sFamily((sal_Char*)family);
+ std::hash_map< rtl::OString, rtl::OString, rtl::OStringHash >::const_iterator aI = rWrapper.m_aFontconfigNameToLocalized.find(sFamily);
+ if (aI != rWrapper.m_aFontconfigNameToLocalized.end())
+ sFamily = aI->second;
+ aName = rtl::OStringToOUString( sFamily, RTL_TEXTENCODING_UTF8 );
+ }
+
+ // update rMissingCodes by removing resolved unicodes
+ if( rMissingCodes.getLength() > 0 )
+ {
+ sal_uInt32* pRemainingCodes = (sal_uInt32*)alloca( rMissingCodes.getLength() * sizeof(sal_uInt32) );
+ int nRemainingLen = 0;
+ FcCharSet* unicodes;
+ if( !rWrapper.FcPatternGetCharSet( pSet->fonts[0], FC_CHARSET, 0, &unicodes ) )
+ {
+ for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
+ {
+ // also handle unicode surrogates
+ const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );
+ if( rWrapper.FcCharSetHasChar( unicodes, nCode ) != FcTrue )
+ pRemainingCodes[ nRemainingLen++ ] = nCode;
+ }
+ }
+ rMissingCodes = OUString( pRemainingCodes, nRemainingLen );
+ }
+ }
+
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ return aName;
+}
+
+bool PrintFontManager::matchFont( FastPrintFontInfo& rInfo, const com::sun::star::lang::Locale& rLocale )
+{
+ FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+ if( ! rWrapper.isValid() )
+ return false;
+
+ FcConfig* pConfig = rWrapper.FcConfigGetCurrent();
+ FcPattern* pPattern = rWrapper.FcPatternCreate();
+
+ OString aLangAttrib;
+ // populate pattern with font characteristics
+ if( rLocale.Language.getLength() )
+ {
+ OUStringBuffer aLang(6);
+ aLang.append( rLocale.Language );
+ if( rLocale.Country.getLength() )
+ {
+ aLang.append( sal_Unicode('-') );
+ aLang.append( rLocale.Country );
+ }
+ aLangAttrib = OUStringToOString( aLang.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
+ }
+ if( aLangAttrib.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_LANG, (FcChar8*)aLangAttrib.getStr() );
+
+ OString aFamily = OUStringToOString( rInfo.m_aFamilyName, RTL_TEXTENCODING_UTF8 );
+ if( aFamily.getLength() )
+ rWrapper.FcPatternAddString( pPattern, FC_FAMILY, (FcChar8*)aFamily.getStr() );
+
+ addtopattern(rWrapper, pPattern, rInfo.m_eItalic, rInfo.m_eWeight, rInfo.m_eWidth, rInfo.m_ePitch);
+
+ rWrapper.FcConfigSubstitute( pConfig, pPattern, FcMatchPattern );
+ rWrapper.FcDefaultSubstitute( pPattern );
+ FcResult eResult = FcResultNoMatch;
+ FcFontSet *pFontSet = rWrapper.getFontSet();
+ FcPattern* pResult = rWrapper.FcFontSetMatch( pConfig, &pFontSet, 1, pPattern, &eResult );
+ bool bSuccess = false;
+ if( pResult )
+ {
+ FcFontSet* pSet = rWrapper.FcFontSetCreate();
+ rWrapper.FcFontSetAdd( pSet, pResult );
+ if( pSet->nfont > 0 )
+ {
+ //extract the closest match
+ FcChar8* file = NULL;
+ FcResult eFileRes = rWrapper.FcPatternGetString( pSet->fonts[0], FC_FILE, 0, &file );
+ if( eFileRes == FcResultMatch )
+ {
+ OString aDir, aBase, aOrgPath( (sal_Char*)file );
+ splitPath( aOrgPath, aDir, aBase );
+ int nDirID = getDirectoryAtom( aDir, true );
+ fontID aFont = findFontFileID( nDirID, aBase );
+ if( aFont > 0 )
+ bSuccess = getFontFastInfo( aFont, rInfo );
+ }
+ }
+ // info: destroying the pSet destroys pResult implicitly
+ // since pResult was "added" to pSet
+ rWrapper.FcFontSetDestroy( pSet );
+ }
+
+ // cleanup
+ rWrapper.FcPatternDestroy( pPattern );
+
+ return bSuccess;
+}
+
+#else // ENABLE_FONTCONFIG not defined
+
+bool PrintFontManager::initFontconfig()
+{
+ return false;
+}
+
+int PrintFontManager::countFontconfigFonts()
+{
+ return 0;
+}
+
+void PrintFontManager::deinitFontconfig()
+{}
+
+bool PrintFontManager::addFontconfigDir( const rtl::OString& )
+{
+ return false;
+}
+
+bool PrintFontManager::matchFont( FastPrintFontInfo&, const com::sun::star::lang::Locale& )
+{
+ return false;
+}
+
+int PrintFontManager::FreeTypeCharIndex( void*, sal_uInt32 )
+{
+ return 0;
+}
+
+rtl::OUString PrintFontManager::Substitute( const rtl::OUString&,
+ rtl::OUString&, const rtl::OString&, italic::type, weight::type, width::type, pitch::type) const
+{
+ rtl::OUString aName;
+ return aName;
+}
+
+#endif // ENABLE_FONTCONFIG
+
diff --git a/vcl/unx/source/fontmanager/fontmanager.cxx b/vcl/unx/source/fontmanager/fontmanager.cxx
new file mode 100644
index 000000000000..73e117550a14
--- /dev/null
+++ b/vcl/unx/source/fontmanager/fontmanager.cxx
@@ -0,0 +1,4008 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: fontmanager.cxx,v $
+ * $Revision: 1.81.22.2 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <osl/thread.h>
+
+#include "unotools/atom.hxx"
+
+#include "vcl/fontmanager.hxx"
+#include "vcl/fontcache.hxx"
+#include "vcl/helper.hxx"
+#include "vcl/strhelper.hxx"
+#include "vcl/ppdparser.hxx"
+#include "vcl/svdata.hxx"
+#include "vcl/salinst.hxx"
+
+#include "tools/urlobj.hxx"
+#include "tools/stream.hxx"
+#include "tools/debug.hxx"
+#include "tools/config.hxx"
+
+#include "osl/file.hxx"
+#include "osl/process.h"
+
+#include "rtl/tencinfo.h"
+#include "rtl/ustrbuf.hxx"
+#include "rtl/strbuf.hxx"
+
+#include "i18npool/mslangid.hxx"
+
+
+#include "parseAFM.hxx"
+#define NO_LIST
+#include "sft.h"
+#undef NO_LIST
+
+#if OSL_DEBUG_LEVEL > 1
+#include <sys/times.h>
+#include <stdio.h>
+#endif
+
+#include "sal/alloca.h"
+
+#include <set>
+#include <hash_set>
+#include <algorithm>
+
+#include "adobeenc.tab" // get encoding table for AFM metrics
+
+#ifdef CALLGRIND_COMPILE
+#include <valgrind/callgrind.h>
+#endif
+
+#include "comphelper/processfactory.hxx"
+#include "com/sun/star/beans/XMaterialHolder.hpp"
+#include "com/sun/star/beans/NamedValue.hpp"
+
+#define PRINTER_METRICDIR "fontmetric"
+
+using namespace utl;
+using namespace psp;
+using namespace osl;
+using namespace rtl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+
+/*
+ * static helpers
+ */
+
+inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
+ (((sal_uInt16)pBuffer[0]) << 8);
+ pBuffer+=2;
+ return nRet;
+}
+
+inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
+ (((sal_uInt32)pBuffer[1]) << 16) |
+ (((sal_uInt32)pBuffer[2]) << 8) |
+ (((sal_uInt32)pBuffer[3]) );
+ pBuffer += 4;
+ return nRet;
+}
+
+static italic::type parseItalic( const ByteString& rItalic )
+{
+ italic::type eItalic = italic::Unknown;
+ if( rItalic.EqualsIgnoreCaseAscii( "i" ) )
+ eItalic = italic::Italic;
+ else if( rItalic.EqualsIgnoreCaseAscii( "o" ) )
+ eItalic = italic::Oblique;
+ else
+ eItalic = italic::Upright;
+ return eItalic;
+}
+
+// -------------------------------------------------------------------------
+
+static weight::type parseWeight( const ByteString& rWeight )
+{
+ weight::type eWeight = weight::Unknown;
+ if( rWeight.Search( "bold" ) != STRING_NOTFOUND )
+ {
+ if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
+ eWeight = weight::SemiBold;
+ else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
+ eWeight = weight::UltraBold;
+ else
+ eWeight = weight::Bold;
+ }
+ else if( rWeight.Search( "heavy" ) != STRING_NOTFOUND )
+ eWeight = weight::Bold;
+ else if( rWeight.Search( "light" ) != STRING_NOTFOUND )
+ {
+ if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
+ eWeight = weight::SemiLight;
+ else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
+ eWeight = weight::UltraLight;
+ else
+ eWeight = weight::Light;
+ }
+ else if( rWeight.Search( "black" ) != STRING_NOTFOUND )
+ eWeight = weight::Black;
+ else if( rWeight.Equals( "demi" ) )
+ eWeight = weight::SemiBold;
+ else if( rWeight.Equals( "book" ) ||
+ rWeight.Equals( "semicondensed" ) )
+ eWeight = weight::Light;
+ else if( rWeight.Equals( "medium" ) || rWeight.Equals( "roman" ) )
+ eWeight = weight::Medium;
+ else
+ eWeight = weight::Normal;
+ return eWeight;
+}
+
+// -------------------------------------------------------------------------
+
+static width::type parseWidth( const ByteString& rWidth )
+{
+ width::type eWidth = width::Unknown;
+ if( rWidth.Equals( "bold" ) ||
+ rWidth.Equals( "semiexpanded" ) )
+ eWidth = width::SemiExpanded;
+ else if( rWidth.Equals( "condensed" ) ||
+ rWidth.Equals( "narrow" ) )
+ eWidth = width::Condensed;
+ else if( rWidth.Equals( "double wide" ) ||
+ rWidth.Equals( "extraexpanded" ) ||
+ rWidth.Equals( "ultraexpanded" ) )
+ eWidth = width::UltraExpanded;
+ else if( rWidth.Equals( "expanded" ) ||
+ rWidth.Equals( "wide" ) )
+ eWidth = width::Expanded;
+ else if( rWidth.Equals( "extracondensed" ) )
+ eWidth = width::ExtraCondensed;
+ else if( rWidth.Equals( "semicondensed" ) )
+ eWidth = width::SemiCondensed;
+ else if( rWidth.Equals( "ultracondensed" ) )
+ eWidth = width::UltraCondensed;
+ else
+ eWidth = width::Normal;
+
+ return eWidth;
+}
+
+// -------------------------------------------------------------------------
+bool PrintFontManager::XLFDEntry::operator<(const PrintFontManager::XLFDEntry& rRight) const
+{
+ sal_Int32 nCmp = 0;
+ if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
+ aFamily.pData->length,
+ rRight.aFamily.pData->buffer,
+ rRight.aFamily.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
+ aFoundry.pData->length,
+ rRight.aFoundry.pData->buffer,
+ rRight.aFoundry.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
+ {
+ if( eItalic != rRight.eItalic )
+ return (int)eItalic < (int)rRight.eItalic;
+ }
+
+ if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
+ {
+ if( eWeight != rRight.eWeight )
+ return (int)eWeight < (int)rRight.eWeight;
+ }
+
+ if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
+ {
+ if( eWidth != rRight.eWidth )
+ return (int)eWidth < (int)rRight.eWidth;
+ }
+
+ if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
+ {
+ if( ePitch != rRight.ePitch )
+ return (int)ePitch < (int)rRight.ePitch;
+ }
+
+ if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
+ aAddStyle.pData->length,
+ rRight.aAddStyle.pData->buffer,
+ rRight.aAddStyle.pData->length );
+ if( nCmp != 0 )
+ return nCmp < 0;
+ }
+
+ if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
+ {
+ if( aEncoding != rRight.aEncoding )
+ return aEncoding < rRight.aEncoding;
+ }
+
+ return false;
+}
+
+bool PrintFontManager::XLFDEntry::operator==(const PrintFontManager::XLFDEntry& rRight) const
+{
+ sal_Int32 nCmp = 0;
+ if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
+ aFamily.pData->length,
+ rRight.aFamily.pData->buffer,
+ rRight.aFamily.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
+ aFoundry.pData->length,
+ rRight.aFoundry.pData->buffer,
+ rRight.aFoundry.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
+ {
+ if( eItalic != rRight.eItalic )
+ return false;
+ }
+
+ if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
+ {
+ if( eWeight != rRight.eWeight )
+ return false;
+ }
+
+ if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
+ {
+ if( eWidth != rRight.eWidth )
+ return false;
+ }
+
+ if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
+ {
+ if( ePitch != rRight.ePitch )
+ return false;
+ }
+
+ if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
+ {
+ nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
+ aAddStyle.pData->length,
+ rRight.aAddStyle.pData->buffer,
+ rRight.aAddStyle.pData->length );
+ if( nCmp != 0 )
+ return false;
+ }
+
+ if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
+ {
+ if( aEncoding != rRight.aEncoding )
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * PrintFont implementations
+ */
+PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
+ m_eType( eType ),
+ m_nFamilyName( 0 ),
+ m_nPSName( 0 ),
+ m_eItalic( italic::Unknown ),
+ m_eWidth( width::Unknown ),
+ m_eWeight( weight::Unknown ),
+ m_ePitch( pitch::Unknown ),
+ m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
+ m_bFontEncodingOnly( false ),
+ m_pMetrics( NULL ),
+ m_nAscend( 0 ),
+ m_nDescend( 0 ),
+ m_nLeading( 0 ),
+ m_nXMin( 0 ),
+ m_nYMin( 0 ),
+ m_nXMax( 0 ),
+ m_nYMax( 0 ),
+ m_bHaveVerticalSubstitutedGlyphs( false ),
+ m_bUserOverride( false ),
+ m_eEmbeddedbitmap( fcstatus::isunset ),
+ m_eAntialias( fcstatus::isunset )
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::PrintFont::~PrintFont()
+{
+ if( m_pMetrics )
+ delete m_pMetrics;
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::Type1FontFile::~Type1FontFile()
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
+{
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::BuiltinFont::~BuiltinFont()
+{
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
+{
+ return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
+{
+ return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
+{
+ bool bSuccess = false;
+
+ ByteString aFile( PrintFontManager::get().getFontFile( this ) );
+
+ TrueTypeFont* pTTFont = NULL;
+
+ if( OpenTTFontFile( aFile.GetBuffer(), m_nCollectionEntry < 0 ? 0 : m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ if( ! m_pMetrics )
+ {
+ m_pMetrics = new PrintFontMetrics;
+ memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
+ }
+ m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
+ int i;
+ sal_uInt16 table[256], table_vert[256];
+
+ for( i = 0; i < 256; i++ )
+ table[ i ] = 256*nPage + i;
+
+ int nCharacters = nPage < 255 ? 256 : 254;
+ MapString( pTTFont, table, nCharacters, NULL, 0 );
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nCharacters; i++ )
+ {
+ if( table[i] )
+ {
+ CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
+ rChar.width = pMetrics[ i ].adv;
+ rChar.height = m_aGlobalMetricX.height;
+ }
+ }
+
+ free( pMetrics );
+ }
+
+ for( i = 0; i < 256; i++ )
+ table_vert[ i ] = 256*nPage + i;
+ MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
+ pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nCharacters; i++ )
+ {
+ if( table_vert[i] )
+ {
+ CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
+ rChar.width = m_aGlobalMetricY.width;
+ rChar.height = pMetrics[ i ].adv;
+ if( table_vert[i] != table[i] )
+ m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
+ }
+ }
+ free( pMetrics );
+ }
+
+ if( ! m_pMetrics->m_bKernPairsQueried )
+ {
+ m_pMetrics->m_bKernPairsQueried = true;
+ // this is really a hack
+ // in future MapString/KernGlyphs should be used
+ // but vcl is not in a state where that could be used
+ // so currently we get kernpairs by accessing the raw data
+ struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
+
+ //-----------------------------------------------------------------
+ // Kerning: KT_MICROSOFT
+ //-----------------------------------------------------------------
+ if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
+ {
+ // create a glyph -> character mapping
+ ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
+ ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
+ for( i = 21; i < 0xfffd; i++ )
+ {
+ sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
+ if( nGlyph != 0 )
+ aGlyphMap[ nGlyph ] = (sal_Unicode)i;
+ }
+
+
+ KernPair aPair;
+ for( i = 0; i < (int)pImplTTFont->nkern; i++ )
+ {
+ const sal_uInt8* pTable = pImplTTFont->kerntables[i];
+
+ /*sal_uInt16 nVersion =*/ getUInt16BE( pTable );
+ /*sal_uInt16 nLength =*/ getUInt16BE( pTable );
+ sal_uInt16 nCoverage = getUInt16BE( pTable );
+
+ aPair.kern_x = 0;
+ aPair.kern_y = 0;
+ switch( nCoverage >> 8 )
+ {
+ case 0:
+ {
+ sal_uInt16 nPairs = getUInt16BE( pTable );
+ pTable += 6;
+ for( int n = 0; n < nPairs; n++ )
+ {
+ sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
+ sal_uInt16 nRightGlyph = getUInt16BE( pTable );
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
+
+ left = aGlyphMap.find( nLeftGlyph );
+ right = aGlyphMap.find( nRightGlyph );
+ if( left != aGlyphMap.end() && right != aGlyphMap.end() )
+ {
+ aPair.first = left->second;
+ aPair.second = right->second;
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case 2:
+ {
+ const sal_uInt8* pSubTable = pTable;
+ /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
+ sal_uInt16 nOfLeft = getUInt16BE( pTable );
+ sal_uInt16 nOfRight = getUInt16BE( pTable );
+ /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
+ const sal_uInt8* pTmp = pSubTable + nOfLeft;
+ sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
+ sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
+ pTmp = pSubTable + nOfRight;
+ sal_uInt16 nFirstRight = getUInt16BE( pTmp );
+ sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
+
+ // int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
+ for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
+ {
+ for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
+ {
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // Kerning: KT_APPLE_NEW
+ //-----------------------------------------------------------------
+ if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
+ {
+ // create a glyph -> character mapping
+ ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
+ ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
+ for( i = 21; i < 0xfffd; i++ )
+ {
+ sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
+ if( nGlyph != 0 )
+ aGlyphMap[ nGlyph ] = (sal_Unicode)i;
+ }
+
+ // Loop through each of the 'kern' subtables
+ KernPair aPair;
+ for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
+ {
+ const sal_uInt8* pTable = pImplTTFont->kerntables[i];
+
+ /*sal_uInt32 nLength =*/ getUInt32BE( pTable );
+ sal_uInt16 nCoverage = getUInt16BE( pTable );
+ /*sal_uInt16 nTupleIndex =*/ getUInt16BE( pTable );
+
+ // Get kerning type
+ // sal_Bool bKernVertical = nCoverage & 0x8000;
+ // sal_Bool bKernCrossStream = nCoverage & 0x4000;
+ // sal_Bool bKernVariation = nCoverage & 0x2000;
+
+ // Kerning sub-table format, 0 through 3
+ sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
+
+ aPair.kern_x = 0;
+ aPair.kern_y = 0;
+ switch( nSubTableFormat )
+ {
+ case 0:
+ {
+ // Grab the # of kern pairs but skip over the:
+ // searchRange
+ // entrySelector
+ // rangeShift
+ sal_uInt16 nPairs = getUInt16BE( pTable );
+ pTable += 6;
+
+ for( int n = 0; n < nPairs; n++ )
+ {
+ sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
+ sal_uInt16 nRightGlyph = getUInt16BE( pTable );
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
+
+ left = aGlyphMap.find( nLeftGlyph );
+ right = aGlyphMap.find( nRightGlyph );
+ if( left != aGlyphMap.end() && right != aGlyphMap.end() )
+ {
+ aPair.first = left->second;
+ aPair.second = right->second;
+
+ // Only support horizontal kerning for now
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ aPair.kern_y = 0;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+
+/* switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+*/
+ }
+ }
+ }
+ break;
+
+ case 2:
+ {
+ const sal_uInt8* pSubTable = pTable;
+ /*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
+ sal_uInt16 nOfLeft = getUInt16BE( pTable );
+ sal_uInt16 nOfRight = getUInt16BE( pTable );
+ /*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
+ const sal_uInt8* pTmp = pSubTable + nOfLeft;
+ sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
+ sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
+ pTmp = pSubTable + nOfRight;
+ sal_uInt16 nFirstRight = getUInt16BE( pTmp );
+ sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
+
+ for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
+ {
+ for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
+ {
+ sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
+ switch( nCoverage & 1 )
+ {
+ case 1:
+ aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ break;
+ case 0:
+ aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
+ m_pMetrics->m_aYKernPairs.push_back( aPair );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
+ break;
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found %d/%d kern pairs for %s\n",
+ m_pMetrics->m_aXKernPairs.size(),
+ m_pMetrics->m_aYKernPairs.size(),
+ OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
+#else
+ (void) pProvider; /* avoid warnings */
+#endif
+ }
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+/* #i73387# There seem to be fonts with a rather unwell chosen family name
+* consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
+* It can really only be distinguished by its PSName and FullName. Both of
+* which are not user presentable in OOo. So replace it by something sensible.
+*
+* If other fonts feature this behaviour, insert them to the map.
+*/
+static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
+{
+ static std::hash_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
+ if( aPSNameToFamily.empty() ) // initialization
+ {
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Bold" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-BoldOblique" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Oblique" ) ) ] =
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
+ }
+ std::hash_map<OUString,OUString,OUStringHash>::const_iterator it =
+ aPSNameToFamily.find( i_rPSname );
+ bool bReplaced = (it != aPSNameToFamily.end() );
+ if( bReplaced )
+ o_rFamilyName = it->second;
+ return bReplaced;
+};
+
+bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
+{
+ PrintFontManager& rManager( PrintFontManager::get() );
+
+ int i;
+ FontInfo* pInfo = NULL;
+ parseFile( rFileName.getStr(), &pInfo, P_ALL );
+ if( ! pInfo || ! pInfo->numOfChars )
+ {
+ if( pInfo )
+ freeFontInfo( pInfo );
+ return false;
+ }
+
+ m_aEncodingVector.clear();
+ // fill in global info
+
+ // PSName
+ OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
+ m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
+
+ // family name (if not already set)
+ OUString aFamily;
+ if( ! m_nFamilyName )
+ {
+ aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
+ if( ! aFamily.getLength() )
+ {
+ aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
+ sal_Int32 nIndex = 0;
+ aFamily = aFamily.getToken( 0, '-', nIndex );
+ }
+ familyNameOverride( aPSName, aFamily );
+ m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
+ }
+ else
+ aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
+
+ // style name: if fullname begins with family name
+ // interpret the rest of fullname as style
+ if( ! m_aStyleName.getLength() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
+ {
+ OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
+ if( aFullName.indexOf( aFamily ) == 0 )
+ m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
+ }
+
+ // italic
+ if( pInfo->gfi->italicAngle > 0 )
+ m_eItalic = italic::Oblique;
+ else if( pInfo->gfi->italicAngle < 0 )
+ m_eItalic = italic::Italic;
+ else
+ m_eItalic = italic::Upright;
+
+ // weight
+ ByteString aLowerWeight( pInfo->gfi->weight );
+ aLowerWeight.ToLowerAscii();
+ m_eWeight = parseWeight( aLowerWeight );
+
+ // pitch
+ m_ePitch = pInfo->gfi->isFixedPitch ? pitch::Fixed : pitch::Variable;
+
+ // encoding - only set if unknown
+ int nAdobeEncoding = 0;
+ if( pInfo->gfi->encodingScheme )
+ {
+ if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
+ nAdobeEncoding = 1;
+ else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
+ {
+ nAdobeEncoding = 1;
+ m_aEncoding = RTL_TEXTENCODING_UNICODE;
+ }
+ else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
+ nAdobeEncoding = 2;
+ else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
+ nAdobeEncoding = 3;
+
+ if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = nAdobeEncoding == 1 ?
+ RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
+ }
+ else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
+
+ // try to parse the font name and decide wether it might be a
+ // japanese font. Who invented this PITA ?
+ OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
+ if( ! aPSNameLastToken.compareToAscii( "H" ) ||
+ ! aPSNameLastToken.compareToAscii( "V" ) )
+ {
+ static const char* pEncs[] =
+ {
+ "EUC",
+ "RKSJ",
+ "SJ"
+ };
+ static const rtl_TextEncoding aEncs[] =
+ {
+ RTL_TEXTENCODING_EUC_JP,
+ RTL_TEXTENCODING_SHIFT_JIS,
+ RTL_TEXTENCODING_JIS_X_0208
+ };
+
+ for( unsigned int enc = 0; enc < sizeof( aEncs )/sizeof(aEncs[0]) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
+ {
+ sal_Int32 nIndex = 0, nOffset = 1;
+ do
+ {
+ OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
+ if( nIndex == -1 )
+ break;
+ nOffset = 0;
+ if( ! aToken.compareToAscii( pEncs[enc] ) )
+ {
+ m_aEncoding = aEncs[ enc ];
+ m_bFontEncodingOnly = true;
+ }
+ } while( nIndex != -1 );
+ }
+
+ // default is jis
+ if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
+ m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
+#endif
+ }
+
+ // hack for GB encoded builtin fonts posing as FontSpecific
+ if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
+ {
+ int nLen = aFamily.getLength();
+ if( nLen > 2 &&
+ aFamily.getStr()[ nLen-2 ] == 'G' &&
+ aFamily.getStr()[ nLen-1 ] == 'B' &&
+ pInfo->numOfChars > 255 )
+ {
+ m_aEncoding = RTL_TEXTENCODING_GBK;
+ m_bFontEncodingOnly = true;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
+#endif
+ }
+ }
+
+ // #i37313# check if Fontspecific is not rather some character encoding
+ if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
+ {
+ bool bYFound = false;
+ bool bQFound = false;
+ CharMetricInfo* pChar = pInfo->cmi;
+ for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
+ {
+ if( pChar[j].name )
+ {
+ if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
+ bYFound = true;
+ else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
+ bQFound = true;
+ }
+ }
+ if( bQFound && bYFound )
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
+ pInfo->gfi->fontName,
+ rFileName.getStr()
+ );
+ #endif
+ nAdobeEncoding = 4;
+ m_aEncoding = RTL_TEXTENCODING_UNICODE;
+ bFillEncodingvector = false; // will be filled anyway, don't do the work twice
+ }
+ }
+
+ // ascend
+ m_nAscend = pInfo->gfi->fontBBox.ury;
+
+ // descend
+ // descends have opposite sign of our definition
+ m_nDescend = -pInfo->gfi->fontBBox.lly;
+
+ // fallback to ascender, descender
+ // interesting: the BBox seems to describe Ascender and Descender better
+ // as we understand it
+ if( m_nAscend == 0 )
+ m_nAscend = pInfo->gfi->ascender;
+ if( m_nDescend == 0)
+ m_nDescend = -pInfo->gfi->descender;
+
+ m_nLeading = m_nAscend + m_nDescend - 1000;
+
+ if( m_pMetrics )
+ delete m_pMetrics;
+ m_pMetrics = new PrintFontMetrics;
+ // mark all pages as queried (or clear if only global font info queiried)
+ memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
+
+ m_aGlobalMetricX.width = m_aGlobalMetricY.width =
+ pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
+ m_aGlobalMetricX.height = m_aGlobalMetricY.height =
+ pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
+
+ m_nXMin = pInfo->gfi->fontBBox.llx;
+ m_nYMin = pInfo->gfi->fontBBox.lly;
+ m_nXMax = pInfo->gfi->fontBBox.urx;
+ m_nYMax = pInfo->gfi->fontBBox.ury;
+
+ if( bFillEncodingvector || !bOnlyGlobalAttributes )
+ {
+ // fill in character metrics
+
+ // first transform the character codes to unicode
+ // note: this only works with single byte encodings
+ sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
+ CharMetricInfo* pChar = pInfo->cmi;
+
+ for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
+ {
+ if( nAdobeEncoding == 4 )
+ {
+ if( pChar->name )
+ {
+ pUnicodes[i] = 0;
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ {
+ m_aEncodingVector[ *it ] = pChar->code;
+ if( pChar->code == -1 )
+ m_aNonEncoded[ *it ] = pChar->name;
+ if( ! pUnicodes[i] ) // map the first
+ pUnicodes[i] = *it;
+ }
+ }
+ }
+ }
+ else if( pChar->code != -1 )
+ {
+ if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
+ {
+ pUnicodes[i] = pChar->code + 0xf000;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
+ continue;
+ }
+
+ if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
+ {
+ pUnicodes[i] = (sal_Unicode)pChar->code;
+ continue;
+ }
+
+ ByteString aTranslate;
+ if( pChar->code & 0xff000000 )
+ aTranslate += (char)(pChar->code >> 24 );
+ if( pChar->code & 0xffff0000 )
+ aTranslate += (char)((pChar->code & 0x00ff0000) >> 16 );
+ if( pChar->code & 0xffffff00 )
+ aTranslate += (char)((pChar->code & 0x0000ff00) >> 8 );
+ aTranslate += (char)(pChar->code & 0xff);
+ String aUni( aTranslate, m_aEncoding );
+ pUnicodes[i] = *aUni.GetBuffer();
+ }
+ else
+ pUnicodes[i] = 0;
+ }
+
+ // now fill in the character metrics
+ // parseAFM.cxx effectively only supports direction 0 (horizontal)
+ pChar = pInfo->cmi;
+ CharacterMetric aMetric;
+ for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
+ {
+ if( pChar->code == -1 && ! pChar->name )
+ continue;
+
+ if( bFillEncodingvector && pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ {
+ m_aEncodingVector[ *it ] = pChar->code;
+ if( pChar->code == -1 )
+ m_aNonEncoded[ *it ] = pChar->name;
+ }
+ }
+ }
+
+ aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
+ aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
+ if( aMetric.width == 0 && aMetric.height == 0 )
+ // guess something for e.g. space
+ aMetric.width = m_aGlobalMetricX.width/4;
+
+ if( ( nAdobeEncoding == 0 ) ||
+ ( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
+ {
+ if( pChar->code != -1 )
+ {
+ m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
+ }
+ else if( pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ m_pMetrics->m_aMetrics[ *it ] = aMetric;
+ }
+ }
+ }
+ else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
+ {
+ if( pChar->name )
+ {
+ std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
+ for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
+ {
+ if( *it != 0 )
+ m_pMetrics->m_aMetrics[ *it ] = aMetric;
+ }
+ }
+ else if( pChar->code != -1 )
+ {
+ ::std::pair< ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator,
+ ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator >
+ aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
+ while( aCodes.first != aCodes.second )
+ {
+ if( (*aCodes.first).second != 0 )
+ {
+ m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
+ if( bFillEncodingvector )
+ m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
+ }
+ ++aCodes.first;
+ }
+ }
+ }
+ else if( nAdobeEncoding == 3 )
+ {
+ if( pChar->code != -1 )
+ {
+ sal_Unicode code = 0xf000 + pChar->code;
+ m_pMetrics->m_aMetrics[ code ] = aMetric;
+ // maybe should try to find the name in the convtabs ?
+ if( bFillEncodingvector )
+ m_aEncodingVector[ code ] = pChar->code;
+ }
+ }
+ }
+
+ m_pMetrics->m_aXKernPairs.clear();
+ m_pMetrics->m_aYKernPairs.clear();
+
+ // now fill in the kern pairs
+ // parseAFM.cxx effectively only supports direction 0 (horizontal)
+ PairKernData* pKern = pInfo->pkd;
+ KernPair aPair;
+ for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
+ {
+ // #i37703# broken kern table
+ if( ! pKern->name1 || ! pKern->name2 )
+ continue;
+
+ aPair.first = 0;
+ aPair.second = 0;
+ // currently we have to find the adobe character names
+ // in the already parsed character metrics to find
+ // the corresponding UCS2 code which is a bit dangerous
+ // since the character names are not required
+ // in the metric descriptions
+ pChar = pInfo->cmi;
+ for( int j = 0;
+ j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
+ j++, pChar++ )
+ {
+ if( pChar->code != -1 )
+ {
+ if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
+ aPair.first = pUnicodes[ j ];
+ if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
+ aPair.second = pUnicodes[ j ];
+ }
+ }
+ if( aPair.first && aPair.second )
+ {
+ aPair.kern_x = pKern->xamt;
+ aPair.kern_y = pKern->yamt;
+ m_pMetrics->m_aXKernPairs.push_back( aPair );
+ }
+ }
+ m_pMetrics->m_bKernPairsQueried = true;
+ }
+
+ freeFontInfo( pInfo );
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::s_aEmptyOString;
+
+/*
+ * one instance only
+ */
+PrintFontManager& PrintFontManager::get()
+{
+ static PrintFontManager* theManager = NULL;
+ if( ! theManager )
+ {
+ theManager = new PrintFontManager();
+ theManager->initialize();
+ }
+ return *theManager;
+}
+
+// -------------------------------------------------------------------------
+
+/*
+ * the PrintFontManager
+ */
+
+PrintFontManager::PrintFontManager() :
+ m_nNextFontID( 1 ),
+ m_pAtoms( new MultiAtomProvider() ),
+ m_nNextDirAtom( 1 ),
+ m_pFontCache( NULL ),
+ m_bFontconfigSuccess( false )
+{
+ for( unsigned int i = 0; i < sizeof( aAdobeCodes )/sizeof( aAdobeCodes[0] ); i++ )
+ {
+ m_aUnicodeToAdobename.insert( ::std::hash_multimap< sal_Unicode, ::rtl::OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
+ m_aAdobenameToUnicode.insert( ::std::hash_multimap< ::rtl::OString, sal_Unicode, ::rtl::OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
+ if( aAdobeCodes[i].aAdobeStandardCode )
+ {
+ m_aUnicodeToAdobecode.insert( ::std::hash_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
+ m_aAdobecodeToUnicode.insert( ::std::hash_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
+ }
+#if 0
+ m_aUnicodeToAdobename[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].pAdobename;
+ m_aAdobenameToUnicode[ aAdobeCodes[i].pAdobename ] = aAdobeCodes[i].aUnicode;
+ if( aAdobeCodes[i].aAdobeStandardCode )
+ {
+ m_aUnicodeToAdobecode[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].aAdobeStandardCode;
+ m_aAdobecodeToUnicode[ aAdobeCodes[i].aAdobeStandardCode ] = aAdobeCodes[i].aUnicode;
+ }
+#endif
+ }
+}
+
+// -------------------------------------------------------------------------
+
+PrintFontManager::~PrintFontManager()
+{
+ deinitFontconfig();
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ delete (*it).second;
+ delete m_pAtoms;
+ if( m_pFontCache )
+ delete m_pFontCache;
+}
+
+// -------------------------------------------------------------------------
+
+const OString& PrintFontManager::getDirectory( int nAtom ) const
+{
+ ::std::hash_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
+ return it != m_aAtomToDir.end() ? it->second : s_aEmptyOString;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
+{
+ int nAtom = 0;
+ ::std::hash_map< OString, int, OStringHash >::const_iterator it
+ ( m_aDirToAtom.find( rDirectory ) );
+ if( it != m_aDirToAtom.end() )
+ nAtom = it->second;
+ else if( bCreate )
+ {
+ nAtom = m_nNextDirAtom++;
+ m_aDirToAtom[ rDirectory ] = nAtom;
+ m_aAtomToDir[ nAtom ] = rDirectory;
+ }
+ return nAtom;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::addFontFile( const ::rtl::OString& rFileName, int /*nFaceNum*/ )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ OString aName( OUStringToOString( aPath.GetName(), aEncoding ) );
+ OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) );
+
+ int nDirID = getDirectoryAtom( aDir, true );
+ fontID nFontId = findFontFileID( nDirID, aName );
+ if( !nFontId )
+ {
+ ::std::list< PrintFont* > aNewFonts;
+ if( analyzeFontFile( nDirID, aName, ::std::list<OString>(), aNewFonts ) )
+ {
+ for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
+ it != aNewFonts.end(); ++it )
+ {
+ m_aFonts[ nFontId = m_nNextFontID++ ] = *it;
+ m_aFontFileToFontID[ aName ].insert( nFontId );
+ m_pFontCache->updateFontCacheEntry( *it, true );
+ }
+ }
+ }
+ return nFontId;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, const ::std::list<OString>& rXLFDs, ::std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
+{
+ rNewFonts.clear();
+
+ OString aDir( getDirectory( nDirID ) );
+
+ OString aFullPath( aDir );
+ aFullPath += "/";
+ aFullPath += rFontFile;
+
+ // #i1872# reject unreadable files
+ if( access( aFullPath.getStr(), R_OK ) )
+ return false;
+
+ ByteString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
+ if( aExt.EqualsIgnoreCaseAscii( "pfb" ) || aExt.EqualsIgnoreCaseAscii( "pfa" ) )
+ {
+ // check for corresponding afm metric
+ // first look for an adjacent file
+ static const char* pSuffix[] = { ".afm", ".AFM" };
+
+ for( unsigned int i = 0; i < sizeof(pSuffix)/sizeof(pSuffix[0]); i++ )
+ {
+ ByteString aName( rFontFile );
+ aName.Erase( aName.Len()-4 );
+ aName.Append( pSuffix[i] );
+
+ ByteString aFilePath( aDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( aName );
+
+ ByteString aAfmFile;
+ if( access( aFilePath.GetBuffer(), R_OK ) )
+ {
+ // try in subdirectory afm instead
+ aFilePath = aDir;
+ aFilePath.Append( "/afm/" );
+ aFilePath.Append( aName );
+
+ if( ! access( aFilePath.GetBuffer(), R_OK ) )
+ {
+ aAfmFile = "afm/";
+ aAfmFile += aName;
+ }
+ }
+ else
+ aAfmFile = aName;
+
+ if( aAfmFile.Len() )
+ {
+ Type1FontFile* pFont = new Type1FontFile();
+ pFont->m_nDirectory = nDirID;
+
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_aMetricFile = aAfmFile;
+
+ if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ if( pFont && rXLFDs.size() )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ if( pFont )
+ rNewFonts.push_back( pFont );
+ break;
+ }
+ }
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "afm" ) )
+ {
+ ByteString aFilePath( aDir );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString( rFontFile ) );
+ BuiltinFont* pFont = new BuiltinFont();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aMetricFile = rFontFile;
+ if( pFont->readAfmMetrics( aFilePath, m_pAtoms, false, true ) )
+ rNewFonts.push_back( pFont );
+ else
+ delete pFont;
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "ttf" )
+ || aExt.EqualsIgnoreCaseAscii( "tte" ) // #i33947# for Gaiji support
+ || aExt.EqualsIgnoreCaseAscii( "otf" ) ) // #112957# allow GLYF-OTF
+ {
+ TrueTypeFontFile* pFont = new TrueTypeFontFile();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_nCollectionEntry = -1;
+
+ if( rXLFDs.size() )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ // need to read the font anyway to get aliases inside the font file
+ if( ! analyzeTrueTypeFile( pFont ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ else
+ rNewFonts.push_back( pFont );
+ }
+ else if( aExt.EqualsIgnoreCaseAscii( "ttc" ) )
+ {
+ // get number of ttc entries
+ int nLength = CountTTCFonts( aFullPath.getStr() );
+ if( nLength )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "%s contains %d fonts\n", aFullPath.getStr(), nLength );
+#endif
+ for( int i = 0; i < nLength; i++ )
+ {
+ TrueTypeFontFile* pFont = new TrueTypeFontFile();
+ pFont->m_nDirectory = nDirID;
+ pFont->m_aFontFile = rFontFile;
+ pFont->m_nCollectionEntry = i;
+ if( nLength == 1 )
+ getFontAttributesFromXLFD( pFont, rXLFDs );
+ if( ! analyzeTrueTypeFile( pFont ) )
+ {
+ delete pFont;
+ pFont = NULL;
+ }
+ else
+ rNewFonts.push_back( pFont );
+ }
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "CountTTCFonts( \"%s/%s\" ) failed\n", getDirectory(nDirID).getStr(), rFontFile.getStr() );
+#endif
+ }
+ return ! rNewFonts.empty();
+}
+
+// -------------------------------------------------------------------------
+
+fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
+{
+ fontID nID = 0;
+ ::std::hash_map< fontID, PrintFont* >::const_iterator it;
+ for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
+ {
+ if( it->second->m_eType == fonttype::Builtin &&
+ it->second->m_nPSName == nPSNameAtom )
+ nID = it->first;
+ }
+ return nID;
+}
+
+// -------------------------------------------------------------------------
+
+fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile ) const
+{
+ fontID nID = 0;
+
+ ::std::hash_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
+ if( set_it != m_aFontFileToFontID.end() )
+ {
+ for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
+ {
+ ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
+ if( it != m_aFonts.end() )
+ {
+ switch( it->second->m_eType )
+ {
+ case fonttype::Type1:
+ {
+ Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
+ if( pFont->m_nDirectory == nDirID &&
+ pFont->m_aFontFile == rFontFile )
+ nID = it->first;
+ }
+ break;
+ case fonttype::TrueType:
+ {
+ TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
+ if( pFont->m_nDirectory == nDirID &&
+ pFont->m_aFontFile == rFontFile )
+ nID = it->first;
+ }
+ break;
+ case fonttype::Builtin:
+ if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
+ static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
+ nID = it->first;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return nID;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::parseXLFD( const OString& rXLFD, XLFDEntry& rEntry )
+{
+ sal_Int32 nIndex = 0;
+ OString aFoundry = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ) );
+ if( nIndex < 0 ) return false;
+ OString aFamilyXLFD = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ) );
+ if( nIndex < 0 ) return false;
+ OString aWeight = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aSlant = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aWidth = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aAddStyle = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aPitch = rXLFD.getToken( 4, '-', nIndex ).toAsciiLowerCase();
+ if( nIndex < 0 ) return false;
+ OString aRegEnc = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ).toAsciiLowerCase() );
+ if( nIndex < 0 ) return false;
+ OString aEnc = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase() );
+
+ // capitalize words
+ sal_Int32 nFamIndex = 0;
+ OStringBuffer aFamilyName;
+ while( nFamIndex >= 0 )
+ {
+ OString aToken = aFamilyXLFD.getToken( 0, ' ', nFamIndex );
+ sal_Char aFirst = aToken.toChar();
+ if( aFirst >= 'a' && aFirst <= 'z' )
+ aFirst = aFirst - 'a' + 'A';
+ OStringBuffer aNewToken( aToken.getLength() );
+ aNewToken.append( aToken );
+ aNewToken.setCharAt( 0, aFirst );
+ if( aFamilyName.getLength() > 0 )
+ aFamilyName.append( ' ' );
+ aFamilyName.append( aNewToken.makeStringAndClear() );
+ }
+
+ rEntry.aFoundry = aFoundry;
+ rEntry.aFamily = aFamilyName.makeStringAndClear();
+ rEntry.aAddStyle = aAddStyle;
+ // evaluate weight
+ rEntry.eWeight = parseWeight( aWeight );
+ // evaluate slant
+ rEntry.eItalic = parseItalic( aSlant );
+ // evaluate width
+ rEntry.eWidth = parseWidth( aWidth );
+
+ // evaluate pitch
+ if( aPitch.toChar() == 'c' || aPitch.toChar() == 'm' )
+ rEntry.ePitch = pitch::Fixed;
+ else
+ rEntry.ePitch = pitch::Variable;
+
+ OString aToken = aEnc.toAsciiLowerCase();
+ // get encoding
+ if( aAddStyle.indexOf( "symbol" ) != -1 )
+ rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
+ else
+ {
+ if( aToken.equals( "symbol" ) )
+ rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
+ else
+ {
+ OStringBuffer aCharset( aRegEnc.getLength() + aEnc.getLength() + 1 );
+ aCharset.append( aRegEnc );
+ aCharset.append( '-' );
+ aCharset.append( aEnc );
+ rEntry.aEncoding = rtl_getTextEncodingFromUnixCharset( aCharset.getStr() );
+ }
+ }
+
+ // set correct mask flags
+ rEntry.nMask = 0;
+ if( rEntry.aFoundry != "*" ) rEntry.nMask |= XLFDEntry::MaskFoundry;
+ if( rEntry.aFamily != "*" ) rEntry.nMask |= XLFDEntry::MaskFamily;
+ if( rEntry.aAddStyle != "*" ) rEntry.nMask |= XLFDEntry::MaskAddStyle;
+ if( aWeight != "*" ) rEntry.nMask |= XLFDEntry::MaskWeight;
+ if( aSlant != "*" ) rEntry.nMask |= XLFDEntry::MaskItalic;
+ if( aWidth != "*" ) rEntry.nMask |= XLFDEntry::MaskWidth;
+ if( aPitch != "*" ) rEntry.nMask |= XLFDEntry::MaskPitch;
+ if( aRegEnc != "*" && aEnc != "*" ) rEntry.nMask |= XLFDEntry::MaskEncoding;
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::parseXLFD_appendAliases( const std::list< OString >& rXLFDs, std::list< XLFDEntry >& rEntries ) const
+{
+ for( std::list< OString >::const_iterator it = rXLFDs.begin(); it != rXLFDs.end(); ++it )
+ {
+ XLFDEntry aEntry;
+ if( ! parseXLFD(*it, aEntry) )
+ continue;
+ rEntries.push_back( aEntry );
+ std::map< XLFDEntry, std::list< XLFDEntry > >::const_iterator alias_it =
+ m_aXLFD_Aliases.find( aEntry );
+ if( alias_it != m_aXLFD_Aliases.end() )
+ {
+ rEntries.insert( rEntries.end(), alias_it->second.begin(), alias_it->second.end() );
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontAttributesFromXLFD( PrintFont* pFont, const std::list< OString >& rXLFDs ) const
+{
+ bool bFamilyName = false;
+
+ std::list< XLFDEntry > aXLFDs;
+
+ parseXLFD_appendAliases( rXLFDs, aXLFDs );
+
+ for( std::list< XLFDEntry >::const_iterator it = aXLFDs.begin();
+ it != aXLFDs.end(); ++it )
+ {
+ // set family name or alias
+ int nFam =
+ m_pAtoms->getAtom( ATOM_FAMILYNAME,
+ OStringToOUString( it->aFamily, it->aAddStyle.indexOf( "utf8" ) != -1 ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1 ),
+ sal_True );
+ if( ! bFamilyName )
+ {
+ bFamilyName = true;
+ pFont->m_nFamilyName = nFam;
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ case fonttype::TrueType:
+ static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // make sure that aliases are unique
+ if( nFam != pFont->m_nFamilyName )
+ {
+ std::list< int >::const_iterator al_it;
+ for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nFam; ++al_it )
+ ;
+ if( al_it == pFont->m_aAliases.end() )
+ pFont->m_aAliases.push_back( nFam );
+
+ }
+ // for the rest of the attributes there can only be one value;
+ // we'll trust the first one
+ continue;
+ }
+
+ // fill in weight
+ pFont->m_eWeight = it->eWeight;
+ // fill in slant
+ pFont->m_eItalic = it->eItalic;
+ // fill in width
+ pFont->m_eWidth = it->eWidth;
+ // fill in pitch
+ pFont->m_ePitch = it->ePitch;
+ // fill in encoding
+ pFont->m_aEncoding = it->aEncoding;
+ }
+
+ // handle iso8859-1 as ms1252 to fill the "gap" starting at 0x80
+ if( pFont->m_aEncoding == RTL_TEXTENCODING_ISO_8859_1 )
+ pFont->m_aEncoding = RTL_TEXTENCODING_MS_1252;
+ if( rXLFDs.begin() != rXLFDs.end() )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ case fonttype::TrueType:
+ static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
+ break;
+ default: break;
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getXLFD( PrintFont* pFont ) const
+{
+ if( pFont->m_eType == fonttype::Type1 )
+ {
+ if( static_cast<Type1FontFile*>(pFont)->m_aXLFD.getLength() )
+ return static_cast<Type1FontFile*>(pFont)->m_aXLFD;
+ }
+ if( pFont->m_eType == fonttype::TrueType )
+ {
+ if( static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD.getLength() )
+ return static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD;
+ }
+
+ OStringBuffer aXLFD( 128 );
+
+ aXLFD.append( "-misc-" );
+ ByteString aFamily( String( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ), RTL_TEXTENCODING_UTF8 );
+ aFamily.SearchAndReplaceAll( '-',' ' );
+ aFamily.SearchAndReplaceAll( '?',' ' );
+ aFamily.SearchAndReplaceAll( '*',' ' );
+ aXLFD.append( OString( aFamily ) );
+ aXLFD.append( '-' );
+ switch( pFont->m_eWeight )
+ {
+ case weight::Thin: aXLFD.append("thin");break;
+ case weight::UltraLight: aXLFD.append("ultralight");break;
+ case weight::Light: aXLFD.append("light");break;
+ case weight::SemiLight: aXLFD.append("semilight");break;
+ case weight::Normal: aXLFD.append("normal");break;
+ case weight::Medium: aXLFD.append("medium");break;
+ case weight::SemiBold: aXLFD.append("semibold");break;
+ case weight::Bold: aXLFD.append("bold");break;
+ case weight::UltraBold: aXLFD.append("ultrabold");break;
+ case weight::Black: aXLFD.append("black");break;
+ default: break;
+ }
+ aXLFD.append('-');
+ switch( pFont->m_eItalic )
+ {
+ case italic::Upright: aXLFD.append('r');break;
+ case italic::Oblique: aXLFD.append('o');break;
+ case italic::Italic: aXLFD.append('i');break;
+ default: break;
+ }
+ aXLFD.append('-');
+ switch( pFont->m_eWidth )
+ {
+ case width::UltraCondensed: aXLFD.append("ultracondensed");break;
+ case width::ExtraCondensed: aXLFD.append("extracondensed");break;
+ case width::Condensed: aXLFD.append("condensed");break;
+ case width::SemiCondensed: aXLFD.append("semicondensed");break;
+ case width::Normal: aXLFD.append("normal");break;
+ case width::SemiExpanded: aXLFD.append("semiexpanded");break;
+ case width::Expanded: aXLFD.append("expanded");break;
+ case width::ExtraExpanded: aXLFD.append("extraexpanded");break;
+ case width::UltraExpanded: aXLFD.append("ultraexpanded");break;
+ default: break;
+ }
+ aXLFD.append("-utf8-0-0-0-0-");
+ aXLFD.append( pFont->m_ePitch == pitch::Fixed ? "m" : "p" );
+ aXLFD.append("-0-");
+ const char* pEnc = rtl_getBestUnixCharsetFromTextEncoding( pFont->m_aEncoding );
+ if( ! pEnc )
+ {
+ if( pFont->m_aEncoding == RTL_TEXTENCODING_ADOBE_STANDARD )
+ pEnc = "adobe-standard";
+ else
+ pEnc = "iso8859-1";
+ }
+ aXLFD .append( pEnc );
+
+ return aXLFD.makeStringAndClear();
+}
+
+// -------------------------------------------------------------------------
+
+OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
+{
+ NameRecord* pNameRecord = (NameRecord*)pRecord;
+ OUString aValue;
+ if(
+ ( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
+ ||
+ ( pNameRecord->platformID == 0 ) // Apple, Unicode
+ )
+ {
+ OUStringBuffer aName( pNameRecord->slen/2 );
+ const sal_uInt8* pNameBuffer = pNameRecord->sptr;
+ for(int n = 0; n < pNameRecord->slen/2; n++ )
+ aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
+ aValue = aName.makeStringAndClear();
+ }
+ else if( pNameRecord->platformID == 3 )
+ {
+ if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
+ {
+ /*
+ * and now for a special kind of madness:
+ * some fonts encode their byte value string as BE uint16
+ * (leading to stray zero bytes in the string)
+ * while others code two bytes as a uint16 and swap to BE
+ */
+ OStringBuffer aName;
+ const sal_uInt8* pNameBuffer = pNameRecord->sptr;
+ for(int n = 0; n < pNameRecord->slen/2; n++ )
+ {
+ sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
+ sal_Char aChar = aCode >> 8;
+ if( aChar )
+ aName.append( aChar );
+ aChar = aCode & 0x00ff;
+ if( aChar )
+ aName.append( aChar );
+ }
+ switch( pNameRecord->encodingID )
+ {
+ case 2:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
+ break;
+ case 3:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
+ break;
+ case 4:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
+ break;
+ case 5:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
+ break;
+ case 6:
+ aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
+ break;
+ }
+ }
+ }
+ return aValue;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
+{
+ OUString aFamily;
+
+ rNames.clear();
+ ::std::set< OUString > aSet;
+
+ NameRecord* pNameRecords = NULL;
+ int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
+ if( nNameRecords && pNameRecords )
+ {
+ LanguageType aLang = MsLangId::getSystemLanguage();
+ int nLastMatch = -1;
+ for( int i = 0; i < nNameRecords; i++ )
+ {
+ if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
+ continue;
+ int nMatch = -1;
+ if( pNameRecords[i].platformID == 0 ) // Unicode
+ nMatch = 4000;
+ else if( pNameRecords[i].platformID == 3 )
+ {
+ // this bases on the LanguageType actually being a Win LCID
+ if( pNameRecords[i].languageID == aLang )
+ nMatch = 8000;
+ else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
+ nMatch = 2000;
+ else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
+ pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
+ nMatch = 1500;
+ else
+ nMatch = 1000;
+ }
+ OUString aName = convertTrueTypeName( pNameRecords + i );
+ aSet.insert( aName );
+ if( nMatch > nLastMatch )
+ {
+ nLastMatch = nMatch;
+ aFamily = aName;
+ }
+ }
+ DisposeNameRecords( pNameRecords, nNameRecords );
+ }
+ if( aFamily.getLength() )
+ {
+ rNames.push_front( aFamily );
+ for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
+ if( *it != aFamily )
+ rNames.push_back( *it );
+ }
+ return;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
+{
+ bool bSuccess = false;
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aFile = getFontFile( pFont );
+ TrueTypeFont* pTTFont = NULL;
+
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+
+ ::std::list< OUString > aNames;
+ analyzeTrueTypeFamilyName( pTTFont, aNames );
+
+ // set family name from XLFD if possible
+ if( ! pFont->m_nFamilyName )
+ {
+ if( aNames.begin() != aNames.end() )
+ {
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
+ aNames.pop_front();
+ }
+ else
+ {
+ sal_Int32 dotIndex;
+
+ // poor font does not have a family name
+ // name it to file name minus the extension
+ dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
+ if ( dotIndex == -1 )
+ dotIndex = pTTFontFile->m_aFontFile.getLength();
+
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
+ }
+ }
+ for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
+ {
+ if( it->getLength() )
+ {
+ int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
+ if( nAlias != pFont->m_nFamilyName )
+ {
+ std::list< int >::const_iterator al_it;
+ for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
+ ;
+ if( al_it == pFont->m_aAliases.end() )
+ pFont->m_aAliases.push_back( nAlias );
+ }
+ }
+ }
+
+ if( aInfo.usubfamily )
+ pFont->m_aStyleName = OUString( aInfo.usubfamily );
+
+ pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, String( ByteString( aInfo.psname ), aEncoding ), sal_True );
+ switch( aInfo.weight )
+ {
+ case FW_THIN: pFont->m_eWeight = weight::Thin; break;
+ case FW_EXTRALIGHT: pFont->m_eWeight = weight::UltraLight; break;
+ case FW_LIGHT: pFont->m_eWeight = weight::Light; break;
+ case FW_MEDIUM: pFont->m_eWeight = weight::Medium; break;
+ case FW_SEMIBOLD: pFont->m_eWeight = weight::SemiBold; break;
+ case FW_BOLD: pFont->m_eWeight = weight::Bold; break;
+ case FW_EXTRABOLD: pFont->m_eWeight = weight::UltraBold; break;
+ case FW_BLACK: pFont->m_eWeight = weight::Black; break;
+
+ case FW_NORMAL:
+ default: pFont->m_eWeight = weight::Normal; break;
+ }
+
+ switch( aInfo.width )
+ {
+ case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = width::UltraCondensed; break;
+ case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = width::ExtraCondensed; break;
+ case FWIDTH_CONDENSED: pFont->m_eWidth = width::Condensed; break;
+ case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = width::SemiCondensed; break;
+ case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = width::SemiExpanded; break;
+ case FWIDTH_EXPANDED: pFont->m_eWidth = width::Expanded; break;
+ case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = width::ExtraExpanded; break;
+ case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = width::UltraExpanded; break;
+
+ case FWIDTH_NORMAL:
+ default: pFont->m_eWidth = width::Normal; break;
+ }
+
+ pFont->m_ePitch = aInfo.pitch ? pitch::Fixed : pitch::Variable;
+ pFont->m_eItalic = aInfo.italicAngle == 0 ? italic::Upright : ( aInfo.italicAngle < 0 ? italic::Italic : italic::Oblique );
+ // #104264# there are fonts that set italic angle 0 although they are
+ // italic; use macstyle bit here
+ if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
+ pFont->m_eItalic = italic::Italic;
+
+ pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
+
+ pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
+ pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
+
+ if( aInfo.winAscent && aInfo.winDescent )
+ {
+ pFont->m_nAscend = aInfo.winAscent;
+ pFont->m_nDescend = aInfo.winDescent;
+ pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
+ }
+ else if( aInfo.typoAscender && aInfo.typoDescender )
+ {
+ pFont->m_nLeading = aInfo.typoLineGap;
+ pFont->m_nAscend = aInfo.typoAscender;
+ pFont->m_nDescend = -aInfo.typoDescender;
+ }
+ else
+ {
+ pFont->m_nLeading = aInfo.linegap;
+ pFont->m_nAscend = aInfo.ascender;
+ pFont->m_nDescend = -aInfo.descender;
+ }
+
+ // last try: font bounding box
+ if( pFont->m_nAscend == 0 )
+ pFont->m_nAscend = aInfo.yMax;
+ if( pFont->m_nDescend == 0 )
+ pFont->m_nDescend = -aInfo.yMin;
+ if( pFont->m_nLeading == 0 )
+ pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
+
+ if( pFont->m_nAscend )
+ pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
+
+ // get bounding box
+ pFont->m_nXMin = aInfo.xMin;
+ pFont->m_nYMin = aInfo.yMin;
+ pFont->m_nXMax = aInfo.xMax;
+ pFont->m_nYMax = aInfo.yMax;
+
+ // get type flags
+ pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
+
+ // get vertical substitutions flag
+ pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ else
+ fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.GetBuffer() );
+#endif
+
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::initFontsAlias()
+{
+ m_aXLFD_Aliases.clear();
+ rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
+ for( std::list< OString >::const_iterator dir_it = m_aFontDirectories.begin();
+ dir_it != m_aFontDirectories.end(); ++dir_it )
+ {
+ OStringBuffer aDirName(512);
+ aDirName.append( *dir_it );
+ aDirName.append( "/fonts.alias" );
+ SvFileStream aStream( OStringToOUString( aDirName.makeStringAndClear(), aEnc ), STREAM_READ );
+ if( ! aStream.IsOpen() )
+ continue;
+
+ do
+ {
+ ByteString aLine;
+ aStream.ReadLine( aLine );
+
+ // get the alias and the pattern it gets translated to
+ ByteString aAlias = GetCommandLineToken( 0, aLine );
+ ByteString aMap = GetCommandLineToken( 1, aLine );
+
+ // remove eventual quotes
+ aAlias.EraseLeadingChars( '"' );
+ aAlias.EraseTrailingChars( '"' );
+ aMap.EraseLeadingChars( '"' );
+ aMap.EraseTrailingChars( '"' );
+
+ XLFDEntry aAliasEntry, aMapEntry;
+ parseXLFD( aAlias, aAliasEntry );
+ parseXLFD( aMap, aMapEntry );
+
+ if( aAliasEntry.nMask && aMapEntry.nMask )
+ m_aXLFD_Aliases[ aMapEntry ].push_back( aAliasEntry );
+ } while( ! aStream.IsEof() );
+ }
+}
+
+// code stolen from vcl's RegisterFontSubstitutors()
+// TODO: use that method once psprint gets merged into vcl
+static bool AreFCSubstitutionsEnabled()
+{
+ // init font substitution defaults
+ int nDisableBits = 0;
+#ifdef SOLARIS
+ // TODO: check the OS version and fc-data maintenance level
+ nDisableBits = 1; // disable "font fallback" here on default
+#endif
+ // apply the environment variable if any
+ const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
+ if( pEnvStr )
+ {
+ //
+ if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
+ nDisableBits = (*pEnvStr - '0');
+ else
+ nDisableBits = ~0U; // no specific bits set: disable all
+ }
+
+ return ((nDisableBits & 3) == 0);
+}
+
+void PrintFontManager::initialize()
+{
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_TOGGLE_COLLECT();
+ CALLGRIND_ZERO_STATS();
+ #endif
+
+ long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ];
+
+ if( ! m_pFontCache )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "creating font cache ... " );
+ clock_t aStart;
+ struct tms tms;
+ aStart = times( &tms );
+#endif
+ m_pFontCache = new FontCache();
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStop = times( &tms );
+ fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
+#endif
+ }
+
+ // initialize may be called twice in the future
+ {
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ delete (*it).second;
+ m_nNextFontID = 1;
+ m_aFonts.clear();
+ m_aFontDirectories.clear();
+ m_aPrivateFontDirectories.clear();
+ m_aOverrideFonts.clear();
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStart;
+ clock_t aStep1;
+ clock_t aStep2;
+ clock_t aStep3;
+ int nBuiltinFonts = 0;
+ int nCached = 0;
+
+ struct tms tms;
+
+ aStart = times( &tms );
+#endif
+
+ // first try fontconfig
+ m_bFontconfigSuccess = initFontconfig();
+
+ // part one - look for downloadable fonts
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ const ::rtl::OUString &rSalPrivatePath = psp::getFontPath();
+
+ // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
+ // the TrueType fonts installed with the office
+ if( rSalPrivatePath.getLength() )
+ {
+ OString aPath = rtl::OUStringToOString( rSalPrivatePath, aEncoding );
+ const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aToken = aPath.getToken( 0, ';', nIndex );
+ normPath( aToken );
+ // if registering an app-specific fontdir with fontconfig fails
+ // and fontconfig-based substitutions are enabled
+ // then trying to use these app-specific fonts doesn't make sense
+ if( m_bFontconfigSuccess && !addFontconfigDir( aToken ) )
+ if( bAreFCSubstitutionsEnabled )
+ continue;
+ m_aFontDirectories.push_back( aToken );
+ m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
+ } while( nIndex >= 0 );
+ }
+
+ // now that all global and local font dirs are known to fontconfig
+ // check that there are fonts actually managed by fontconfig
+ if( m_bFontconfigSuccess )
+ m_bFontconfigSuccess = (countFontconfigFonts() > 0);
+
+ // don't search through many directories fontconfig already told us about
+ if( ! m_bFontconfigSuccess )
+ ImplGetSVData()->mpDefInst->FillFontPathList( m_aFontDirectories );
+
+ // fill XLFD aliases from fonts.alias files
+ initFontsAlias();
+
+ // search for font files in each path
+ std::list< OString >::iterator dir_it;
+ // protect against duplicate paths
+ std::hash_map< OString, int, OStringHash > visited_dirs;
+ for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
+ {
+ OString aPath( *dir_it );
+ // see if we were here already
+ if( visited_dirs.find( aPath ) != visited_dirs.end() )
+ continue;
+ visited_dirs[ aPath ] = 1;
+
+ // there may be ":unscaled" directories (see XFree86)
+ // it should be safe to ignore them since they should not
+ // contain any of our recognizeable fonts
+
+ // ask the font cache whether it handles this directory
+ std::list< PrintFont* > aCacheFonts;
+ if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
+#endif
+ for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *it;
+ if( (*it)->m_eType == fonttype::Type1 )
+ m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::TrueType )
+ m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::Builtin )
+ m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
+#if OSL_DEBUG_LEVEL > 1
+ if( (*it)->m_eType == fonttype::Builtin )
+ nBuiltinFonts++;
+ nCached++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+#endif
+ }
+ if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
+ continue;
+ }
+
+ DIR* pDIR = opendir( aPath.getStr() );
+ struct dirent* pEntry = (struct dirent*)aDirEntBuffer;
+ if( pDIR )
+ {
+ // read fonts.dir if possible
+ ::std::hash_map< OString, ::std::list<OString>, OStringHash > aFontsDir;
+ int nDirID = getDirectoryAtom( aPath, true );
+ // #i38367# no fonts.dir in our own directories anymore
+ std::list< int >::const_iterator priv_dir;
+ for( priv_dir = m_aPrivateFontDirectories.begin();
+ priv_dir != m_aPrivateFontDirectories.end() && *priv_dir != nDirID;
+ ++priv_dir )
+ ;
+
+ if( priv_dir == m_aPrivateFontDirectories.end() )
+ {
+ ByteString aGccDummy( aPath );
+ String aFontsDirPath( aGccDummy, aEncoding );
+ aFontsDirPath.AppendAscii( "/fonts.dir" );
+ SvFileStream aStream( aFontsDirPath, STREAM_READ );
+ if( aStream.IsOpen() )
+ {
+ ByteString aLine;
+ while( ! aStream.IsEof() )
+ {
+ aStream.ReadLine( aLine );
+ ByteString aFileName( GetCommandLineToken( 0, aLine ) );
+ ByteString aXLFD( aLine.Copy( aFileName.Len() ) );
+ if( aFileName.Len() && aXLFD.Len() )
+ aFontsDir[ aFileName ].push_back(aXLFD);
+ }
+ }
+ }
+
+ int nDirFonts = 0;
+ while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pEntry ) && pEntry )
+ {
+ OString aFileName( pEntry->d_name );
+ // ignore .afm files here
+ if( aFileName.getLength() > 3 &&
+ aFileName.lastIndexOf( ".afm" ) == aFileName.getLength()-4 )
+ continue;
+
+ struct stat aStat;
+ ByteString aFilePath( aPath );
+ aFilePath.Append( '/' );
+ aFilePath.Append( ByteString( aFileName ) );
+ if( ! stat( aFilePath.GetBuffer(), &aStat ) &&
+ S_ISREG( aStat.st_mode ) )
+ {
+ if( findFontFileID( nDirID, aFileName ) == 0 )
+ {
+ ::std::list<OString> aXLFDs;
+ ::std::hash_map< OString, ::std::list<OString>, OStringHash >::const_iterator it =
+ aFontsDir.find( aFileName );
+ if( it != aFontsDir.end() )
+ aXLFDs = (*it).second;
+
+ // fill in font attributes from XLFD rather
+ // than reading every file
+ ::std::list< PrintFont* > aNewFonts;
+ if( analyzeFontFile( nDirID, aFileName, aXLFDs, aNewFonts ) )
+ {
+ for( ::std::list< PrintFont* >::iterator font_it = aNewFonts.begin(); font_it != aNewFonts.end(); ++font_it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *font_it;
+ m_aFontFileToFontID[ aFileName ].insert( aFont );
+ m_pFontCache->updateFontCacheEntry( *font_it, false );
+ nDirFonts++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+ }
+ }
+ }
+ }
+ }
+ closedir( pDIR );
+ m_pFontCache->updateDirTimestamp( nDirID );
+ if( ! nDirFonts )
+ m_pFontCache->markEmptyDir( nDirID );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep1 = times( &tms );
+#endif
+
+ // part two - look for metrics for builtin printer fonts
+ std::list< OUString > aMetricDirs;
+ psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
+
+ std::list< OString > aEmptyFontsDir;
+ for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
+ {
+ OString aDir = OUStringToOString( *met_dir_it, aEncoding );
+
+ // ask the font cache whether it handles this directory
+ std::list< PrintFont* > aCacheFonts;
+
+ if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
+#endif
+ for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
+ {
+ fontID aFont = m_nNextFontID++;
+ m_aFonts[ aFont ] = *it;
+ if( (*it)->m_eType == fonttype::Type1 )
+ m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::TrueType )
+ m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
+ else if( (*it)->m_eType == fonttype::Builtin )
+ m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
+#if OSL_DEBUG_LEVEL > 1
+ if( (*it)->m_eType == fonttype::Builtin )
+ nBuiltinFonts++;
+ nCached++;
+#if OSL_DEBUG_LEVEL > 2
+ fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
+ OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
+ getFontFileSysPath( aFont ).getStr() );
+#endif
+#endif
+ }
+ continue;
+ }
+
+ DIR* pDIR = opendir( aDir.getStr() );
+ if( pDIR )
+ {
+ struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
+ int nDirID = getDirectoryAtom( aDir, true );
+ int nDirFonts = 0;
+
+ while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
+ {
+ ByteString aFile( aDir );
+ aFile += '/';
+ aFile += pDirEntry->d_name;
+ struct stat aStat;
+ if( ! stat( aFile.GetBuffer(), &aStat )
+ && S_ISREG( aStat.st_mode )
+ )
+ {
+ OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
+ OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
+ if( aExt.equalsIgnoreAsciiCase( "afm" ) )
+ {
+ ::std::list< PrintFont* > aNewFonts;
+
+ analyzeFontFile( nDirID, aFileName, aEmptyFontsDir, aNewFonts );
+ for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
+ {
+ if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
+ {
+ m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = *it;
+ m_pFontCache->updateFontCacheEntry( *it, false );
+#if OSL_DEBUG_LEVEL > 2
+ nBuiltinFonts++;
+#endif
+ }
+ else
+ delete *it;
+ }
+ }
+ }
+ }
+ closedir( pDIR );
+ if( ! nDirFonts )
+ m_pFontCache->markEmptyDir( nDirID );
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep2 = times( &tms );
+#endif
+
+ // part three - fill in family styles
+ ::std::hash_map< fontID, PrintFont* >::iterator font_it;
+ for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
+ {
+ ::std::hash_map< int, family::type >::const_iterator it =
+ m_aFamilyTypes.find( font_it->second->m_nFamilyName );
+ if (it != m_aFamilyTypes.end())
+ continue;
+ const ::rtl::OUString& rFamily =
+ m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
+ family::type eType = matchFamilyName( rFamily );
+ m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep3 = times( &tms );
+ fprintf( stderr, "PrintFontManager::initialize: collected %d fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
+ double fTick = (double)sysconf( _SC_CLK_TCK );
+ fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
+ fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
+ fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
+#endif
+
+ m_pFontCache->flush();
+
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_DUMP_STATS();
+ CALLGRIND_TOGGLE_COLLECT();
+ #endif
+}
+
+// -------------------------------------------------------------------------
+inline bool
+equalPitch (psp::pitch::type from, psp::pitch::type to)
+{
+ return from == to;
+}
+
+inline bool
+equalWeight (psp::weight::type from, psp::weight::type to)
+{
+ return from > to ? (from - to) <= 3 : (to - from) <= 3;
+}
+
+inline bool
+equalItalic (psp::italic::type from, psp::italic::type to)
+{
+ if ( (from == psp::italic::Italic) || (from == psp::italic::Oblique) )
+ return (to == psp::italic::Italic) || (to == psp::italic::Oblique);
+ return to == from;
+}
+inline bool
+equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
+{
+ if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
+ return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
+ return from == to;
+}
+
+namespace {
+ struct BuiltinFontIdentifier
+ {
+ OUString aFamily;
+ italic::type eItalic;
+ weight::type eWeight;
+ pitch::type ePitch;
+ rtl_TextEncoding aEncoding;
+
+ BuiltinFontIdentifier( const OUString& rFam,
+ italic::type eIt,
+ weight::type eWg,
+ pitch::type ePt,
+ rtl_TextEncoding enc ) :
+ aFamily( rFam ),
+ eItalic( eIt ),
+ eWeight( eWg ),
+ ePitch( ePt ),
+ aEncoding( enc )
+ {}
+
+ bool operator==( const BuiltinFontIdentifier& rRight ) const
+ {
+ return equalItalic( eItalic, rRight.eItalic ) &&
+ equalWeight( eWeight, rRight.eWeight ) &&
+ equalPitch( ePitch, rRight.ePitch ) &&
+ equalEncoding( aEncoding, rRight.aEncoding ) &&
+ aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
+ }
+ };
+
+ struct BuiltinFontIdentifierHash
+ {
+ size_t operator()( const BuiltinFontIdentifier& rFont ) const
+ {
+ return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
+ }
+ };
+}
+
+void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFontIDs.clear();
+ std::hash_map< fontID, PrintFont* >::const_iterator it;
+
+ /*
+ * Note: there are two easy steps making this faster:
+ * first: insert the printer builtins first, then the not builtins,
+ * if they do not match.
+ * drawback: this would change the sequence of fonts; this could have
+ * subtle, unknown consequences in vcl font matching
+ * second: instead of comparing attributes to see whether a softfont
+ * is duplicate to a builtin one could simply compare the PSName (which is
+ * supposed to be unique), which at this point is just an int.
+ * drawback: this could change which fonts are listed; especially TrueType
+ * fonts often have a rather dubious PSName, so this could change the
+ * font list not so subtle.
+ * Until getFontList for a printer becomes a performance issue (which is
+ * currently not the case), best stay with the current algorithm.
+ */
+
+ // fill sets of printer supported fonts
+ if( pParser )
+ {
+ std::set<int> aBuiltinPSNames;
+ std::hash_set< BuiltinFontIdentifier,
+ BuiltinFontIdentifierHash
+ > aBuiltinFonts;
+
+ std::map<int, fontID > aOverridePSNames;
+ if( bUseOverrideMetrics )
+ {
+ readOverrideMetrics();
+ for( std::vector<fontID>::const_iterator over = m_aOverrideFonts.begin();
+ over != m_aOverrideFonts.end(); ++over )
+ {
+ std::hash_map<fontID,PrintFont*>::const_iterator font_it = m_aFonts.find( *over );
+ DBG_ASSERT( font_it != m_aFonts.end(), "override to nonexistant font" );
+ if( font_it != m_aFonts.end() )
+ aOverridePSNames[ font_it->second->m_nPSName ] = *over;
+ }
+ }
+
+ int nFonts = pParser->getFonts();
+ for( int i = 0; i < nFonts; i++ )
+ aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ PrintFont* pFont = it->second;
+ if( it->second->m_eType == fonttype::Builtin &&
+ aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
+ {
+ bool bInsert = true;
+ if( bUseOverrideMetrics )
+ {
+ // in override case only use the override fonts, not their counterparts
+ std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
+ if( over != aOverridePSNames.end() && over->second != it->first )
+ bInsert = false;
+ }
+ else
+ {
+ // do not insert override fonts in non override case
+ if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
+ bInsert = false;
+ }
+ if( bInsert )
+ {
+ aBuiltinFonts.insert( BuiltinFontIdentifier(
+ m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
+ pFont->m_eItalic,
+ pFont->m_eWeight,
+ pFont->m_ePitch,
+ pFont->m_aEncoding
+ ) );
+ }
+ }
+ }
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ PrintFont* pFont = it->second;
+ if( it->second->m_eType == fonttype::Builtin )
+ {
+ if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
+ {
+ bool bInsert = true;
+ if( bUseOverrideMetrics )
+ {
+ // in override case only use the override fonts, not their counterparts
+ std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
+ if( over != aOverridePSNames.end() && over->second != it->first )
+ bInsert = false;
+ }
+ else
+ {
+ // do not insert override fonts in non override case
+ if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
+ bInsert = false;
+ }
+ if( bInsert )
+ rFontIDs.push_back( it->first );
+ }
+ }
+ else if( aBuiltinFonts.find( BuiltinFontIdentifier(
+ m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
+ pFont->m_eItalic,
+ pFont->m_eWeight,
+ pFont->m_ePitch,
+ pFont->m_aEncoding
+ ) ) == aBuiltinFonts.end() )
+ {
+ rFontIDs.push_back( it->first );
+ }
+ }
+ }
+ else // no specific printer
+ {
+ for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ rFontIDs.push_back( it->first );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
+{
+ ::std::hash_map< int, family::type >::const_iterator style_it =
+ m_aFamilyTypes.find( pFont->m_nFamilyName );
+ rInfo.m_eType = pFont->m_eType;
+ rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
+ rInfo.m_aStyleName = pFont->m_aStyleName;
+ rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : family::Unknown;
+ rInfo.m_eItalic = pFont->m_eItalic;
+ rInfo.m_eWidth = pFont->m_eWidth;
+ rInfo.m_eWeight = pFont->m_eWeight;
+ rInfo.m_ePitch = pFont->m_ePitch;
+ rInfo.m_aEncoding = pFont->m_aEncoding;
+ rInfo.m_eEmbeddedbitmap = pFont->m_eEmbeddedbitmap;
+ rInfo.m_eAntialias = pFont->m_eAntialias;
+ rInfo.m_aAliases.clear();
+ for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
+ rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
+{
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
+ ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a truetype font not analyzed or type1 without metrics read
+ if( pFont->m_eType == fonttype::Type1 )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
+
+ rInfo.m_nAscend = pFont->m_nAscend;
+ rInfo.m_nDescend = pFont->m_nDescend;
+ rInfo.m_nLeading = pFont->m_nLeading;
+ rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontListWithInfo( ::std::list< PrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFonts.clear();
+ ::std::list< fontID > aFontList;
+ getFontList( aFontList, pParser, bUseOverrideMetrics );
+
+ ::std::list< fontID >::iterator it;
+ for( it = aFontList.begin(); it != aFontList.end(); ++it )
+ {
+ PrintFontInfo aInfo;
+ aInfo.m_nID = *it;
+ fillPrintFontInfo( getFont( *it ), aInfo );
+ rFonts.push_back( aInfo );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
+{
+ rFonts.clear();
+ ::std::list< fontID > aFontList;
+ getFontList( aFontList, pParser, bUseOverrideMetrics );
+
+ ::std::list< fontID >::iterator it;
+ for( it = aFontList.begin(); it != aFontList.end(); ++it )
+ {
+ FastPrintFontInfo aInfo;
+ aInfo.m_nID = *it;
+ fillPrintFontInfo( getFont( *it ), aInfo );
+ rFonts.push_back( aInfo );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ rInfo.m_nID = nFontID;
+ fillPrintFontInfo( pFont, rInfo );
+ }
+ return pFont ? true : false;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ rInfo.m_nID = nFontID;
+ fillPrintFontInfo( pFont, rInfo );
+ }
+ return pFont ? true : false;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
+{
+ bool bSuccess = false;
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont )
+ {
+ if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
+ {
+ // might be a truetype font not analyzed or type1 without metrics read
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ bSuccess = true;
+ xMin = pFont->m_nXMin;
+ yMin = pFont->m_nYMin;
+ xMax = pFont->m_nXMax;
+ yMax = pFont->m_nYMax;
+ }
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
+{
+ int nRet = -1;
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
+ return nRet;
+}
+
+// -------------------------------------------------------------------------
+
+
+family::type PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const
+{
+ typedef struct {
+ const char* mpName;
+ sal_uInt16 mnLength;
+ family::type meType;
+ } family_t;
+
+#define InitializeClass( p, a ) p, sizeof(p) - 1, a
+ const family_t pFamilyMatch[] = {
+ { InitializeClass( "arial", family::Swiss ) },
+ { InitializeClass( "arioso", family::Script ) },
+ { InitializeClass( "avant garde", family::Swiss ) },
+ { InitializeClass( "avantgarde", family::Swiss ) },
+ { InitializeClass( "bembo", family::Roman ) },
+ { InitializeClass( "bookman", family::Roman ) },
+ { InitializeClass( "conga", family::Roman ) },
+ { InitializeClass( "courier", family::Modern ) },
+ { InitializeClass( "curl", family::Script ) },
+ { InitializeClass( "fixed", family::Modern ) },
+ { InitializeClass( "gill", family::Swiss ) },
+ { InitializeClass( "helmet", family::Modern ) },
+ { InitializeClass( "helvetica", family::Swiss ) },
+ { InitializeClass( "international", family::Modern ) },
+ { InitializeClass( "lucida", family::Swiss ) },
+ { InitializeClass( "new century schoolbook", family::Roman ) },
+ { InitializeClass( "palatino", family::Roman ) },
+ { InitializeClass( "roman", family::Roman ) },
+ { InitializeClass( "sans serif", family::Swiss ) },
+ { InitializeClass( "sansserif", family::Swiss ) },
+ { InitializeClass( "serf", family::Roman ) },
+ { InitializeClass( "serif", family::Roman ) },
+ { InitializeClass( "times", family::Roman ) },
+ { InitializeClass( "utopia", family::Roman ) },
+ { InitializeClass( "zapf chancery", family::Script ) },
+ { InitializeClass( "zapfchancery", family::Script ) }
+ };
+
+ rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
+ sal_uInt32 nLower = 0;
+ sal_uInt32 nUpper = sizeof(pFamilyMatch) / sizeof(pFamilyMatch[0]);
+
+ while( nLower < nUpper )
+ {
+ sal_uInt32 nCurrent = (nLower + nUpper) / 2;
+ const family_t* pHaystack = pFamilyMatch + nCurrent;
+ sal_Int32 nComparison =
+ rtl_str_compareIgnoreAsciiCase_WithLength
+ (
+ aFamily.getStr(), aFamily.getLength(),
+ pHaystack->mpName, pHaystack->mnLength
+ );
+
+ if( nComparison < 0 )
+ nUpper = nCurrent;
+ else
+ if( nComparison > 0 )
+ nLower = nCurrent + 1;
+ else
+ return pHaystack->meType;
+ }
+
+ return family::Unknown;
+}
+
+// -------------------------------------------------------------------------
+
+family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( !pFont )
+ return family::Unknown;
+
+ ::std::hash_map< int, family::type >::const_iterator it =
+ m_aFamilyTypes.find( pFont->m_nFamilyName );
+ return (it != m_aFamilyTypes.end()) ? it->second : family::Unknown;
+}
+
+
+// -------------------------------------------------------------------------
+
+const ::rtl::OUString& PrintFontManager::getFontFamily( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ return m_pAtoms->getString( ATOM_FAMILYNAME, pFont ? pFont->m_nFamilyName : INVALID_ATOM );
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
+{
+ OString aMetricPath;
+ if( pFont )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1:
+ {
+ Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
+ aMetricPath = getDirectory( pPSFont->m_nDirectory );
+ aMetricPath += "/";
+ aMetricPath += pPSFont->m_aMetricFile;
+ }
+ break;
+ case fonttype::Builtin:
+ {
+ BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
+ aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
+ aMetricPath += "/";
+ aMetricPath += pBuiltinFont->m_aMetricFile;
+ }
+ break;
+ default: break;
+ }
+ }
+ return aMetricPath;
+}
+
+// -------------------------------------------------------------------------
+
+OString PrintFontManager::getFontFile( PrintFont* pFont ) const
+{
+ OString aPath;
+
+ if( pFont && pFont->m_eType == fonttype::Type1 )
+ {
+ Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
+ ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
+ aPath = it->second;
+ aPath += "/";
+ aPath += pPSFont->m_aFontFile;
+ }
+ else if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
+ ::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
+ aPath = it->second;
+ aPath += "/";
+ aPath += pTTFont->m_aFontFile;
+ }
+ return aPath;
+}
+
+// -------------------------------------------------------------------------
+
+const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont && pFont->m_nPSName == 0 )
+ {
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
+}
+
+// -------------------------------------------------------------------------
+
+const CharacterMetric& PrintFontManager::getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const
+{
+ static CharacterMetric aMetric;
+ PrintFont* pFont = getFont( nFontID );
+ return pFont ? ( bHorizontal ? pFont->m_aGlobalMetricX : pFont->m_aGlobalMetricY ) : aMetric;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontAscend( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ }
+ return pFont->m_nAscend;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontDescend( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
+ }
+ return pFont->m_nDescend;
+}
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::getFontLeading( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ return pFont->m_nLeading;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::hasVerticalSubstitutions( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+ return pFont->m_bHaveVerticalSubstitutedGlyphs;
+}
+
+// -------------------------------------------------------------------------
+
+void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
+ const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ {
+ // might be a truetype font not yet analyzed
+ if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
+ memset( pHasSubst, 0, sizeof(bool)*nCharacters );
+ else
+ {
+ for( int i = 0; i < nCharacters; i++ )
+ {
+ sal_Unicode code = pCharacters[i];
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( code >> 8, m_pAtoms );
+ ::std::hash_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
+ pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+OUString PrintFontManager::getFontXLFD( fontID nFontID ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ OUString aRet;
+ if( pFont )
+ {
+ ByteString aXLFD( getXLFD( pFont ) );
+ rtl_TextEncoding aEncoding = aXLFD.GetToken( 6, '-' ).Search( "utf8" ) != STRING_NOTFOUND ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1;
+ aRet = OStringToOUString( aXLFD, aEncoding );
+ }
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+
+const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
+{
+ static ::std::list< KernPair > aEmpty;
+
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return aEmpty;
+
+ if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
+ pFont->queryMetricPage( 0, m_pAtoms );
+ if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
+ return aEmpty;
+ return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::isFontDownloadingAllowed( fontID nFont ) const
+{
+ static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
+ bool bRet = true;
+
+ if( pEnable && *pEnable )
+ {
+ PrintFont* pFont = getFont( nFont );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
+ if( pTTFontFile->m_nTypeFlags & 0x80000000 )
+ {
+ TrueTypeFont* pTTFont = NULL;
+ ByteString aFile = getFontFile( pFont );
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ // get type flags
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+ pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
+ CloseTTFont( pTTFont );
+ }
+ }
+
+ unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & 0x0e;
+
+ // font embedding is allowed if either
+ // no restriction at all (bit 1 clear)
+ // printing allowed (bit 1 set, bit 2 set )
+ bRet = ! ( nCopyrightFlags & 0x02 ) || ( nCopyrightFlags & 0x04 );
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return false;
+
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a font not yet analyzed
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ for( int i = 0; i < nLen; i++ )
+ {
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
+ pArray[i].width = pArray[i].height = -1;
+ if( pFont->m_pMetrics )
+ {
+ int effectiveCode = pString[i];
+ effectiveCode |= bVertical ? 1 << 16 : 0;
+ ::std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
+ // if no vertical metrics are available assume rotated horizontal metrics
+ if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
+ it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
+ // the character metrics are in it->second
+ if( it != pFont->m_pMetrics->m_aMetrics.end() )
+ pArray[ i ] = it->second;
+ }
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
+{
+ PrintFont* pFont = getFont( nFontID );
+ if( ! pFont )
+ return false;
+
+ if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
+ || ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
+ )
+ {
+ // might be a font not yet analyzed
+ if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
+ else if( pFont->m_eType == fonttype::TrueType )
+ analyzeTrueTypeFile( pFont );
+ }
+
+ sal_Unicode code = minCharacter;
+ do
+ {
+ if( ! pFont->m_pMetrics ||
+ ! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
+ pFont->queryMetricPage( code >> 8, m_pAtoms );
+ pArray[ code - minCharacter ].width = -1;
+ pArray[ code - minCharacter ].height = -1;
+ if( pFont->m_pMetrics )
+ {
+ int effectiveCode = code;
+ effectiveCode |= bVertical ? 1 << 16 : 0;
+ ::std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
+ // if no vertical metrics are available assume rotated horizontal metrics
+ if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
+ it = pFont->m_pMetrics->m_aMetrics.find( code );
+ // the character metrics are in it->second
+ if( it != pFont->m_pMetrics->m_aMetrics.end() )
+ pArray[ code - minCharacter ] = it->second;
+ }
+ } while( code++ != maxCharacter );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+static bool createWriteablePath( const ByteString& rPath )
+{
+ bool bSuccess = false;
+
+ if( access( rPath.GetBuffer(), W_OK ) )
+ {
+ int nPos = rPath.SearchBackward( '/' );
+ if( nPos != STRING_NOTFOUND )
+ while( nPos > 0 && rPath.GetChar( nPos ) == '/' )
+ nPos--;
+
+ if( nPos != STRING_NOTFOUND && nPos != 0 && createWriteablePath( rPath.Copy( 0, nPos+1 ) ) )
+ {
+ bSuccess = mkdir( rPath.GetBuffer(), 0777 ) ? false : true;
+ }
+ }
+ else
+ bSuccess = true;
+
+ return bSuccess;
+}
+
+
+// -------------------------------------------------------------------------
+
+int PrintFontManager::importFonts( const ::std::list< OString >& rFiles, bool bLinkOnly, ImportFontCallback* pCallback )
+{
+ int nSuccess = 0;
+
+ // find a directory with write access
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ bool bCanWrite = false;
+ int nDirID = 0;
+ INetURLObject aDir;
+ for( ::std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
+ ! bCanWrite && dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
+ {
+ // check if we can create files in that directory
+ ByteString aDirPath = getDirectory( *dir_it );
+ if( createWriteablePath( aDirPath ) )
+ {
+ aDir = INetURLObject( OStringToOUString( aDirPath, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ nDirID = *dir_it;
+ bCanWrite = true;
+ }
+ }
+ if( bCanWrite )
+ {
+ for( ::std::list< OString >::const_iterator font_it = rFiles.begin();
+ font_it != rFiles.end(); ++font_it )
+ {
+ INetURLObject aFrom( OStringToOUString( *font_it, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
+ INetURLObject aTo( aDir );
+ aTo.Append( aFrom.GetName() );
+
+ if( pCallback )
+ pCallback->progress( aTo.PathToFileName() );
+
+ if( pCallback && pCallback->isCanceled() )
+ break;
+
+ if( ! access( ByteString( String(aTo.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ if( ! ( pCallback ? pCallback->queryOverwriteFile( aTo.PathToFileName() ) : false ) )
+ continue;
+ }
+ // look for afm if necessary
+ OUString aAfmCopied;
+ FileBase::RC nError;
+ if( aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfa" ) ||
+ aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfb" ) )
+ {
+ INetURLObject aFromAfm( aFrom );
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.removeSegment();
+ aFromAfm.Append( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ aFromAfm.Append( aTo.GetName() );
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
+ if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
+ {
+ // give up
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::NoAfmMetric );
+ continue;
+ }
+ }
+ }
+ }
+ INetURLObject aToAfm( aTo );
+ aToAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
+ OUString aFromPath, aToPath;
+ if( bLinkOnly )
+ {
+ ByteString aLinkFromPath( String(aFromAfm.PathToFileName()),
+ aEncoding );
+ ByteString aLinkToPath( String(aToAfm.PathToFileName()),
+ aEncoding );
+ nError = (FileBase::RC)symlink( aLinkFromPath.GetBuffer(), aLinkToPath.GetBuffer() );
+ }
+ else
+ nError = File::copy( aFromAfm.GetMainURL(INetURLObject::DECODE_TO_IURI), aToAfm.GetMainURL(INetURLObject::DECODE_TO_IURI) );
+ if( nError )
+ {
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::AfmCopyFailed );
+ continue;
+ }
+ aAfmCopied = aToPath;
+ }
+ if( bLinkOnly )
+ {
+ ByteString aFromPath( String(aFrom.PathToFileName()),
+ aEncoding );
+ ByteString aToPath( String(aTo.PathToFileName()), aEncoding );
+ nError = (FileBase::RC)symlink( aFromPath.GetBuffer(),
+ aToPath.GetBuffer() );
+ }
+ else
+ nError = File::copy( aFrom.GetMainURL(INetURLObject::DECODE_TO_IURI), aTo.GetMainURL(INetURLObject::DECODE_TO_IURI) );
+ // copy font file
+ if( nError )
+ {
+ if( aAfmCopied.getLength() )
+ File::remove( aAfmCopied );
+ if( pCallback )
+ pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::FontCopyFailed );
+ continue;
+ }
+
+ ::std::list< PrintFont* > aNewFonts;
+ ::std::list< PrintFont* >::iterator it;
+ if( analyzeFontFile( nDirID, OUStringToOString( aTo.GetName(), aEncoding ), ::std::list<OString>(), aNewFonts ) )
+ {
+ // remove all fonts for the same file
+ // discarding their font ids
+ ::std::hash_map< fontID, PrintFont* >::iterator current, next;
+ current = m_aFonts.begin();
+ OString aFileName( OUStringToOString( aTo.GetName(), aEncoding ) );
+ while( current != m_aFonts.end() )
+ {
+ bool bRemove = false;
+ switch( current->second->m_eType )
+ {
+ case fonttype::Type1:
+ if( static_cast<Type1FontFile*>(current->second)->m_aFontFile == aFileName )
+ bRemove = true;
+ break;
+ case fonttype::TrueType:
+ if( static_cast<TrueTypeFontFile*>(current->second)->m_aFontFile == aFileName )
+ bRemove = true;
+ break;
+ default: break;
+ }
+ if( bRemove )
+ {
+ next = current;
+ ++next;
+ m_aFontFileToFontID[ aFileName ].erase( current->first );
+ delete current->second;
+ m_aFonts.erase( current );
+ current = next;
+ }
+ else
+ ++current;
+ }
+
+ DBG_ASSERT( !findFontFileID( nDirID, aFileName ), "not all fonts removed for file" );
+
+ nSuccess++;
+ for( it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
+ {
+ m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = *it;
+ m_pFontCache->updateFontCacheEntry( *it, false );
+ }
+ }
+ }
+
+ m_pFontCache->updateDirTimestamp( nDirID );
+ m_pFontCache->flush();
+ }
+ else if( pCallback )
+ pCallback->importFontsFailed( ImportFontCallback::NoWritableDirectory );
+
+ return nSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::checkImportPossible() const
+{
+ bool bSuccess = false;
+
+ // find a directory with write access
+ ByteString aDir;
+ for( std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
+ dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
+ {
+ aDir = getDirectory( *dir_it );
+ if( createWriteablePath( aDir ) )
+ {
+ bSuccess = true;
+ break;
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ if( bSuccess )
+ fprintf( stderr, "found writable %s\n", aDir.GetBuffer() );
+#endif
+
+ return bSuccess;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::checkChangeFontPropertiesPossible( fontID /*nFontID*/ ) const
+{
+ // since font properties are changed in the font cache file only nowadays
+ // they can always be changed
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::changeFontProperties( fontID nFontID, const ::rtl::OUString& rXLFD )
+{
+ ByteString aXLFD( OUStringToOString( rXLFD, RTL_TEXTENCODING_UTF8 ) );
+ ByteString aAddStyle = aXLFD.GetToken( '-', 6 );
+ if( aAddStyle.Search( "utf8" ) == STRING_NOTFOUND )
+ {
+ aAddStyle.Append( aAddStyle.Len() ? ";utf8" : "utf8" );
+ aXLFD.SetToken( 6, ';', aAddStyle );
+ }
+ PrintFont* pFont = getFont( nFontID );
+ std::list< OString > aDummyList;
+ aDummyList.push_back( aXLFD );
+ getFontAttributesFromXLFD( pFont, aDummyList );
+ pFont->m_bUserOverride = true;
+ m_pFontCache->updateFontCacheEntry( pFont, true );
+
+ return true;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::
+getImportableFontProperties(
+ const OString& rFile,
+ ::std::list< FastPrintFontInfo >& rFontProps
+ )
+{
+ rFontProps.clear();
+ int nIndex = rFile.lastIndexOf( '/' );
+ OString aDir, aFile( rFile.copy( nIndex+1 ) );
+ if( nIndex != -1 )
+ aDir = rFile.copy( 0, nIndex );
+ int nDirID = getDirectoryAtom( aDir, true );
+ ::std::list< PrintFont* > aFonts;
+ bool bRet = analyzeFontFile( nDirID, aFile, ::std::list<OString>(), aFonts );
+ while( aFonts.begin() != aFonts.end() )
+ {
+ PrintFont* pFont = aFonts.front();
+ aFonts.pop_front();
+ FastPrintFontInfo aInfo;
+ fillPrintFontInfo( pFont, aInfo );
+ rFontProps.push_back( aInfo );
+ delete pFont;
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getFileDuplicates( fontID nFont, ::std::list< fontID >& rFonts ) const
+{
+ bool bRet = false;
+
+ rFonts.clear();
+
+ PrintFont* pSearchFont = getFont( nFont );
+ if( ! pSearchFont ||
+ pSearchFont->m_eType != fonttype::TrueType ||
+ static_cast<TrueTypeFontFile*>(pSearchFont)->m_nCollectionEntry == -1
+ )
+ return false;
+
+ OString aFile( getFontFileSysPath( nFont ) );
+ if( ! aFile.getLength() )
+ return false;
+
+ for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
+ {
+ if( nFont != it->first )
+ {
+ OString aCompFile( getFontFile( it->second ) );
+ if( aCompFile == aFile )
+ {
+ rFonts.push_back( it->first );
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::removeFonts( const ::std::list< fontID >& rFonts )
+{
+ bool bRet = true;
+ ::std::list< fontID > aDuplicates;
+ for( ::std::list< fontID >::const_iterator it = rFonts.begin(); it != rFonts.end(); ++it )
+ {
+ ::std::hash_map< fontID, PrintFont* >::const_iterator haveFont = m_aFonts.find( *it );
+ if( haveFont == m_aFonts.end() )
+ continue;
+
+ PrintFont* pFont = haveFont->second;
+ bool bRemoveDuplicates = getFileDuplicates( *it, aDuplicates );
+ ByteString aFile( getFontFile( pFont ) );
+ if( aFile.Len() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try unlink( \"%s\" ) ... ", aFile.GetBuffer() );
+#endif
+ if( unlink( aFile.GetBuffer() ) )
+ {
+ bRet = false;
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "failed\n" );
+#endif
+ continue;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "succeeded\n" );
+#endif
+ OString aAfm( getAfmFile( pFont ) );
+ if( aAfm.getLength() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "unlink( \"%s\" )\n", aAfm.getStr() );
+#endif
+ unlink( aAfm.getStr() );
+ }
+ m_aFonts.erase( *it );
+ delete pFont;
+ if( bRemoveDuplicates )
+ {
+ for( ::std::list< fontID >::iterator dup = aDuplicates.begin(); dup != aDuplicates.end(); ++dup )
+ {
+ m_aFontFileToFontID[ aFile ].erase( *dup );
+ PrintFont* pDup = m_aFonts[ *dup ];
+ m_aFonts.erase( *dup );
+ delete pDup;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::isPrivateFontFile( fontID nFont ) const
+{
+ bool bRet = false;
+ int nDirID = -1;
+ PrintFont* pFont = getFont( nFont );
+ if( pFont )
+ {
+ switch( pFont->m_eType )
+ {
+ case fonttype::Type1: nDirID = static_cast< Type1FontFile* >(pFont)->m_nDirectory;break;
+ case fonttype::TrueType: nDirID = static_cast< TrueTypeFontFile* >(pFont)->m_nDirectory;break;
+ default: break;
+ }
+ }
+ if( nDirID != -1 )
+ {
+ for( ::std::list< int >::const_iterator it = m_aPrivateFontDirectories.begin(); it != m_aPrivateFontDirectories.end(); ++it )
+ {
+ if( nDirID == *it )
+ {
+ bRet = true;
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::getAlternativeFamilyNames( fontID nFont, ::std::list< OUString >& rNames ) const
+{
+ rNames.clear();
+
+ PrintFont* pFont = getFont( nFont );
+ if( pFont && pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ ByteString aFile( getFontFile( pFont ) );
+ TrueTypeFont* pTTFont;
+ if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
+ {
+ NameRecord* pNameRecords = NULL;
+ int nNameRecords = GetTTNameRecords( pTTFont, &pNameRecords );
+ for( int i = 0; i < nNameRecords; i++ )
+ {
+ if( pNameRecords[i].nameID != 1 ) // family name
+ continue;
+
+ OUString aFamily( convertTrueTypeName( pNameRecords+i ) );
+ if( aFamily.getLength()
+ &&
+ m_pAtoms->getAtom( ATOM_FAMILYNAME, aFamily, sal_True ) != pFont->m_nFamilyName
+ )
+ {
+ rNames.push_back( aFamily );
+ }
+ }
+
+ if( nNameRecords )
+ DisposeNameRecords( pNameRecords, nNameRecords );
+ CloseTTFont( pTTFont );
+ }
+ }
+ return rNames.begin() != rNames.end();
+}
+
+// -------------------------------------------------------------------------
+
+bool PrintFontManager::createFontSubset(
+ fontID nFont,
+ const OUString& rOutFile,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pNewEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ bool bVertical
+ )
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont || pFont->m_eType != fonttype::TrueType )
+ return false;
+
+ OUString aSysPath;
+ if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
+ return false;
+
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ ByteString aFromFile = getFontFile( pFont );
+ ByteString aToFile( OUStringToOString( aSysPath, aEncoding ) );
+
+ sal_uInt8 pEnc[256];
+ sal_uInt16 pGID[256];
+ sal_uInt8 pOldIndex[256];
+
+ memset( pEnc, 0, sizeof( pEnc ) );
+ memset( pGID, 0, sizeof( pGID ) );
+ memset( pOldIndex, 0, sizeof( pOldIndex ) );
+ int nChar = 1;
+ int i;
+ for( i = 0; i < nGlyphs; i++ )
+ {
+ if( pNewEncoding[i] == 0 )
+ {
+ pOldIndex[ 0 ] = i;
+ }
+ else
+ {
+ DBG_ASSERT( !(pGlyphIDs[i] & 0x007f0000), "overlong glyph id" );
+ DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
+ DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
+ pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
+ pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIDs[ i ];
+ pOldIndex[ pNewEncoding[i] ] = i;
+ nChar++;
+ }
+ }
+ nGlyphs = nChar; // either input value or increased by one
+
+ if( nGlyphs > 256 )
+ return false;
+
+ TrueTypeFont* pTTFont = NULL;
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
+ return false;
+
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
+ pGID,
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( i = 0; i < nGlyphs; i++ )
+ pWidths[pOldIndex[i]] = pMetrics[i].adv;
+ free( pMetrics );
+ }
+ else
+ {
+ CloseTTFont( pTTFont );
+ return false;
+ }
+
+ bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
+ aToFile.GetBuffer(),
+ pGID,
+ pEnc,
+ nGlyphs,
+ 0,
+ NULL,
+ 0 ) );
+ CloseTTFont( pTTFont );
+
+ return bSuccess;
+}
+
+void PrintFontManager::getGlyphWidths( fontID nFont,
+ bool bVertical,
+ std::vector< sal_Int32 >& rWidths,
+ std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont ||
+ (pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
+ return;
+ if( pFont->m_eType == fonttype::TrueType )
+ {
+ TrueTypeFont* pTTFont = NULL;
+ TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
+ ByteString aFromFile = getFontFile( pFont );
+ if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
+ return;
+ int nGlyphs = GetTTGlyphCount( pTTFont );
+ if( nGlyphs > 0 )
+ {
+ rWidths.resize(nGlyphs);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphs);
+ for( int i = 0; i < nGlyphs; i++ )
+ aGlyphIds[i] = sal_uInt16(i);
+ TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
+ &aGlyphIds[0],
+ nGlyphs,
+ bVertical ? 1 : 0 );
+ if( pMetrics )
+ {
+ for( int i = 0; i< nGlyphs; i++ )
+ rWidths[i] = pMetrics[i].adv;
+ free( pMetrics );
+ rUnicodeEnc.clear();
+ }
+ }
+ CloseTTFont( pTTFont );
+ }
+ else if( pFont->m_eType == fonttype::Type1 )
+ {
+ if( ! pFont->m_aEncodingVector.size() )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
+ if( pFont->m_pMetrics )
+ {
+ rUnicodeEnc.clear();
+ rWidths.clear();
+ rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
+ for( std::hash_map< int, CharacterMetric >::const_iterator it =
+ pFont->m_pMetrics->m_aMetrics.begin();
+ it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
+ {
+ if( (it->first & 0x00010000) == 0 || bVertical )
+ {
+ rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
+ rWidths.push_back( it->second.width );
+ }
+ }
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, rtl::OString >** pNonEncoded ) const
+{
+ PrintFont* pFont = getFont( nFont );
+ if( !pFont ||
+ (pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
+ )
+ return NULL;
+
+ if( ! pFont->m_aEncodingVector.size() )
+ pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
+
+ if( pNonEncoded )
+ *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
+
+ return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
+}
+
+// -------------------------------------------------------------------------
+
+std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
+{
+ std::pair< std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator,
+ std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator > range
+ = m_aUnicodeToAdobename.equal_range( aChar );
+
+ std::list< OString > aRet;
+ for( ; range.first != range.second; ++range.first )
+ aRet.push_back( range.first->second );
+
+ if( aRet.begin() == aRet.end() && aChar != 0 )
+ {
+ sal_Char aBuf[8];
+ sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
+ aRet.push_back( OString( aBuf, nChars ) );
+ }
+
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const rtl::OString& rName ) const
+{
+ std::pair< std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator,
+ std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator > range
+ = m_aAdobenameToUnicode.equal_range( rName );
+
+ std::list< sal_Unicode > aRet;
+ for( ; range.first != range.second; ++range.first )
+ aRet.push_back( range.first->second );
+
+ if( aRet.begin() == aRet.end() )
+ {
+ if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
+ {
+ sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
+ aRet.push_back( aCode );
+ }
+ }
+
+ return aRet;
+}
+
+// -------------------------------------------------------------------------
+namespace
+{
+ OUString getString( const Any& rAny )
+ {
+ OUString aStr;
+ rAny >>= aStr;
+ return aStr;
+ }
+ bool getBool( const Any& rAny )
+ {
+ sal_Bool bBool = sal_False;
+ rAny >>= bBool;
+ return static_cast<bool>(bBool);
+ }
+ sal_Int32 getInt( const Any& rAny )
+ {
+ sal_Int32 n = 0;
+ rAny >>= n;
+ return n;
+ }
+}
+bool PrintFontManager::readOverrideMetrics()
+{
+ if( ! m_aOverrideFonts.empty() )
+ return false;
+
+ Reference< XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
+ if( !xFact.is() )
+ return false;
+ Reference< XMaterialHolder > xMat(
+ xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.psprint.CompatMetricOverride" ) ) ),
+ UNO_QUERY );
+ if( !xMat.is() )
+ return false;
+
+ Any aAny( xMat->getMaterial() );
+ Sequence< Any > aOverrideFonts;
+ if( ! (aAny >>= aOverrideFonts ) )
+ return false;
+ sal_Int32 nFonts = aOverrideFonts.getLength();
+ for( sal_Int32 i = 0; i < nFonts; i++ )
+ {
+ Sequence< NamedValue > aMetrics;
+ if( ! (aOverrideFonts.getConstArray()[i] >>= aMetrics) )
+ continue;
+ BuiltinFont* pFont = new BuiltinFont();
+ pFont->m_nDirectory = 0;
+ pFont->m_bUserOverride = false;
+ pFont->m_eEmbeddedbitmap = fcstatus::isunset;
+ pFont->m_eAntialias = fcstatus::isunset;
+ pFont->m_pMetrics = new PrintFontMetrics;
+ memset( pFont->m_pMetrics->m_aPages, 0xff, sizeof( pFont->m_pMetrics->m_aPages ) );
+ pFont->m_pMetrics->m_bKernPairsQueried = true;
+ sal_Int32 nProps = aMetrics.getLength();
+ const NamedValue* pProps = aMetrics.getConstArray();
+ for( sal_Int32 n = 0; n < nProps; n++ )
+ {
+ if( pProps[n].Name.equalsAscii( "FamilyName" ) )
+ pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME,
+ getString(pProps[n].Value),
+ sal_True );
+ else if( pProps[n].Name.equalsAscii( "PSName" ) )
+ pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME,
+ getString(pProps[n].Value),
+ sal_True );
+ else if( pProps[n].Name.equalsAscii( "StyleName" ) )
+ pFont->m_aStyleName = getString(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Italic" ) )
+ pFont->m_eItalic = static_cast<italic::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Width" ) )
+ pFont->m_eWidth = static_cast<width::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Weight" ) )
+ pFont->m_eWeight = static_cast<weight::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Pitch" ) )
+ pFont->m_ePitch = static_cast<pitch::type>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "Encoding" ) )
+ pFont->m_aEncoding = static_cast<rtl_TextEncoding>(getInt(pProps[n].Value));
+ else if( pProps[n].Name.equalsAscii( "FontEncodingOnly" ) )
+ pFont->m_bFontEncodingOnly = getBool(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricXWidth" ) )
+ pFont->m_aGlobalMetricX.width = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricXHeight" ) )
+ pFont->m_aGlobalMetricX.height = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricYWidth" ) )
+ pFont->m_aGlobalMetricY.width = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "GlobalMetricYHeight" ) )
+ pFont->m_aGlobalMetricY.height = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Ascend" ) )
+ pFont->m_nAscend = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Descend" ) )
+ pFont->m_nDescend = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "Leading" ) )
+ pFont->m_nLeading = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "XMin" ) )
+ pFont->m_nXMin = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "YMin" ) )
+ pFont->m_nYMin = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "XMax" ) )
+ pFont->m_nXMax = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "YMax" ) )
+ pFont->m_nYMax = getInt(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "VerticalSubstitutes" ) )
+ pFont->m_bHaveVerticalSubstitutedGlyphs = getBool(pProps[n].Value);
+ else if( pProps[n].Name.equalsAscii( "EncodingVector" ) )
+ {
+ Sequence< NamedValue > aEncoding;
+ pProps[n].Value >>= aEncoding;
+ sal_Int32 nEnc = aEncoding.getLength();
+ const NamedValue* pEnc = aEncoding.getConstArray();
+ for( sal_Int32 m = 0; m < nEnc; m++ )
+ {
+ sal_Unicode cCode = *pEnc[m].Name.getStr();
+ sal_Int32 nGlyph = getInt(pEnc[m].Value);
+ pFont->m_aEncodingVector[ cCode ] = nGlyph;
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "NonEncoded" ) )
+ {
+ Sequence< NamedValue > aEncoding;
+ pProps[n].Value >>= aEncoding;
+ sal_Int32 nEnc = aEncoding.getLength();
+ const NamedValue* pEnc = aEncoding.getConstArray();
+ for( sal_Int32 m = 0; m < nEnc; m++ )
+ {
+ sal_Unicode cCode = *pEnc[m].Name.getStr();
+ OUString aGlyphName( getString(pEnc[m].Value) );
+ pFont->m_aNonEncoded[ cCode ] = OUStringToOString(aGlyphName,RTL_TEXTENCODING_ASCII_US);
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "CharacterMetrics" ) )
+ {
+ // fill pFont->m_pMetrics->m_aMetrics
+ // expect triples of int: int -> CharacterMetric.{ width, height }
+ Sequence< sal_Int32 > aSeq;
+ pProps[n].Value >>= aSeq;
+ sal_Int32 nInts = aSeq.getLength();
+ const sal_Int32* pInts = aSeq.getConstArray();
+ for( sal_Int32 m = 0; m < nInts; m+=3 )
+ {
+ pFont->m_pMetrics->m_aMetrics[ pInts[m] ].width = static_cast<short int>(pInts[m+1]);
+ pFont->m_pMetrics->m_aMetrics[ pInts[m] ].height = static_cast<short int>(pInts[m+2]);
+ }
+ }
+ else if( pProps[n].Name.equalsAscii( "XKernPairs" ) )
+ {
+ // fill pFont->m_pMetrics->m_aXKernPairs
+ // expection name: <unicode1><unicode2> value: ((height << 16)| width)
+ Sequence< NamedValue > aKern;
+ pProps[n].Value >>= aKern;
+ KernPair aPair;
+ const NamedValue* pVals = aKern.getConstArray();
+ int nPairs = aKern.getLength();
+ for( int m = 0; m < nPairs; m++ )
+ {
+ if( pVals[m].Name.getLength() == 2 )
+ {
+ aPair.first = pVals[m].Name.getStr()[0];
+ aPair.second = pVals[m].Name.getStr()[1];
+ sal_Int32 nKern = getInt( pVals[m].Value );
+ aPair.kern_x = static_cast<short int>(nKern & 0xffff);
+ aPair.kern_y = static_cast<short int>((sal_uInt32(nKern) >> 16) & 0xffff);
+ pFont->m_pMetrics->m_aXKernPairs.push_back( aPair );
+ }
+ }
+ }
+ }
+ // sanity check
+ if( pFont->m_nPSName &&
+ pFont->m_nFamilyName &&
+ ! pFont->m_pMetrics->m_aMetrics.empty() )
+ {
+ m_aOverrideFonts.push_back( m_nNextFontID );
+ m_aFonts[ m_nNextFontID++ ] = pFont;
+ }
+ else
+ {
+ DBG_ASSERT( 0, "override font failed" );
+ delete pFont;
+ }
+ }
+
+ return true;
+}
diff --git a/vcl/unx/source/fontmanager/helper.cxx b/vcl/unx/source/fontmanager/helper.cxx
new file mode 100644
index 000000000000..2f3821eac7d1
--- /dev/null
+++ b/vcl/unx/source/fontmanager/helper.cxx
@@ -0,0 +1,407 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: helper.cxx,v $
+ * $Revision: 1.35 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include <cstring>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "vcl/helper.hxx"
+#include "vcl/ppdparser.hxx"
+#include "tools/string.hxx"
+#include "tools/urlobj.hxx"
+#include "osl/file.hxx"
+#include "osl/process.h"
+#include "rtl/bootstrap.hxx"
+
+using namespace rtl;
+
+namespace psp {
+
+OUString getOfficePath( enum whichOfficePath ePath )
+{
+ static OUString aNetPath;
+ static OUString aUserPath;
+ static OUString aConfigPath;
+ static OUString aEmpty;
+ static bool bOnce = false;
+
+ if( ! bOnce )
+ {
+ bOnce = true;
+ OUString aIni;
+ Bootstrap::get( OUString( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aIni );
+ aIni += OUString( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
+ Bootstrap aBootstrap( aIni );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "CustomDataUrl" ) ), aConfigPath );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseInstallation" ) ), aNetPath );
+ aBootstrap.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
+ OUString aUPath = aUserPath;
+
+ if( ! aConfigPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aConfigPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aConfigPath = aSysPath;
+ }
+ if( ! aNetPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aNetPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aNetPath = aSysPath;
+ }
+ if( ! aUserPath.compareToAscii( "file://", 7 ) )
+ {
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aUserPath.pData, &aSysPath.pData ) == osl_File_E_None )
+ aUserPath = aSysPath;
+ }
+ // ensure user path exists
+ aUPath += OUString( RTL_CONSTASCII_USTRINGPARAM( "/user/psprint" ) );
+ #if OSL_DEBUG_LEVEL > 1
+ oslFileError eErr =
+ #endif
+ osl_createDirectoryPath( aUPath.pData, NULL, NULL );
+ #if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "try to create \"%s\" = %d\n", OUStringToOString( aUPath, RTL_TEXTENCODING_UTF8 ).getStr(), eErr );
+ #endif
+ }
+
+ switch( ePath )
+ {
+ case ConfigPath: return aConfigPath;
+ case NetPath: return aNetPath;
+ case UserPath: return aUserPath;
+ }
+ return aEmpty;
+}
+
+static OString getEnvironmentPath( const char* pKey )
+{
+ OString aPath;
+
+ const char* pValue = getenv( pKey );
+ if( pValue && *pValue )
+ {
+ aPath = OString( pValue );
+ }
+ return aPath;
+}
+
+} // namespace psp
+
+void psp::getPrinterPathList( std::list< OUString >& rPathList, const char* pSubDir )
+{
+ rPathList.clear();
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+
+ OUStringBuffer aPathBuffer( 256 );
+
+ // append net path
+ aPathBuffer.append( getOfficePath( psp::NetPath ) );
+ if( aPathBuffer.getLength() )
+ {
+ aPathBuffer.appendAscii( "/share/psprint" );
+ if( pSubDir )
+ {
+ aPathBuffer.append( sal_Unicode('/') );
+ aPathBuffer.appendAscii( pSubDir );
+ }
+ rPathList.push_back( aPathBuffer.makeStringAndClear() );
+ }
+ // append user path
+ aPathBuffer.append( getOfficePath( psp::UserPath ) );
+ if( aPathBuffer.getLength() )
+ {
+ aPathBuffer.appendAscii( "/user/psprint" );
+ if( pSubDir )
+ {
+ aPathBuffer.append( sal_Unicode('/') );
+ aPathBuffer.appendAscii( pSubDir );
+ }
+ rPathList.push_back( aPathBuffer.makeStringAndClear() );
+ }
+
+ OString aPath( getEnvironmentPath("SAL_PSPRINT") );
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aDir( aPath.getToken( 0, ':', nIndex ) );
+ if( ! aDir.getLength() )
+ continue;
+
+ if( pSubDir )
+ {
+ aDir += "/";
+ aDir += pSubDir;
+ }
+ struct stat aStat;
+ if( stat( aDir.getStr(), &aStat ) || ! S_ISDIR( aStat.st_mode ) )
+ continue;
+
+ rPathList.push_back( OStringToOUString( aDir, aEncoding ) );
+ } while( nIndex != -1 );
+
+ #ifdef SYSTEM_PPD_DIR
+ if( pSubDir && rtl_str_compare( pSubDir, PRINTER_PPDDIR ) == 0 )
+ {
+ rPathList.push_back( rtl::OStringToOUString( rtl::OString( SYSTEM_PPD_DIR ), RTL_TEXTENCODING_UTF8 ) );
+ }
+ #endif
+
+ if( rPathList.empty() )
+ {
+ // last resort: next to program file (mainly for setup)
+ OUString aExe;
+ if( osl_getExecutableFile( &aExe.pData ) == osl_Process_E_None )
+ {
+ INetURLObject aDir( aExe );
+ aDir.removeSegment();
+ aExe = aDir.GetMainURL( INetURLObject::NO_DECODE );
+ OUString aSysPath;
+ if( osl_getSystemPathFromFileURL( aExe.pData, &aSysPath.pData ) == osl_File_E_None )
+ {
+ rPathList.push_back( aSysPath );
+ }
+ }
+ }
+}
+
+OUString psp::getFontPath()
+{
+ static OUString aPath;
+
+ if( ! aPath.getLength() )
+ {
+ OUStringBuffer aPathBuffer( 512 );
+
+ OUString aConfigPath( getOfficePath( psp::ConfigPath ) );
+ OUString aNetPath( getOfficePath( psp::NetPath ) );
+ OUString aUserPath( getOfficePath( psp::UserPath ) );
+ if( aConfigPath.getLength() )
+ {
+ // #i53530# Path from CustomDataUrl will completely
+ // replace net and user paths if the path exists
+ aPathBuffer.append(aConfigPath);
+ aPathBuffer.appendAscii("/share/fonts");
+ // check existance of config path
+ struct stat aStat;
+ if( 0 != stat( OUStringToOString( aPathBuffer.makeStringAndClear(), osl_getThreadTextEncoding() ).getStr(), &aStat )
+ || ! S_ISDIR( aStat.st_mode ) )
+ aConfigPath = OUString();
+ else
+ {
+ aPathBuffer.append(aConfigPath);
+ aPathBuffer.appendAscii("/share/fonts");
+ }
+ }
+ if( aConfigPath.getLength() == 0 )
+ {
+ if( aNetPath.getLength() )
+ {
+ aPathBuffer.append( aNetPath );
+ aPathBuffer.appendAscii( "/share/fonts/truetype;");
+ aPathBuffer.append( aNetPath );
+ aPathBuffer.appendAscii( "/share/fonts/type1;" );
+ }
+ if( aUserPath.getLength() )
+ {
+ aPathBuffer.append( aUserPath );
+ aPathBuffer.appendAscii( "/user/fonts" );
+ }
+ }
+ OString aEnvPath( getEnvironmentPath( "SAL_FONTPATH_PRIVATE" ) );
+ if( aEnvPath.getLength() )
+ {
+ aPathBuffer.append( sal_Unicode(';') );
+ aPathBuffer.append( OStringToOUString( aEnvPath, osl_getThreadTextEncoding() ) );
+ }
+
+ aPath = aPathBuffer.makeStringAndClear();
+#if OSL_DEBUG_LEVEL > 1
+ fprintf( stderr, "initializing font path to \"%s\"\n", OUStringToOString( aPath, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
+#endif
+ }
+ return aPath;
+}
+
+bool psp::convertPfbToPfa( ::osl::File& rInFile, ::osl::File& rOutFile )
+{
+ static unsigned char hexDigits[] =
+ {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ bool bSuccess = true;
+ bool bEof = false;
+ unsigned char buffer[256];
+ sal_uInt64 nRead;
+ sal_uInt64 nOrgPos = 0;
+ rInFile.getPos( nOrgPos );
+
+ while( bSuccess && ! bEof )
+ {
+ // read leading bytes
+ bEof = ! rInFile.read( buffer, 6, nRead ) && nRead == 6 ? false : true;
+ unsigned int nType = buffer[ 1 ];
+ unsigned int nBytesToRead = buffer[2] | buffer[3] << 8 | buffer[4] << 16 | buffer[5] << 24;
+ if( buffer[0] != 0x80 ) // test for pfb m_agic number
+ {
+ // this migt be a pfa font already
+ sal_uInt64 nWrite = 0;
+ if( ! rInFile.read( buffer+6, 9, nRead ) && nRead == 9 &&
+ ( ! std::strncmp( (char*)buffer, "%!FontType1-", 12 ) ||
+ ! std::strncmp( (char*)buffer, "%!PS-AdobeFont-", 15 ) ) )
+ {
+ if( rOutFile.write( buffer, 15, nWrite ) || nWrite != 15 )
+ bSuccess = false;
+ while( bSuccess &&
+ ! rInFile.read( buffer, sizeof( buffer ), nRead ) &&
+ nRead != 0 )
+ {
+ if( rOutFile.write( buffer, nRead, nWrite ) ||
+ nWrite != nRead )
+ bSuccess = false;
+ }
+ bEof = true;
+ }
+ else
+ bSuccess = false;
+ }
+ else if( nType == 1 || nType == 2 )
+ {
+ unsigned char* pBuffer = new unsigned char[ nBytesToRead+1 ];
+
+ if( ! rInFile.read( pBuffer, nBytesToRead, nRead ) && nRead == nBytesToRead )
+ {
+ if( nType == 1 )
+ {
+ // ascii data, convert dos lineends( \r\n ) and
+ // m_ac lineends( \r ) to \n
+ unsigned char * pWriteBuffer = new unsigned char[ nBytesToRead ];
+ unsigned int nBytesToWrite = 0;
+ for( unsigned int i = 0; i < nBytesToRead; i++ )
+ {
+ if( pBuffer[i] != '\r' )
+ pWriteBuffer[ nBytesToWrite++ ] = pBuffer[i];
+ else if( pBuffer[ i+1 ] == '\n' )
+ {
+ i++;
+ pWriteBuffer[ nBytesToWrite++ ] = '\n';
+ }
+ else
+ pWriteBuffer[ nBytesToWrite++ ] = '\n';
+ }
+ if( rOutFile.write( pWriteBuffer, nBytesToWrite, nRead ) || nRead != nBytesToWrite )
+ bSuccess = false;
+
+ delete [] pWriteBuffer;
+ }
+ else
+ {
+ // binary data
+ unsigned int nBuffer = 0;
+ for( unsigned int i = 0; i < nBytesToRead && bSuccess; i++ )
+ {
+ buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] >> 4 ];
+ buffer[ nBuffer++ ] = hexDigits[ pBuffer[ i ] & 15 ];
+ if( nBuffer >= 80 )
+ {
+ buffer[ nBuffer++ ] = '\n';
+ if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
+ bSuccess = false;
+ nBuffer = 0;
+ }
+ }
+ if( nBuffer > 0 && bSuccess )
+ {
+ buffer[ nBuffer++ ] = '\n';
+ if( rOutFile.write( buffer, nBuffer, nRead ) || nRead != nBuffer )
+ bSuccess = false;
+ }
+ }
+ }
+ else
+ bSuccess = false;
+
+ delete [] pBuffer;
+ }
+ else if( nType == 3 )
+ bEof = true;
+ else
+ bSuccess = false;
+ }
+
+ return bSuccess;
+}
+
+void psp::normPath( OString& rPath )
+{
+ char buf[PATH_MAX];
+
+ ByteString aPath( rPath );
+
+ // double slashes and slash at end are probably
+ // removed by realpath anyway, but since this runs
+ // on many different platforms let's play it safe
+ while( aPath.SearchAndReplace( "//", "/" ) != STRING_NOTFOUND )
+ ;
+ if( aPath.Len() > 0 && aPath.GetChar( aPath.Len()-1 ) == '/' )
+ aPath.Erase( aPath.Len()-1 );
+
+ if( ( aPath.Search( "./" ) != STRING_NOTFOUND ||
+ aPath.Search( "~" ) != STRING_NOTFOUND )
+ && realpath( aPath.GetBuffer(), buf ) )
+ {
+ rPath = buf;
+ }
+ else
+ {
+ rPath = aPath;
+ }
+}
+
+void psp::splitPath( OString& rPath, OString& rDir, OString& rBase )
+{
+ normPath( rPath );
+ sal_Int32 nIndex = rPath.lastIndexOf( '/' );
+ if( nIndex > 0 )
+ rDir = rPath.copy( 0, nIndex );
+ else if( nIndex == 0 ) // root dir
+ rDir = rPath.copy( 0, 1 );
+ if( rPath.getLength() > nIndex+1 )
+ rBase = rPath.copy( nIndex+1 );
+}
+
+
diff --git a/vcl/unx/source/fontmanager/makefile.mk b/vcl/unx/source/fontmanager/makefile.mk
new file mode 100644
index 000000000000..c1d1fde15de3
--- /dev/null
+++ b/vcl/unx/source/fontmanager/makefile.mk
@@ -0,0 +1,76 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.11 $
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+ENABLE_EXCEPTIONS=TRUE
+PRJNAME=vcl
+TARGET=fontman
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+CFLAGS+= -I..$/fontsubset
+INCDEPN+= -I..$/fontsubset
+
+.IF "$(ENABLE_FONTCONFIG)" != ""
+CDEFS += -DENABLE_FONTCONFIG
+.ENDIF
+
+CFLAGS+=$(FREETYPE_CFLAGS)
+
+
+# --- Files --------------------------------------------------------
+
+.IF "$(GUIBASE)"=="aqua"
+
+dummy:
+ @echo "Nothing to build for GUIBASE $(GUIBASE)"
+
+.ELSE # "$(GUIBASE)"=="aqua"
+
+SLOFILES=\
+ $(SLO)$/fontmanager.obj \
+ $(SLO)$/fontcache.obj \
+ $(SLO)$/fontconfig.obj \
+ $(SLO)$/helper.obj \
+ $(SLO)$/parseAFM.obj
+
+.IF "$(OS)$(CPU)"=="SOLARISI"
+NOOPTFILES=$(SLO)$/fontmanager.obj
+.ENDIF
+
+.ENDIF
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/vcl/unx/source/fontmanager/parseAFM.cxx b/vcl/unx/source/fontmanager/parseAFM.cxx
new file mode 100644
index 000000000000..0ac4754d4bd5
--- /dev/null
+++ b/vcl/unx/source/fontmanager/parseAFM.cxx
@@ -0,0 +1,1569 @@
+/*
+ * (C) 1988, 1989, 1990 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - performance increase:
+ * - fread file in one pass
+ * - replace file io by buffer access
+ * 10/20/2005 pl - performance increase:
+ * - use one table lookup in token() routine
+ * instead of many conditions
+ * - return token length in toke() routine
+ * - use hash lookup instead of binary search
+ * in recognize() routine
+ */
+
+/*************************************************************************
+ *
+ * $RCSfile: parseAFM.cxx,v $
+ *
+ * $Revision: 1.11 $
+ *
+ * last change: $Author: rt $ $Date: 2008-01-29 16:08:31 $
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+/* parseAFM.c
+ *
+ * This file is used in conjuction with the parseAFM.h header file.
+ * This file contains several procedures that are used to parse AFM
+ * files. It is intended to work with an application program that needs
+ * font metric information. The program can be used as is by making a
+ * procedure call to "parseFile" (passing in the expected parameters)
+ * and having it fill in a data structure with the data from the
+ * AFM file, or an application developer may wish to customize this
+ * code.
+ *
+ * There is also a file, parseAFMclient.c, that is a sample application
+ * showing how to call the "parseFile" procedure and how to use the data
+ * after "parseFile" has returned.
+ *
+ * Please read the comments in parseAFM.h and parseAFMclient.c.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed bug of not allocating extra byte for string duplication
+ * - fixed typos
+ * modified: DSM Tue Apr 3 11:18:34 PDT 1990
+ * - added free(ident) at end of parseFile routine
+ * modified: DSM Tue Jun 19 10:16:29 PDT 1990
+ * - changed (width == 250) to (width = 250) in initializeArray
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <math.h>
+
+#include "parseAFM.hxx"
+#include "vcl/strhelper.hxx"
+
+#include "rtl/alloc.h"
+
+#define lineterm EOL /* line terminating character */
+#define normalEOF 1 /* return code from parsing routines used only */
+/* in this module */
+#define Space "space" /* used in string comparison to look for the width */
+/* of the space character to init the widths array */
+#define False "false" /* used in string comparison to check the value of */
+/* boolean keys (e.g. IsFixedPitch) */
+
+#define MATCH(A,B) (strncmp((A),(B), MAX_NAME) == 0)
+
+namespace psp {
+
+class FileInputStream
+{
+ char* m_pMemory;
+ unsigned int m_nPos;
+ unsigned int m_nLen;
+ public:
+ FileInputStream( const char* pFilename );
+ ~FileInputStream();
+
+ int getChar() { return (m_nPos < m_nLen) ? int(m_pMemory[m_nPos++]) : -1; }
+ void ungetChar()
+ {
+ if( m_nPos > 0 )
+ m_nPos--;
+ }
+ unsigned int tell() const { return m_nPos; }
+ void seek( unsigned int nPos )
+ // NOTE: do not check input data since only results of tell()
+ // get seek()ed in this file
+ { m_nPos = nPos; }
+};
+
+FileInputStream::FileInputStream( const char* pFilename ) :
+ m_pMemory( NULL ),
+ m_nPos( 0 ),
+ m_nLen( 0 )
+{
+ struct stat aStat;
+ if( ! stat( pFilename, &aStat ) &&
+ S_ISREG( aStat.st_mode ) &&
+ aStat.st_size > 0
+ )
+ {
+ FILE* fp = fopen( pFilename, "r" );
+ if( fp )
+ {
+ m_pMemory = (char*)rtl_allocateMemory( aStat.st_size );
+ m_nLen = (unsigned int)fread( m_pMemory, 1, aStat.st_size, fp );
+ fclose( fp );
+ }
+ }
+}
+
+FileInputStream::~FileInputStream()
+{
+ rtl_freeMemory( m_pMemory );
+}
+
+/*************************** GLOBALS ***********************/
+/* "shorts" for fast case statement
+ * The values of each of these enumerated items correspond to an entry in the
+ * table of strings defined below. Therefore, if you add a new string as
+ * new keyword into the keyStrings table, you must also add a corresponding
+ * parseKey AND it MUST be in the same position!
+ *
+ * IMPORTANT: since the sorting algorithm is a binary search, the strings of
+ * keywords must be placed in lexicographical order, below. [Therefore, the
+ * enumerated items are not necessarily in lexicographical order, depending
+ * on the name chosen. BUT, they must be placed in the same position as the
+ * corresponding key string.] The NOPE shall remain in the last position,
+ * since it does not correspond to any key string, and it is used in the
+ * "recognize" procedure to calculate how many possible keys there are.
+ */
+
+// some metrics have Ascent, Descent instead Ascender, Descender or Em
+// which is not allowed per afm spcification, but let us handle
+// this gently
+enum parseKey {
+ ASCENDER, ASCENT, CHARBBOX, CODE, COMPCHAR, CODEHEX, CAPHEIGHT, CHARWIDTH, CHARACTERSET, CHARACTERS, COMMENT,
+ DESCENDER, DESCENT, EM, ENCODINGSCHEME, ENDCHARMETRICS, ENDCOMPOSITES, ENDDIRECTION,
+ ENDFONTMETRICS, ENDKERNDATA, ENDKERNPAIRS, ENDTRACKKERN,
+ FAMILYNAME, FONTBBOX, FONTNAME, FULLNAME, ISBASEFONT, ISFIXEDPITCH,
+ ITALICANGLE, KERNPAIR, KERNPAIRXAMT, LIGATURE, MAPPINGSCHEME, METRICSSETS, CHARNAME,
+ NOTICE, COMPCHARPIECE, STARTCHARMETRICS, STARTCOMPOSITES, STARTDIRECTION,
+ STARTFONTMETRICS, STARTKERNDATA, STARTKERNPAIRS,
+ STARTTRACKKERN, STDHW, STDVW, TRACKKERN, UNDERLINEPOSITION,
+ UNDERLINETHICKNESS, VVECTOR, VERSION, XYWIDTH, X0WIDTH, XWIDTH, WEIGHT, XHEIGHT,
+ NOPE
+};
+
+/*************************** PARSING ROUTINES **************/
+
+/*************************** token *************************/
+
+/* A "AFM file Conventions" tokenizer. That means that it will
+ * return the next token delimited by white space. See also
+ * the `linetoken' routine, which does a similar thing but
+ * reads all tokens until the next end-of-line.
+ */
+
+// token white space is ' ', '\n', '\r', ',', '\t', ';'
+static const bool is_white_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, true, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, false, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+// token delimiters are ' ', '\n', '\r', '\t', ':', ';'
+static const bool is_delimiter_Array[ 256 ] =
+{ false, false, false, false, false, false, false, false, // 0-7
+ false, true, true, false, false, true, false, false, // 8-15
+ false, false, false, false, false, false, false, false, // 16-23
+ false, false, false, false, false, false, false, false, // 24-31
+ true, false, false, false, false, false, false, false, // 32-39
+ false, false, false, false, false, false, false, false, // 40-47
+ false, false, false, false, false, false, false, false, // 48-55
+ false, false, true, true, false, false, false, false, // 56-63
+
+ false, false, false, false, false, false, false, false, // 64 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 127
+
+ false, false, false, false, false, false, false, false, // 128 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 191
+
+ false, false, false, false, false, false, false, false, // 192 -
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, // 255
+};
+static char *token( FileInputStream* stream, int& rLen )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+
+ int ch, idx;
+
+ /* skip over white space */
+ // relies on EOF = -1
+ while( is_white_Array[ (ch = stream->getChar()) & 255 ] )
+ ;
+
+ idx = 0;
+ while( ch != -1 && ! is_delimiter_Array[ ch & 255 ] && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ }
+
+ if (ch == -1 && idx < 1) return ((char *)NULL);
+ if (idx >= 1 && ch != ':' && ch != -1) stream->ungetChar();
+ if (idx < 1 ) ident[idx++] = ch; /* single-character token */
+ ident[idx] = 0;
+ rLen = idx;
+
+ return(ident); /* returns pointer to the token */
+
+} /* token */
+
+
+/*************************** linetoken *************************/
+
+/* "linetoken" will get read all tokens until the EOL character from
+ * the given stream. This is used to get any arguments that can be
+ * more than one word (like Comment lines and FullName).
+ */
+
+static char *linetoken( FileInputStream* stream )
+{
+ static char ident[MAX_NAME]; /* storage buffer for keywords */
+ int ch, idx;
+
+ while ((ch = stream->getChar()) == ' ' || ch == '\t' ) ;
+
+ idx = 0;
+ while (ch != -1 && ch != lineterm && ch != '\r' && idx < MAX_NAME-1 )
+ {
+ ident[idx++] = ch;
+ ch = stream->getChar();
+ } /* while */
+
+ stream->ungetChar();
+ ident[idx] = 0;
+
+ return(ident); /* returns pointer to the token */
+
+} /* linetoken */
+
+
+/*************************** recognize *************************/
+
+/* This function tries to match a string to a known list of
+ * valid AFM entries (check the keyStrings array above).
+ * "ident" contains everything from white space through the
+ * next space, tab, or ":" character.
+ *
+ * The algorithm is a standard Knuth binary search.
+ */
+#include "afm_hash.cpp"
+
+static inline enum parseKey recognize( register char* ident, int len)
+{
+ const hash_entry* pEntry = AfmKeywordHash::in_word_set( ident, len );
+ return pEntry ? pEntry->eKey : NOPE;
+
+} /* recognize */
+
+
+/************************* parseGlobals *****************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "StartCharMetrics" keyword, which essentially marks the
+ * end of the Global Font Information and the beginning of the character
+ * metrics information.
+ *
+ * If the caller of "parseFile" specified that it wanted the Global
+ * Font Information (as defined by the "AFM file Specification"
+ * document), then that information will be stored in the returned
+ * data structure.
+ *
+ * Any Global Font Information entries that are not found in a
+ * given file, will have the usual default initialization value
+ * for its type (i.e. entries of type int will be 0, etc).
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseGlobals( FileInputStream* fp, register GlobalFontInfo* gfi )
+{
+ bool cont = true, save = (gfi != NULL);
+ int error = ok;
+ register char *keyword;
+ int direction = -1;
+ int tokenlen;
+
+ while (cont)
+ {
+ keyword = token(fp, tokenlen);
+
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Global Font info section */
+ /* without saving any of the data */
+ switch (recognize(keyword, tokenlen))
+ {
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire global font info section, */
+ /* saving the data */
+ switch(recognize(keyword, tokenlen))
+ {
+ case STARTFONTMETRICS:
+ keyword = token(fp,tokenlen);
+ gfi->afmVersion = strdup( keyword );
+ break;
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case FONTNAME:
+ keyword = token(fp, tokenlen);
+ gfi->fontName = strdup( keyword );
+ break;
+ case ENCODINGSCHEME:
+ keyword = token(fp, tokenlen);
+ gfi->encodingScheme = strdup( keyword );
+ break;
+ case FULLNAME:
+ keyword = linetoken(fp);
+ gfi->fullName = strdup( keyword );
+ break;
+ case FAMILYNAME:
+ keyword = linetoken(fp);
+ gfi->familyName = strdup( keyword );
+ break;
+ case WEIGHT:
+ keyword = token(fp, tokenlen);
+ gfi->weight = strdup( keyword );
+ break;
+ case ITALICANGLE:
+ keyword = token(fp,tokenlen);
+ gfi->italicAngle = StringToDouble( keyword );
+ break;
+ case ISFIXEDPITCH:
+ keyword = token(fp,tokenlen);
+ if (MATCH(keyword, False))
+ gfi->isFixedPitch = 0;
+ else
+ gfi->isFixedPitch = 1;
+ break;
+ case UNDERLINEPOSITION:
+ keyword = token(fp,tokenlen);
+ gfi->underlinePosition = atoi(keyword);
+ break;
+ case UNDERLINETHICKNESS:
+ keyword = token(fp,tokenlen);
+ gfi->underlineThickness = atoi(keyword);
+ break;
+ case VERSION:
+ keyword = token(fp,tokenlen);
+ gfi->version = strdup( keyword );
+ break;
+ case NOTICE:
+ keyword = linetoken(fp);
+ gfi->notice = strdup( keyword );
+ break;
+ case FONTBBOX:
+ keyword = token(fp,tokenlen);
+ gfi->fontBBox.llx = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ gfi->fontBBox.lly = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ gfi->fontBBox.urx = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ gfi->fontBBox.ury = atoi(keyword);
+ break;
+ case CAPHEIGHT:
+ keyword = token(fp,tokenlen);
+ gfi->capHeight = atoi(keyword);
+ break;
+ case XHEIGHT:
+ keyword = token(fp,tokenlen);
+ gfi->xHeight = atoi(keyword);
+ break;
+ case DESCENT:
+ keyword = token(fp,tokenlen);
+ gfi->descender = -atoi(keyword);
+ break;
+ case DESCENDER:
+ keyword = token(fp,tokenlen);
+ gfi->descender = atoi(keyword);
+ break;
+ case ASCENT:
+ case ASCENDER:
+ keyword = token(fp,tokenlen);
+ gfi->ascender = atoi(keyword);
+ break;
+ case STARTCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case EM:
+ // skip one token
+ keyword = token(fp,tokenlen);
+ break;
+ case STARTDIRECTION:
+ keyword = token(fp,tokenlen);
+ direction = atoi(keyword);
+ break; /* ignore this for now */
+ case ENDDIRECTION:
+ break; /* ignore this for now */
+ case MAPPINGSCHEME:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case ISBASEFONT:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case CHARACTERSET:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDHW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case STDVW:
+ keyword=token(fp,tokenlen); //ignore
+ break;
+ case CHARWIDTH:
+ keyword = token(fp,tokenlen);
+ if (direction == 0)
+ gfi->charwidth = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ /* ignore y-width for now */
+ break;
+ case METRICSSETS:
+ keyword = token(fp,tokenlen);
+ break; /* ignore this for now */
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseGlobals */
+
+
+#if 0
+/************************* initializeArray ************************/
+
+/* Unmapped character codes are (at Adobe Systems) assigned the
+ * width of the space character (if one exists) else they get the
+ * value of 250 ems. This function initializes all entries in the
+ * char widths array to have this value. Then any mapped character
+ * codes will be replaced with the width of the appropriate character
+ * when parsing the character metric section.
+
+ * This function parses the Character Metrics Section looking
+ * for a space character (by comparing character names). If found,
+ * the width of the space character will be used to initialize the
+ * values in the array of character widths.
+ *
+ * Before returning, the position of the read/write pointer of the
+ * FileInputStream is reset to be where it was upon entering this function.
+ */
+
+static int initializeArray( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, found = false;
+ unsigned int opos = fp->tell();
+ int code = 0, width = 0, i = 0, error = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ code = atoi(token(fp,tokenlen));
+ break;
+ case CODEHEX:
+ sscanf(token(fp,tokenlen),"<%x>", &code);
+ break;
+ case XWIDTH:
+ width = atoi(token(fp,tokenlen));
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case CHARNAME:
+ keyword = token(fp,tokenlen);
+ if (MATCH(keyword, Space))
+ {
+ cont = false;
+ found = true;
+ }
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (!found)
+ width = 250;
+
+ for (i = 0; i < 256; ++i)
+ cwi[i] = width;
+
+ fp->seek(opos);
+
+ return(error);
+
+} /* initializeArray */
+#endif
+
+/************************* parseCharWidths **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndCharMetrics" keyword. It will save the character
+ * width info (as opposed to all of the character metric information)
+ * if requested by the caller of parseFile. Otherwise, it will just
+ * parse through the section without saving any information.
+ *
+ * If data is to be saved, parseCharWidths is passed in a pointer
+ * to an array of widths that has already been initialized by the
+ * standard value for unmapped character codes. This function parses
+ * the Character Metrics section only storing the width information
+ * for the encoded characters into the array using the character code
+ * as the index into that array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharWidths( FileInputStream* fp, register int* cwi)
+{
+ bool cont = true, save = (cwi != NULL);
+ int pos = 0, error = ok, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Char Metrics section without */
+ /* saving any of the data*/
+ switch (recognize(keyword,tokenlen))
+ {
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire char metrics section, saving */
+ /* only the char x-width info */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ keyword = token(fp,tokenlen);
+ pos = atoi(keyword);
+ break;
+ case XYWIDTH:
+ /* PROBLEM: Should be no Y-WIDTH when doing "quick & dirty" */
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen); /* eat values */
+ error = parseError;
+ break;
+ case CODEHEX:
+ keyword = token(fp,tokenlen);
+ sscanf(keyword, "<%x>", &pos);
+ break;
+ case X0WIDTH:
+ (void) token(fp,tokenlen);
+ break;
+ case XWIDTH:
+ keyword = token(fp,tokenlen);
+ if (pos >= 0) /* ignore unmapped chars */
+ cwi[pos] = atoi(keyword);
+ break;
+ case ENDCHARMETRICS:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case CHARNAME: /* eat values (so doesn't cause parseError) */
+ keyword = token(fp,tokenlen);
+ break;
+ case CHARBBOX:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case LIGATURE:
+ keyword = token(fp,tokenlen); keyword = token(fp,tokenlen);
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ return(error);
+
+} /* parseCharWidths */
+
+
+/*
+ * number of char metrics is almost allways inaccurate, so be gentle and try to
+ * adapt our internal storage by adjusting the allocated list
+ */
+
+static int
+reallocFontMetrics( void **pp_fontmetrics, int *p_oldcount, int n_newcount, unsigned int n_size )
+{
+ char *p_tmpmetrics = NULL;
+
+ if ((pp_fontmetrics == NULL) || (*pp_fontmetrics == NULL))
+ return storageProblem;
+
+ if (*p_oldcount == n_newcount)
+ return ok;
+
+ p_tmpmetrics = (char*)realloc(*pp_fontmetrics, n_newcount * n_size);
+ if (p_tmpmetrics == NULL)
+ return storageProblem;
+
+ if ( n_newcount > *p_oldcount )
+ {
+ char *p_inimetrics = p_tmpmetrics + n_size * *p_oldcount;
+ int n_inimetrics = n_size * (n_newcount - *p_oldcount);
+ memset( p_inimetrics, 0, n_inimetrics );
+ }
+
+ *pp_fontmetrics = p_tmpmetrics;
+ *p_oldcount = n_newcount;
+
+ return ok;
+}
+
+static unsigned int
+enlargeCount( unsigned int n_oldcount )
+{
+ unsigned int n_newcount = n_oldcount + n_oldcount / 5;
+ if (n_oldcount == n_newcount )
+ n_newcount = n_oldcount + 5;
+
+ return n_newcount;
+}
+
+/************************* parseCharMetrics ************************/
+
+/* This function is called by parseFile if the caller of parseFile
+ * requested that all character metric information be saved
+ * (as opposed to only the character width information).
+ *
+ * parseCharMetrics is passed in a pointer to an array of records
+ * to hold information on a per character basis. This function
+ * parses the Character Metrics section storing all character
+ * metric information for the ALL characters (mapped and unmapped)
+ * into the array.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCharMetrics( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true;
+ int error = ok, count = 0, tokenlen;
+ register CharMetricInfo *temp = fi->cmi;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case CODE:
+ if (!(count < fi->numOfChars))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars)
+ {
+ if (firstTime) firstTime = false;
+ else temp++;
+ temp->code = atoi(token(fp,tokenlen));
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case CODEHEX:
+ if (!(count < fi->numOfChars ))
+ {
+ reallocFontMetrics( (void**)&(fi->cmi),
+ &(fi->numOfChars), enlargeCount(fi->numOfChars),
+ sizeof(CharMetricInfo) );
+ temp = &(fi->cmi[ count - 1 ]);
+ }
+ if (count < fi->numOfChars) {
+ if (firstTime)
+ firstTime = false;
+ else
+ temp++;
+ sscanf(token(fp,tokenlen),"<%x>", &temp->code);
+ if (fi->gfi && fi->gfi->charwidth)
+ temp->wx = fi->gfi->charwidth;
+ count++;
+ }
+ else {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case XYWIDTH:
+ temp->wx = atoi(token(fp,tokenlen));
+ temp->wy = atoi(token(fp,tokenlen));
+ break;
+ case X0WIDTH:
+ temp->wx = atoi(token(fp,tokenlen));
+ break;
+ case XWIDTH:
+ temp->wx = atoi(token(fp,tokenlen));
+ break;
+ case CHARNAME:
+ keyword = token(fp,tokenlen);
+ temp->name = (char *)strdup(keyword);
+ break;
+ case CHARBBOX:
+ temp->charBBox.llx = atoi(token(fp,tokenlen));
+ temp->charBBox.lly = atoi(token(fp,tokenlen));
+ temp->charBBox.urx = atoi(token(fp,tokenlen));
+ temp->charBBox.ury = atoi(token(fp,tokenlen));
+ break;
+ case LIGATURE: {
+ Ligature **tail = &(temp->ligs);
+ Ligature *node = *tail;
+
+ if (*tail != NULL)
+ {
+ while (node->next != NULL)
+ node = node->next;
+ tail = &(node->next);
+ }
+
+ *tail = (Ligature *) calloc(1, sizeof(Ligature));
+ keyword = token(fp,tokenlen);
+ (*tail)->succ = (char *)strdup(keyword);
+ keyword = token(fp,tokenlen);
+ (*tail)->lig = (char *)strdup(keyword);
+ break; }
+ case ENDCHARMETRICS:
+ cont = false;;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case VVECTOR:
+ keyword = token(fp,tokenlen);
+ keyword = token(fp,tokenlen);
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = reallocFontMetrics( (void**)&(fi->cmi), &(fi->numOfChars),
+ count, sizeof(CharMetricInfo) );
+
+ if ((error == ok) && (count != fi->numOfChars))
+ error = parseError;
+
+ return(error);
+
+} /* parseCharMetrics */
+
+
+
+/************************* parseTrackKernData ***********************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndTrackKern" or "EndKernData" keywords. It will save the
+ * track kerning data if requested by the caller of parseFile.
+ *
+ * parseTrackKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the track kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseTrackKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->tkd != NULL);
+ int pos = 0, error = ok, tcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Track Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Track Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case TRACKKERN:
+ if (!(tcount < fi->numOfTracks))
+ {
+ reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ enlargeCount(fi->numOfTracks), sizeof(TrackKernData) );
+ }
+
+ if (tcount < fi->numOfTracks)
+ {
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos].degree = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos].minPtSize = StringToDouble(keyword);
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos].minKernAmt = StringToDouble(keyword);
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos].maxPtSize = StringToDouble(keyword);
+ keyword = token(fp,tokenlen);
+ fi->tkd[pos++].maxKernAmt = StringToDouble(keyword);
+ tcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDTRACKKERN:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = reallocFontMetrics( (void**)&(fi->tkd), &(fi->numOfTracks),
+ tcount, sizeof(TrackKernData) );
+
+ if (error == ok && tcount != fi->numOfTracks)
+ error = parseError;
+
+ return(error);
+
+} /* parseTrackKernData */
+
+
+/************************* parsePairKernData ************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndKernPairs" or "EndKernData" keywords. It will save
+ * the pair kerning data if requested by the caller of parseFile.
+ *
+ * parsePairKernData is passed in a pointer to the FontInfo record.
+ * If data is to be saved, the FontInfo record will already contain
+ * a valid pointer to storage for the pair kerning data.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parsePairKernData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, save = (fi->pkd != NULL);
+ int pos = 0, error = ok, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+
+ if (keyword == NULL)
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Pair Kerning Data */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Pair Kerning Data section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case KERNPAIR:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].name1 = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].name2 = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].xamt = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos++].yamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case KERNPAIRXAMT:
+ if (!(pcount < fi->numOfPairs))
+ {
+ reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ enlargeCount(fi->numOfPairs), sizeof(PairKernData) );
+ }
+ if (pcount < fi->numOfPairs)
+ {
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].name1 = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos].name2 = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->pkd[pos++].xamt = atoi(keyword);
+ pcount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case ENDKERNPAIRS:
+ case ENDKERNDATA:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if ((error == ok) && (pcount != fi->numOfPairs))
+ error = reallocFontMetrics( (void**)&(fi->pkd), &(fi->numOfPairs),
+ pcount, sizeof(PairKernData) );
+
+ if (error == ok && pcount != fi->numOfPairs)
+ error = parseError;
+
+ return(error);
+
+} /* parsePairKernData */
+
+
+/************************* parseCompCharData **************************/
+
+/* This function is called by "parseFile". It will parse the AFM file
+ * up to the "EndComposites" keyword. It will save the composite
+ * character data if requested by the caller of parseFile.
+ *
+ * parseCompCharData is passed in a pointer to the FontInfo record, and
+ * a boolean representing if the data should be saved.
+ *
+ * This function will create the appropriate amount of storage for
+ * the composite character data and store a pointer to the storage
+ * in the FontInfo record.
+ *
+ * This function returns an error code specifying whether there was
+ * a premature EOF or a parsing error. This return value is used by
+ * parseFile to determine if there is more file to parse.
+ */
+
+static int parseCompCharData( FileInputStream* fp, register FontInfo* fi)
+{
+ bool cont = true, firstTime = true, save = (fi->ccd != NULL);
+ int pos = 0, j = 0, error = ok, ccount = 0, pcount = 0, tokenlen;
+ register char *keyword;
+
+ while (cont)
+ {
+ keyword = token(fp,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ error = earlyEOF;
+ break; /* get out of loop */
+ }
+ if (ccount > fi->numOfComps)
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount > fi->numOfComps)
+ {
+ error = parseError;
+ break; /* get out of loop */
+ }
+ if (!save)
+ /* get tokens until the end of the Composite Character info */
+ /* section without saving any of the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case COMMENT:
+ case COMPCHAR:
+ keyword = linetoken(fp);
+ break;
+ default:
+ break;
+ } /* switch */
+ else
+ /* otherwise parse entire Composite Character info section, */
+ /* saving the data */
+ switch(recognize(keyword,tokenlen))
+ {
+ case COMMENT:
+ keyword = linetoken(fp);
+ break;
+ case COMPCHAR:
+ if (!(ccount < fi->numOfComps))
+ {
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ enlargeCount(fi->numOfComps), sizeof(CompCharData) );
+ }
+ if (ccount < fi->numOfComps)
+ {
+ keyword = token(fp,tokenlen);
+ if (pcount != fi->ccd[pos].numOfPieces)
+ error = parseError;
+ pcount = 0;
+ if (firstTime) firstTime = false;
+ else pos++;
+ fi->ccd[pos].ccName = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->ccd[pos].numOfPieces = atoi(keyword);
+ fi->ccd[pos].pieces = (Pcc *)
+ calloc(fi->ccd[pos].numOfPieces, sizeof(Pcc));
+ j = 0;
+ ccount++;
+ }
+ else
+ {
+ error = parseError;
+ cont = false;
+ }
+ break;
+ case COMPCHARPIECE:
+ if (pcount < fi->ccd[pos].numOfPieces)
+ {
+ keyword = token(fp,tokenlen);
+ fi->ccd[pos].pieces[j].pccName = strdup( keyword );
+ keyword = token(fp,tokenlen);
+ fi->ccd[pos].pieces[j].deltax = atoi(keyword);
+ keyword = token(fp,tokenlen);
+ fi->ccd[pos].pieces[j++].deltay = atoi(keyword);
+ pcount++;
+ }
+ else
+ error = parseError;
+ break;
+ case ENDCOMPOSITES:
+ cont = false;
+ break;
+ case ENDFONTMETRICS:
+ cont = false;
+ error = normalEOF;
+ break;
+ case NOPE:
+ default:
+ error = parseError;
+ break;
+ } /* switch */
+ } /* while */
+
+ if (error == ok && ccount != fi->numOfComps)
+ reallocFontMetrics( (void**)&(fi->ccd), &(fi->numOfComps),
+ ccount, sizeof(CompCharData) );
+
+ if (error == ok && ccount != fi->numOfComps)
+ error = parseError;
+
+ return(error);
+
+} /* parseCompCharData */
+
+
+
+
+/*************************** 'PUBLIC' FUNCTION ********************/
+
+
+/*************************** parseFile *****************************/
+
+/* parseFile is the only 'public' procedure available. It is called
+ * from an application wishing to get information from an AFM file.
+ * The caller of this function is responsible for locating and opening
+ * an AFM file and handling all errors associated with that task.
+ *
+ * parseFile expects 3 parameters: a filename pointer, a pointer
+ * to a (FontInfo *) variable (for which storage will be allocated and
+ * the data requested filled in), and a mask specifying which
+ * data from the AFM file should be saved in the FontInfo structure.
+ *
+ * The file will be parsed and the requested data will be stored in
+ * a record of type FontInfo (refer to ParseAFM.h).
+ *
+ * parseFile returns an error code as defined in parseAFM.h.
+ *
+ * The position of the read/write pointer associated with the file
+ * pointer upon return of this function is undefined.
+ */
+
+int parseFile( const char* pFilename, FontInfo** fi, FLAGS flags)
+{
+ FileInputStream aFile( pFilename );
+
+ int code = ok; /* return code from each of the parsing routines */
+ int error = ok; /* used as the return code from this function */
+ int tokenlen;
+
+ register char *keyword; /* used to store a token */
+
+
+ (*fi) = (FontInfo *) calloc(1, sizeof(FontInfo));
+ if ((*fi) == NULL) {error = storageProblem; return(error);}
+
+ if (flags & P_G)
+ {
+ (*fi)->gfi = (GlobalFontInfo *) calloc(1, sizeof(GlobalFontInfo));
+ if ((*fi)->gfi == NULL) {error = storageProblem; return(error);}
+ }
+
+ /* The AFM file begins with Global Font Information. This section */
+ /* will be parsed whether or not information should be saved. */
+ code = parseGlobals(&aFile, (*fi)->gfi);
+
+ if (code < 0) error = code;
+
+ /* The Global Font Information is followed by the Character Metrics */
+ /* section. Which procedure is used to parse this section depends on */
+ /* how much information should be saved. If all of the metrics info */
+ /* is wanted, parseCharMetrics is called. If only the character widths */
+ /* is wanted, parseCharWidths is called. parseCharWidths will also */
+ /* be called in the case that no character data is to be saved, just */
+ /* to parse through the section. */
+
+ if ((code != normalEOF) && (code != earlyEOF))
+ {
+ (*fi)->numOfChars = atoi(token(&aFile,tokenlen));
+ if (flags & (P_M ^ P_W))
+ {
+ (*fi)->cmi = (CharMetricInfo *)
+ calloc((*fi)->numOfChars, sizeof(CharMetricInfo));
+ if ((*fi)->cmi == NULL) {error = storageProblem; return(error);}
+ code = parseCharMetrics(&aFile, *fi);
+ }
+ else
+ {
+ if (flags & P_W)
+ {
+ (*fi)->cwi = (int *) calloc(256, sizeof(int));
+ if ((*fi)->cwi == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ }
+ /* parse section regardless */
+ code = parseCharWidths(&aFile, (*fi)->cwi);
+ } /* else */
+ } /* if */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ /* The remaining sections of the AFM are optional. This code will */
+ /* look at the next keyword in the file to determine what section */
+ /* is next, and then allocate the appropriate amount of storage */
+ /* for the data (if the data is to be saved) and call the */
+ /* appropriate parsing routine to parse the section. */
+
+ while ((code != normalEOF) && (code != earlyEOF))
+ {
+ keyword = token(&aFile,tokenlen);
+ if (keyword == NULL)
+ /* Have reached an early and unexpected EOF. */
+ /* Set flag and stop parsing */
+ {
+ code = earlyEOF;
+ break; /* get out of loop */
+ }
+ switch(recognize(keyword,tokenlen))
+ {
+ case STARTKERNDATA:
+ break;
+ case ENDKERNDATA:
+ break;
+ case STARTTRACKKERN:
+ keyword = token(&aFile,tokenlen);
+ if (flags & P_T)
+ {
+ (*fi)->numOfTracks = atoi(keyword);
+ (*fi)->tkd = (TrackKernData *)
+ calloc((*fi)->numOfTracks, sizeof(TrackKernData));
+ if ((*fi)->tkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseTrackKernData(&aFile, *fi);
+ break;
+ case STARTKERNPAIRS:
+ keyword = token(&aFile,tokenlen);
+ if (flags & P_P)
+ {
+ (*fi)->numOfPairs = atoi(keyword);
+ (*fi)->pkd = (PairKernData *)
+ calloc((*fi)->numOfPairs, sizeof(PairKernData));
+ if ((*fi)->pkd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parsePairKernData(&aFile, *fi);
+ break;
+ case STARTCOMPOSITES:
+ keyword = token(&aFile,tokenlen);
+ if (flags & P_C)
+ {
+ (*fi)->numOfComps = atoi(keyword);
+ (*fi)->ccd = (CompCharData *)
+ calloc((*fi)->numOfComps, sizeof(CompCharData));
+ if ((*fi)->ccd == NULL)
+ {
+ error = storageProblem;
+ return(error);
+ }
+ } /* if */
+ code = parseCompCharData(&aFile, *fi);
+ break;
+ case ENDFONTMETRICS:
+ code = normalEOF;
+ break;
+ case COMMENT:
+ linetoken(&aFile);
+ break;
+ case NOPE:
+ default:
+ code = parseError;
+ break;
+ } /* switch */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ } /* while */
+
+ if ((error != earlyEOF) && (code < 0)) error = code;
+
+ return(error);
+
+} /* parseFile */
+
+void
+freeFontInfo (FontInfo *fi)
+{
+ int i, j;
+
+ if (fi->gfi)
+ {
+ free (fi->gfi->afmVersion);
+ free (fi->gfi->fontName);
+ free (fi->gfi->fullName);
+ free (fi->gfi->familyName);
+ free (fi->gfi->weight);
+ free (fi->gfi->version);
+ free (fi->gfi->notice);
+ free (fi->gfi->encodingScheme);
+ free (fi->gfi);
+ }
+
+ free (fi->cwi);
+
+ if (fi->cmi)
+ {
+ for (i = 0; i < fi->numOfChars; i++)
+ {
+ Ligature *ligs;
+ free (fi->cmi[i].name);
+ ligs = fi->cmi[i].ligs;
+ while (ligs)
+ {
+ Ligature *tmp;
+ tmp = ligs;
+ ligs = ligs->next;
+ free (tmp->succ);
+ free (tmp->lig);
+ free (tmp);
+ }
+ }
+ free (fi->cmi);
+ }
+
+ free (fi->tkd);
+
+ if (fi->pkd)
+ {
+ for ( i = 0; i < fi->numOfPairs; i++)
+ {
+ free (fi->pkd[i].name1);
+ free (fi->pkd[i].name2);
+ }
+ free (fi->pkd);
+ }
+
+ if (fi->ccd)
+ {
+ for (i = 0; i < fi->numOfComps; i++)
+ {
+ free (fi->ccd[i].ccName);
+ for (j = 0; j < fi->ccd[i].numOfPieces; j++)
+ free (fi->ccd[i].pieces[j].pccName);
+
+ free (fi->ccd[i].pieces);
+ }
+ free (fi->ccd);
+ }
+
+ free (fi);
+}
+
+} // namspace
diff --git a/vcl/unx/source/fontmanager/parseAFM.hxx b/vcl/unx/source/fontmanager/parseAFM.hxx
new file mode 100644
index 000000000000..ad0c32e4b51b
--- /dev/null
+++ b/vcl/unx/source/fontmanager/parseAFM.hxx
@@ -0,0 +1,344 @@
+/*
+ * (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved.
+ *
+ * This file may be freely copied and redistributed as long as:
+ * 1) This entire notice continues to be included in the file,
+ * 2) If the file has been modified in any way, a notice of such
+ * modification is conspicuously indicated.
+ *
+ * PostScript, Display PostScript, and Adobe are registered trademarks of
+ * Adobe Systems Incorporated.
+ *
+ * ************************************************************************
+ * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
+ * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
+ * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
+ * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
+ * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
+ * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * ************************************************************************
+ */
+
+/*
+ * Changes made for OpenOffice.org
+ *
+ * 10/24/2000 pl - changed code to compile with c++-compilers
+ * - added namespace to avoid symbol clashes
+ * - replaced BOOL by bool
+ * - added function to free space allocated by parseFile
+ * 10/26/2000 pl - added additional keys
+ * - added ability to parse slightly broken files
+ * - added charwidth member to GlobalFontInfo
+ * 04/26/2001 pl - added OpenOffice header
+ * 10/19/2005 pl - changed parseFile to accept a file name instead of a stream
+ */
+
+/*************************************************************************
+ *
+ * $RCSfile: parseAFM.hxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: hr $ $Date: 2005-12-28 17:08:50 $
+ *
+ ************************************************************************/
+
+/* ParseAFM.h
+ *
+ * This header file is used in conjuction with the parseAFM.c file.
+ * Together these files provide the functionality to parse Adobe Font
+ * Metrics files and store the information in predefined data structures.
+ * It is intended to work with an application program that needs font metric
+ * information. The program can be used as is by making a procedure call to
+ * parse an AFM file and have the data stored, or an application developer
+ * may wish to customize the code.
+ *
+ * This header file defines the data structures used as well as the key
+ * strings that are currently recognized by this version of the AFM parser.
+ * This program is based on the document "Adobe Font Metrics Files,
+ * Specification Version 2.0".
+ *
+ * AFM files are separated into distinct sections of different data. Because
+ * of this, the parseAFM program can parse a specified file to only save
+ * certain sections of information based on the application's needs. A record
+ * containing the requested information will be returned to the application.
+ *
+ * AFM files are divided into five sections of data:
+ * 1) The Global Font Information
+ * 2) The Character Metrics Information
+ * 3) The Track Kerning Data
+ * 4) The Pair-Wise Kerning Data
+ * 5) The Composite Character Data
+ *
+ * Basically, the application can request any of these sections independent
+ * of what other sections are requested. In addition, in recognizing that
+ * many applications will want ONLY the x-width of characters and not all
+ * of the other character metrics information, there is a way to receive
+ * only the width information so as not to pay the storage cost for the
+ * unwanted data. An application should never request both the
+ * "quick and dirty" char metrics (widths only) and the Character Metrics
+ * Information since the Character Metrics Information will contain all
+ * of the character widths as well.
+ *
+ * There is a procedure in parseAFM.c, called parseFile, that can be
+ * called from any application wishing to get information from the AFM File.
+ * This procedure expects 3 parameters: a vaild file descriptor, a pointer
+ * to a (FontInfo *) variable (for which space will be allocated and then
+ * will be filled in with the data requested), and a mask specifying
+ * which data from the AFM File should be saved in the FontInfo structure.
+ *
+ * The flags that can be used to set the appropriate mask are defined below.
+ * In addition, several commonly used masks have already been defined.
+ *
+ * History:
+ * original: DSM Thu Oct 20 17:39:59 PDT 1988
+ * modified: DSM Mon Jul 3 14:17:50 PDT 1989
+ * - added 'storageProblem' return code
+ * - fixed typos
+ */
+
+#include <stdio.h>
+
+namespace psp {
+
+/* your basic constants */
+#define EOL '\n' /* end-of-line indicator */
+#define MAX_NAME 4096 /* max length for identifiers */
+#define FLAGS int
+
+
+
+/* Flags that can be AND'ed together to specify exactly what
+ * information from the AFM file should be saved.
+ */
+#define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
+#define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
+#define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
+#define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
+#define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
+#define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
+
+
+/* Commonly used flags
+ */
+#define P_GW (P_G | P_W)
+#define P_GM (P_G | P_M)
+#define P_GMP (P_G | P_M | P_P)
+#define P_GMK (P_G | P_M | P_P | P_T)
+#define P_ALL (P_G | P_M | P_P | P_T | P_C)
+
+
+
+/* Possible return codes from the parseFile procedure.
+ *
+ * ok means there were no problems parsing the file.
+ *
+ * parseError means that there was some kind of parsing error, but the
+ * parser went on. This could include problems like the count for any given
+ * section does not add up to how many entries there actually were, or
+ * there was a key that was not recognized. The return record may contain
+ * vaild data or it may not.
+ *
+ * earlyEOF means that an End of File was encountered before expected. This
+ * may mean that the AFM file had been truncated, or improperly formed.
+ *
+ * storageProblem means that there were problems allocating storage for
+ * the data structures that would have contained the AFM data.
+ */
+
+enum afmError { ok = 0, parseError = -1, earlyEOF = -2, storageProblem = -3 };
+
+
+/************************* TYPES *********************************/
+/* Below are all of the data structure definitions. These structures
+ * try to map as closely as possible to grouping and naming of data
+ * in the AFM Files.
+ */
+
+
+/* Bounding box definition. Used for the Font BBox as well as the
+ * Character BBox.
+ */
+typedef struct
+{
+ int llx; /* lower left x-position */
+ int lly; /* lower left y-position */
+ int urx; /* upper right x-position */
+ int ury; /* upper right y-position */
+} BBox;
+
+
+/* Global Font information.
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the AFM
+ * documentation (full title & version given above).
+ */
+typedef struct
+{
+ char *afmVersion; /* key: StartFontMetrics */
+ char *fontName; /* key: FontName */
+ char *fullName; /* key: FullName */
+ char *familyName; /* key: FamilyName */
+ char *weight; /* key: Weight */
+ float italicAngle; /* key: ItalicAngle */
+ bool isFixedPitch; /* key: IsFixedPitch */
+ BBox fontBBox; /* key: FontBBox */
+ int underlinePosition; /* key: UnderlinePosition */
+ int underlineThickness; /* key: UnderlineThickness */
+ char *version; /* key: Version */
+ char *notice; /* key: Notice */
+ char *encodingScheme; /* key: EncodingScheme */
+ int capHeight; /* key: CapHeight */
+ int xHeight; /* key: XHeight */
+ int ascender; /* key: Ascender */
+ int descender; /* key: Descender */
+ int charwidth; /* key: CharWidth */
+} GlobalFontInfo;
+
+
+/* Ligature definition is a linked list since any character can have
+ * any number of ligatures.
+ */
+typedef struct _t_ligature
+{
+ char *succ, *lig;
+ struct _t_ligature *next;
+} Ligature;
+
+
+/* Character Metric Information. This structure is used only if ALL
+ * character metric information is requested. If only the character
+ * widths is requested, then only an array of the character x-widths
+ * is returned.
+ *
+ * The key that each field is associated with is in comments. For an
+ * explanation about each key and its value please refer to the
+ * Character Metrics section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int code, /* key: C */
+ wx, /* key: WX */
+ w0x, /* key: W0X */
+ wy; /* together wx and wy are associated with key: W */
+ char *name; /* key: N */
+ BBox charBBox; /* key: B */
+ Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */
+} CharMetricInfo;
+
+
+/* Track kerning data structure.
+ * The fields of this record are the five values associated with every
+ * TrackKern entry.
+ *
+ * For an explanation about each value please refer to the
+ * Track Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ int degree;
+ float minPtSize,
+ minKernAmt,
+ maxPtSize,
+ maxKernAmt;
+} TrackKernData;
+
+
+/* Pair Kerning data structure.
+ * The fields of this record are the four values associated with every
+ * KP entry. For KPX entries, the yamt will be zero.
+ *
+ * For an explanation about each value please refer to the
+ * Pair Kerning section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *name1;
+ char *name2;
+ int xamt,
+ yamt;
+} PairKernData;
+
+
+/* PCC is a piece of a composite character. This is a sub structure of a
+ * compCharData described below.
+ * These fields will be filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *pccName;
+ int deltax,
+ deltay;
+} Pcc;
+
+
+/* Composite Character Information data structure.
+ * The fields ccName and numOfPieces are filled with the values associated
+ * with the key CC. The field pieces points to an array (size = numOfPieces)
+ * of information about each of the parts of the composite character. That
+ * array is filled in with the values from the key PCC.
+ *
+ * For an explanation about each key and its value please refer to the
+ * Composite Character section of the AFM documentation (full title
+ * & version given above).
+ */
+typedef struct
+{
+ char *ccName;
+ int numOfPieces;
+ Pcc *pieces;
+} CompCharData;
+
+
+/* FontInfo
+ * Record type containing pointers to all of the other data
+ * structures containing information about a font.
+ * A a record of this type is filled with data by the
+ * parseFile function.
+ */
+typedef struct
+{
+ GlobalFontInfo *gfi; /* ptr to a GlobalFontInfo record */
+ int *cwi; /* ptr to 256 element array of just char widths */
+ int numOfChars; /* number of entries in char metrics array */
+ CharMetricInfo *cmi; /* ptr to char metrics array */
+ int numOfTracks; /* number to entries in track kerning array */
+ TrackKernData *tkd; /* ptr to track kerning array */
+ int numOfPairs; /* number to entries in pair kerning array */
+ PairKernData *pkd; /* ptr to pair kerning array */
+ int numOfComps; /* number to entries in comp char array */
+ CompCharData *ccd; /* ptr to comp char array */
+} FontInfo;
+
+
+
+/************************* PROCEDURES ****************************/
+
+/* Call this procedure to do the grunt work of parsing an AFM file.
+ *
+ * "fp" should be a valid file pointer to an AFM file.
+ *
+ * "fi" is a pointer to a pointer to a FontInfo record sturcture
+ * (defined above). Storage for the FontInfo structure will be
+ * allocated in parseFile and the structure will be filled in
+ * with the requested data from the AFM File.
+ *
+ * "flags" is a mask with bits set representing what data should
+ * be saved. Defined above are valid flags that can be used to set
+ * the mask, as well as a few commonly used masks.
+ *
+ * The possible return codes from parseFile are defined above.
+ */
+
+int parseFile( const char* pFilename, FontInfo **fi, FLAGS flags );
+void freeFontInfo(FontInfo *fi);
+
+} // namespace