diff options
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqpsprinter.cpp')
| -rw-r--r-- | tqtinterface/qt4/src/kernel/tqpsprinter.cpp | 6595 | 
1 files changed, 6595 insertions, 0 deletions
| diff --git a/tqtinterface/qt4/src/kernel/tqpsprinter.cpp b/tqtinterface/qt4/src/kernel/tqpsprinter.cpp new file mode 100644 index 0000000..18227cf --- /dev/null +++ b/tqtinterface/qt4/src/kernel/tqpsprinter.cpp @@ -0,0 +1,6595 @@ +/********************************************************************** +** +** Implementation of TQPSPrinter class +** +** Created : 941003 +** +** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file.  Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqplatformdefs.h" + +// POSIX Large File Support redefines open -> open64 +#if defined(open) +# undef open +#endif + +// POSIX Large File Support redefines truncate -> truncate64 +#if defined(truncate) +# undef truncate +#endif + +#include "tqpsprinter_p.h" + +#ifdef USE_QT4 + +static bool qt_gen_epsf = FALSE; + +TQ_EXPORT void qt_generate_epsf( bool b ) +{ +    qt_gen_epsf = b; +} + +#else // USE_QT4 + +#ifndef TQT_NO_PRINTER + +#undef TQ_PRINTER_USE_TYPE42 + +#include "tqpainter.h" +#include "tqapplication.h" +#include "tqpaintdevicemetrics.h" +#include "tqimage.h" +#include "tqdatetime.h" +#include "tqstring.h" +#include "tqdict.h" +#include "tqmemarray.h" +#include "tqfile.h" +#include "tqbuffer.h" +#include "tqintdict.h" +#include "tqtextcodec.h" +#include "tqsettings.h" +#include "tqmap.h" +#include "tqfontdatabase.h" +#include "tqregexp.h" +#include "tqbitmap.h" +#include <private/tqunicodetables_p.h> + +#if defined(TQ_OS_WIN32) +#include <io.h> +#ifdef TQ_PRINTER_USE_TYPE42 +#include <stdlib.h> +#endif +#else +#include <unistd.h> +#include <stdlib.h> +#endif + +#ifdef TQ_WS_X11 +#include "tqt_x11_p.h" +#ifdef None +#undef None +#endif +#ifdef GrayScale +#undef GrayScale +#endif +#endif + +#if defined( TQ_WS_X11 ) || defined (TQ_WS_TQWS) +#include "tqfontdata_p.h" +#include "tqfontengine_p.h" +#include "tqtextlayout_p.h" +#include "tqtextengine_p.h" +extern bool qt_has_xft; +#endif + +static bool qt_gen_epsf = FALSE; +static bool embedFonts = TRUE; + +TQ_EXPORT void qt_generate_epsf( bool b ) +{ +    qt_gen_epsf = b; +} + +static const char *const ps_header = +"/d/def load def/D{bind d}bind d/d2{dup dup}D/B{0 d2}D/W{255 d2}D/ED{exch d}D\n" +"/D0{0 ED}D/LT{lineto}D/MT{moveto}D/S{stroke}D/F{setfont}D/SW{setlinewidth}D\n" +"/CP{closepath}D/RL{rlineto}D/NP{newpath}D/CM{currentmatrix}D/SM{setmatrix}D\n" +"/TR{translate}D/SD{setdash}D/SC{aload pop setrgbcolor}D/CR{currentfile read\n" +"pop}D/i{index}D/bs{bitshift}D/scs{setcolorspace}D/DB{dict dup begin}D/DE{end\n" +"d}D/ie{ifelse}D/sp{astore pop}D/BSt 0 d/LWi 1 d/PSt 1 d/Cx 0 d/Cy 0 d/WFi\n" +"false d/OMo false d/BCol[1 1 1]d/PCol[0 0 0]d/BkCol[1 1 1]d/BDArr[0.94 0.88\n" +"0.63 0.50 0.37 0.12 0.06]d/defM matrix d/nS 0 d/GPS{PSt 1 ge PSt 5 le and{{\n" +"LArr PSt 1 sub 2 mul get}{LArr PSt 2 mul 1 sub get}ie}{[]}ie}D/QS{PSt 0 ne{\n" +"gsave LWi SW true GPS 0 SD S OMo PSt 1 ne and{BkCol SC false GPS dup 0 get\n" +"SD S}if grestore}if}D/r28{{CR dup 32 gt{exit}if pop}loop 3{CR}repeat 0 4{7\n" +"bs exch dup 128 gt{84 sub}if 42 sub 127 and add}repeat}D/rA 0 d/rL 0 d/rB{rL\n" +"0 eq{/rA r28 d/rL 28 d}if dup rL gt{rA exch rL sub rL exch/rA 0 d/rL 0 d rB\n" +"exch bs add}{dup rA 16#fffffff 3 -1 roll bs not and exch dup rL exch sub/rL\n" +"ED neg rA exch bs/rA ED}ie}D/uc{/rL 0 d 0{dup 2 i length ge{exit}if 1 rB 1\n" +"eq{3 rB dup 3 ge{1 add dup rB 1 i 5 ge{1 i 6 ge{1 i 7 ge{1 i 8 ge{128 add}if\n" +"64 add}if 32 add}if 16 add}if 3 add exch pop}if 3 add exch 10 rB 1 add{dup 3\n" +"i lt{dup}{2 i}ie 4 i 3 i 3 i sub 2 i getinterval 5 i 4 i 3 -1 roll\n" +"putinterval dup 4 -1 roll add 3 1 roll 4 -1 roll exch sub dup 0 eq{exit}if 3\n" +"1 roll}loop pop pop}{3 rB 1 add{2 copy 8 rB put 1 add}repeat}ie}loop pop}D\n" +"/sl D0/TQCIgray D0/TQCIcolor D0/TQCIindex D0/TQCI{/colorimage where{pop false 3\n" +"colorimage}{exec/TQCIcolor ED/TQCIgray TQCIcolor length 3 idiv string d 0 1\n" +"TQCIcolor length 3 idiv 1 sub{/TQCIindex ED/x TQCIindex 3 mul d TQCIgray\n" +"TQCIindex TQCIcolor x get 0.30 mul TQCIcolor x 1 add get 0.59 mul TQCIcolor x 2\n" +"add get 0.11 mul add add cvi put}for TQCIgray image}ie}D/di{gsave TR 1 i 1 eq\n" +"{false eq{pop true 3 1 roll 4 i 4 i false 4 i 4 i imagetqmask BkCol SC\n" +"imagetqmask}{pop false 3 1 roll imagetqmask}ie}{dup false ne{/languagelevel\n" +"where{pop languagelevel 3 ge}{false}ie}{false}ie{/ma ED 8 eq{/dc[0 1]d\n" +"/DeviceGray}{/dc[0 1 0 1 0 1]d/DeviceRGB}ie scs/im ED/mt ED/h ED/w ED/id 7\n" +"DB/ImageType 1 d/Width w d/Height h d/ImageMatrix mt d/DataSource im d\n" +"/BitsPerComponent 8 d/Decode dc d DE/md 7 DB/ImageType 1 d/Width w d/Height\n" +"h d/ImageMatrix mt d/DataSource ma d/BitsPerComponent 1 d/Decode[0 1]d DE 4\n" +"DB/ImageType 3 d/DataDict id d/MaskDict md d/InterleaveType 3 d end image}{\n" +"pop 8 4 1 roll 8 eq{image}{TQCI}ie}ie}ie grestore}d/BF{gsave BSt 1 eq{BCol SC\n" +"WFi{fill}{eofill}ie}if BSt 2 ge BSt 8 le and{BDArr BSt 2 sub get/sc ED BCol{\n" +"1. exch sub sc mul 1. exch sub}forall 3 array astore SC WFi{fill}{eofill}ie}\n" +"if BSt 9 ge BSt 14 le and{WFi{clip}{eoclip}ie defM SM pathbbox 3 i 3 i TR 4\n" +"2 roll 3 2 roll exch sub/h ED sub/w ED OMo{NP 0 0 MT 0 h RL w 0 RL 0 h neg\n" +"RL CP BkCol SC fill}if BCol SC 0.3 SW NP BSt 9 eq BSt 11 eq or{0 4 h{dup 0\n" +"exch MT w exch LT}for}if BSt 10 eq BSt 11 eq or{0 4 w{dup 0 MT h LT}for}if\n" +"BSt 12 eq BSt 14 eq or{w h gt{0 6 w h add{dup 0 MT h sub h LT}for}{0 6 w h\n" +"add{dup 0 exch MT w sub w exch LT}for}ie}if BSt 13 eq BSt 14 eq or{w h gt{0\n" +"6 w h add{dup h MT h sub 0 LT}for}{0 6 w h add{dup w exch MT w sub 0 exch LT\n" +"}for}ie}if S}if BSt 24 eq{}if grestore}D/mat matrix d/ang1 D0/ang2 D0/w D0/h\n" +"D0/x D0/y D0/ARC{/ang2 ED/ang1 ED/h ED/w ED/y ED/x ED mat CM pop x w 2 div\n" +"add y h 2 div add TR 1 h w div neg scale ang2 0 ge{0 0 w 2 div ang1 ang1\n" +"ang2 add arc}{0 0 w 2 div ang1 ang1 ang2 add arcn}ie mat SM}D/C D0/P{NP MT\n" +"0.5 0.5 rmoveto 0 -1 RL -1 0 RL 0 1 RL CP fill}D/M{/Cy ED/Cx ED}D/L{NP Cx Cy\n" +"MT/Cy ED/Cx ED Cx Cy LT QS}D/DL{NP MT LT QS}D/HL{1 i DL}D/VL{2 i exch DL}D/R\n" +"{/h ED/w ED/y ED/x ED NP x y MT 0 h RL w 0 RL 0 h neg RL CP BF QS}D/ACR{/h\n" +"ED/w ED/y ED/x ED x y MT 0 h RL w 0 RL 0 h neg RL CP}D/xr D0/yr D0/rx D0/ry\n" +"D0/rx2 D0/ry2 D0/RR{/yr ED/xr ED/h ED/w ED/y ED/x ED xr 0 le yr 0 le or{x y\n" +"w h R}{xr 100 ge yr 100 ge or{x y w h E}{/rx xr w mul 200 div d/ry yr h mul\n" +"200 div d/rx2 rx 2 mul d/ry2 ry 2 mul d NP x rx add y MT x y rx2 ry2 180 -90\n" +"x y h add ry2 sub rx2 ry2 270 -90 x w add rx2 sub y h add ry2 sub rx2 ry2 0\n" +"-90 x w add rx2 sub y rx2 ry2 90 -90 ARC ARC ARC ARC CP BF QS}ie}ie}D/E{/h\n" +"ED/w ED/y ED/x ED mat CM pop x w 2 div add y h 2 div add TR 1 h w div scale\n" +"NP 0 0 w 2 div 0 360 arc mat SM BF QS}D/A{16 div exch 16 div exch NP ARC QS}\n" +"D/PIE{/ang2 ED/ang1 ED/h ED/w ED/y ED/x ED NP x w 2 div add y h 2 div add MT\n" +"x y w h ang1 16 div ang2 16 div ARC CP BF QS}D/CH{16 div exch 16 div exch NP\n" +"ARC CP BF QS}D/BZ{curveto QS}D/CRGB{255 div 3 1 roll 255 div 3 1 roll 255\n" +"div 3 1 roll}D/BC{CRGB BkCol sp}D/BR{CRGB BCol sp/BSt ED}D/WB{1 W BR}D/NB{0\n" +"B BR}D/PE{setlinejoin setlinecap CRGB PCol sp/LWi ED/PSt ED LWi 0 eq{0.25\n" +"/LWi ED}if PCol SC}D/P1{1 0 5 2 roll 0 0 PE}D/ST{defM SM concat}D/MF{true\n" +"exch true exch{exch pop exch pop dup 0 get dup tqfindfont dup/FontName get 3\n" +"-1 roll eq{exit}if}forall exch dup 1 get/fxscale ED 2 get/fslant ED exch\n" +"/fencoding ED[fxscale 0 fslant 1 0 0]makefont fencoding false eq{}{dup\n" +"maxlength dict begin{1 i/FID ne{def}{pop pop}ifelse}forall/Encoding\n" +"fencoding d currentdict end}ie definefont pop}D/MFEmb{tqfindfont dup length\n" +"dict begin{1 i/FID ne{d}{pop pop}ifelse}forall/Encoding ED currentdict end\n" +"definefont pop}D/DF{tqfindfont/fs 3 -1 roll d[fs 0 0 fs -1 mul 0 0]makefont d}\n" +"D/ty 0 d/Y{/ty ED}D/Tl{gsave SW NP 1 i exch MT 1 i 0 RL S grestore}D/XYT{ty\n" +"MT/xyshow where{pop pop xyshow}{exch pop 1 i dup length 2 div exch\n" +"stringwidth pop 3 -1 roll exch sub exch div exch 0 exch ashow}ie}D/AT{ty MT\n" +"1 i dup length 2 div exch stringwidth pop 3 -1 roll exch sub exch div exch 0\n" +"exch ashow}D/QI{/C save d pageinit/Cx 0 d/Cy 0 d/OMo false d}D/QP{C restore\n" +"showpage}D/SPD{/setpagetqdevice where{1 DB 3 1 roll d end setpagetqdevice}{pop\n" +"pop}ie}D/SV{BSt LWi PSt Cx Cy WFi OMo BCol PCol BkCol/nS nS 1 add d gsave}D\n" +"/RS{nS 0 gt{grestore/BkCol ED/PCol ED/BCol ED/OMo ED/WFi ED/Cy ED/Cx ED/PSt\n" +"ED/LWi ED/BSt ED/nS nS 1 sub d}if}D/CLSTART{/clipTmp matrix CM d defM SM NP}\n" +"D/CLEND{clip NP clipTmp SM}D/CLO{grestore gsave defM SM}D\n"; + +// the next table is derived from a list provided by Adobe on its web +// server: http://partners.adobe.com/asn/developer/typeforum/glyphlist.txt + +// the start of the header comment: +// +// Name:          Adobe Glyph List +// Table version: 1.2 +// Date:          22 Oct 1998 +// +// Description: +// +//   The Adobe Glyph List (AGL) list relates Unicode values (UVs) to glyph +//   names, and should be used only as described in the document "Unicode and +//   Glyph Names," at +//   http://partners.adobe.com:80/asn/developer/type/tqunicodegn.html +// +// IMPORTANT NOTE: +// the list tqcontains glyphs in the private use area of tqunicode. These should get removed when regenerating the glyphlist. +// also 0 shout be mapped to .notdef +static const struct { +    TQ_UINT16 u; +    const char * g; +} tqunicodetoglyph[] = { +    // grep '^[0-9A-F][0-9A-F][0-9A-F][0-9A-F];' < /tmp/glyphlist.txt | sed -e 's/;/, "/' -e 's-;-" },  // -' -e 's/^/    { 0x/' | sort +    { 0x0000, ".notdef" }, +    { 0x0020, "space" },  // SPACE +    { 0x0021, "exclam" },  // EXCLAMATION MARK +    { 0x0022, "quotedbl" },  // TQUOTATION MARK +    { 0x0023, "numbersign" },  // NUMBER SIGN +    { 0x0024, "dollar" },  // DOLLAR SIGN +    { 0x0025, "percent" },  // PERCENT SIGN +    { 0x0026, "ampersand" },  // AMPERSAND +    { 0x0027, "quotesingle" },  // APOSTROPHE +    { 0x0028, "parenleft" },  // LEFT PARENTHESIS +    { 0x0029, "parenright" },  // RIGHT PARENTHESIS +    { 0x002A, "asterisk" },  // ASTERISK +    { 0x002B, "plus" },  // PLUS SIGN +    { 0x002C, "comma" },  // COMMA +    { 0x002D, "hyphen" },  // HYPHEN-MINUS +    { 0x002E, "period" },  // FULL STOP +    { 0x002F, "slash" },  // SOLIDUS +    { 0x0030, "zero" },  // DIGIT ZERO +    { 0x0031, "one" },  // DIGIT ONE +    { 0x0032, "two" },  // DIGIT TWO +    { 0x0033, "three" },  // DIGIT THREE +    { 0x0034, "four" },  // DIGIT FOUR +    { 0x0035, "five" },  // DIGIT FIVE +    { 0x0036, "six" },  // DIGIT SIX +    { 0x0037, "seven" },  // DIGIT SEVEN +    { 0x0038, "eight" },  // DIGIT EIGHT +    { 0x0039, "nine" },  // DIGIT NINE +    { 0x003A, "colon" },  // COLON +    { 0x003B, "semicolon" },  // SEMICOLON +    { 0x003C, "less" },  // LESS-THAN SIGN +    { 0x003D, "equal" },  // ETQUALS SIGN +    { 0x003E, "greater" },  // GREATER-THAN SIGN +    { 0x003F, "question" },  // TQUESTION MARK +    { 0x0040, "at" },  // COMMERCIAL AT +    { 0x0041, "A" },  // LATIN CAPITAL LETTER A +    { 0x0042, "B" },  // LATIN CAPITAL LETTER B +    { 0x0043, "C" },  // LATIN CAPITAL LETTER C +    { 0x0044, "D" },  // LATIN CAPITAL LETTER D +    { 0x0045, "E" },  // LATIN CAPITAL LETTER E +    { 0x0046, "F" },  // LATIN CAPITAL LETTER F +    { 0x0047, "G" },  // LATIN CAPITAL LETTER G +    { 0x0048, "H" },  // LATIN CAPITAL LETTER H +    { 0x0049, "I" },  // LATIN CAPITAL LETTER I +    { 0x004A, "J" },  // LATIN CAPITAL LETTER J +    { 0x004B, "K" },  // LATIN CAPITAL LETTER K +    { 0x004C, "L" },  // LATIN CAPITAL LETTER L +    { 0x004D, "M" },  // LATIN CAPITAL LETTER M +    { 0x004E, "N" },  // LATIN CAPITAL LETTER N +    { 0x004F, "O" },  // LATIN CAPITAL LETTER O +    { 0x0050, "P" },  // LATIN CAPITAL LETTER P +    { 0x0051, "Q" },  // LATIN CAPITAL LETTER Q +    { 0x0052, "R" },  // LATIN CAPITAL LETTER R +    { 0x0053, "S" },  // LATIN CAPITAL LETTER S +    { 0x0054, "T" },  // LATIN CAPITAL LETTER T +    { 0x0055, "U" },  // LATIN CAPITAL LETTER U +    { 0x0056, "V" },  // LATIN CAPITAL LETTER V +    { 0x0057, "W" },  // LATIN CAPITAL LETTER W +    { 0x0058, "X" },  // LATIN CAPITAL LETTER X +    { 0x0059, "Y" },  // LATIN CAPITAL LETTER Y +    { 0x005A, "Z" },  // LATIN CAPITAL LETTER Z +    { 0x005B, "bracketleft" },  // LEFT STQUARE BRACKET +    { 0x005C, "backslash" },  // REVERSE SOLIDUS +    { 0x005D, "bracketright" },  // RIGHT STQUARE BRACKET +    { 0x005E, "asciicircum" },  // CIRCUMFLEX ACCENT +    { 0x005F, "underscore" },  // LOW LINE +    { 0x0060, "grave" },  // GRAVE ACCENT +    { 0x0061, "a" },  // LATIN SMALL LETTER A +    { 0x0062, "b" },  // LATIN SMALL LETTER B +    { 0x0063, "c" },  // LATIN SMALL LETTER C +    { 0x0064, "d" },  // LATIN SMALL LETTER D +    { 0x0065, "e" },  // LATIN SMALL LETTER E +    { 0x0066, "f" },  // LATIN SMALL LETTER F +    { 0x0067, "g" },  // LATIN SMALL LETTER G +    { 0x0068, "h" },  // LATIN SMALL LETTER H +    { 0x0069, "i" },  // LATIN SMALL LETTER I +    { 0x006A, "j" },  // LATIN SMALL LETTER J +    { 0x006B, "k" },  // LATIN SMALL LETTER K +    { 0x006C, "l" },  // LATIN SMALL LETTER L +    { 0x006D, "m" },  // LATIN SMALL LETTER M +    { 0x006E, "n" },  // LATIN SMALL LETTER N +    { 0x006F, "o" },  // LATIN SMALL LETTER O +    { 0x0070, "p" },  // LATIN SMALL LETTER P +    { 0x0071, "q" },  // LATIN SMALL LETTER Q +    { 0x0072, "r" },  // LATIN SMALL LETTER R +    { 0x0073, "s" },  // LATIN SMALL LETTER S +    { 0x0074, "t" },  // LATIN SMALL LETTER T +    { 0x0075, "u" },  // LATIN SMALL LETTER U +    { 0x0076, "v" },  // LATIN SMALL LETTER V +    { 0x0077, "w" },  // LATIN SMALL LETTER W +    { 0x0078, "x" },  // LATIN SMALL LETTER X +    { 0x0079, "y" },  // LATIN SMALL LETTER Y +    { 0x007A, "z" },  // LATIN SMALL LETTER Z +    { 0x007B, "braceleft" },  // LEFT CURLY BRACKET +    { 0x007C, "bar" },  // VERTICAL LINE +    { 0x007D, "braceright" },  // RIGHT CURLY BRACKET +    { 0x007E, "asciitilde" },  // TILDE +    { 0x00A0, "space" },  // NO-BREAK SPACE;Duplicate +    { 0x00A1, "exclamdown" },  // INVERTED EXCLAMATION MARK +    { 0x00A2, "cent" },  // CENT SIGN +    { 0x00A3, "sterling" },  // POUND SIGN +    { 0x00A4, "currency" },  // CURRENCY SIGN +    { 0x00A5, "yen" },  // YEN SIGN +    { 0x00A6, "brokenbar" },  // BROKEN BAR +    { 0x00A7, "section" },  // SECTION SIGN +    { 0x00A8, "dieresis" },  // DIAERESIS +    { 0x00A9, "copyright" },  // COPYRIGHT SIGN +    { 0x00AA, "ordfeminine" },  // FEMININE ORDINAL INDICATOR +    { 0x00AB, "guillemotleft" },  // LEFT-POINTING DOUBLE ANGLE TQUOTATION MARK +    { 0x00AC, "logicalnot" },  // NOT SIGN +    { 0x00AD, "hyphen" },  // SOFT HYPHEN;Duplicate +    { 0x00AE, "registered" },  // REGISTERED SIGN +    { 0x00AF, "macron" },  // MACRON +    { 0x00B0, "degree" },  // DEGREE SIGN +    { 0x00B1, "plusminus" },  // PLUS-MINUS SIGN +    { 0x00B2, "twosuperior" },  // SUPERSCRIPT TWO +    { 0x00B3, "threesuperior" },  // SUPERSCRIPT THREE +    { 0x00B4, "acute" },  // ACUTE ACCENT +    { 0x00B5, "mu" },  // MICRO SIGN +    { 0x00B6, "paragraph" },  // PILCROW SIGN +    { 0x00B7, "periodcentered" },  // MIDDLE DOT +    { 0x00B8, "cedilla" },  // CEDILLA +    { 0x00B9, "onesuperior" },  // SUPERSCRIPT ONE +    { 0x00BA, "ordmasculine" },  // MASCULINE ORDINAL INDICATOR +    { 0x00BB, "guillemotright" }, // RIGHT-POINTING DOUBLE ANGLE TQUOTATION MARK +    { 0x00BC, "onequarter" },  // VULGAR FRACTION ONE TQUARTER +    { 0x00BD, "onehalf" },  // VULGAR FRACTION ONE HALF +    { 0x00BE, "threequarters" },  // VULGAR FRACTION THREE TQUARTERS +    { 0x00BF, "questiondown" },  // INVERTED TQUESTION MARK +    { 0x00C0, "Agrave" },  // LATIN CAPITAL LETTER A WITH GRAVE +    { 0x00C1, "Aacute" },  // LATIN CAPITAL LETTER A WITH ACUTE +    { 0x00C2, "Acircumflex" },  // LATIN CAPITAL LETTER A WITH CIRCUMFLEX +    { 0x00C3, "Atilde" },  // LATIN CAPITAL LETTER A WITH TILDE +    { 0x00C4, "Adieresis" },  // LATIN CAPITAL LETTER A WITH DIAERESIS +    { 0x00C5, "Aring" },  // LATIN CAPITAL LETTER A WITH RING ABOVE +    { 0x00C6, "AE" },  // LATIN CAPITAL LETTER AE +    { 0x00C7, "Ccedilla" },  // LATIN CAPITAL LETTER C WITH CEDILLA +    { 0x00C8, "Egrave" },  // LATIN CAPITAL LETTER E WITH GRAVE +    { 0x00C9, "Eacute" },  // LATIN CAPITAL LETTER E WITH ACUTE +    { 0x00CA, "Ecircumflex" },  // LATIN CAPITAL LETTER E WITH CIRCUMFLEX +    { 0x00CB, "Edieresis" },  // LATIN CAPITAL LETTER E WITH DIAERESIS +    { 0x00CC, "Igrave" },  // LATIN CAPITAL LETTER I WITH GRAVE +    { 0x00CD, "Iacute" },  // LATIN CAPITAL LETTER I WITH ACUTE +    { 0x00CE, "Icircumflex" },  // LATIN CAPITAL LETTER I WITH CIRCUMFLEX +    { 0x00CF, "Idieresis" },  // LATIN CAPITAL LETTER I WITH DIAERESIS +    { 0x00D0, "Eth" },  // LATIN CAPITAL LETTER ETH +    { 0x00D1, "Ntilde" },  // LATIN CAPITAL LETTER N WITH TILDE +    { 0x00D2, "Ograve" },  // LATIN CAPITAL LETTER O WITH GRAVE +    { 0x00D3, "Oacute" },  // LATIN CAPITAL LETTER O WITH ACUTE +    { 0x00D4, "Ocircumflex" },  // LATIN CAPITAL LETTER O WITH CIRCUMFLEX +    { 0x00D5, "Otilde" },  // LATIN CAPITAL LETTER O WITH TILDE +    { 0x00D6, "Odieresis" },  // LATIN CAPITAL LETTER O WITH DIAERESIS +    { 0x00D7, "multiply" },  // MULTIPLICATION SIGN +    { 0x00D8, "Oslash" },  // LATIN CAPITAL LETTER O WITH STROKE +    { 0x00D9, "Ugrave" },  // LATIN CAPITAL LETTER U WITH GRAVE +    { 0x00DA, "Uacute" },  // LATIN CAPITAL LETTER U WITH ACUTE +    { 0x00DB, "Ucircumflex" },  // LATIN CAPITAL LETTER U WITH CIRCUMFLEX +    { 0x00DC, "Udieresis" },  // LATIN CAPITAL LETTER U WITH DIAERESIS +    { 0x00DD, "Yacute" },  // LATIN CAPITAL LETTER Y WITH ACUTE +    { 0x00DE, "Thorn" },  // LATIN CAPITAL LETTER THORN +    { 0x00DF, "germandbls" },  // LATIN SMALL LETTER SHARP S +    { 0x00E0, "agrave" },  // LATIN SMALL LETTER A WITH GRAVE +    { 0x00E1, "aacute" },  // LATIN SMALL LETTER A WITH ACUTE +    { 0x00E2, "acircumflex" },  // LATIN SMALL LETTER A WITH CIRCUMFLEX +    { 0x00E3, "atilde" },  // LATIN SMALL LETTER A WITH TILDE +    { 0x00E4, "adieresis" },  // LATIN SMALL LETTER A WITH DIAERESIS +    { 0x00E5, "aring" },  // LATIN SMALL LETTER A WITH RING ABOVE +    { 0x00E6, "ae" },  // LATIN SMALL LETTER AE +    { 0x00E7, "ccedilla" },  // LATIN SMALL LETTER C WITH CEDILLA +    { 0x00E8, "egrave" },  // LATIN SMALL LETTER E WITH GRAVE +    { 0x00E9, "eacute" },  // LATIN SMALL LETTER E WITH ACUTE +    { 0x00EA, "ecircumflex" },  // LATIN SMALL LETTER E WITH CIRCUMFLEX +    { 0x00EB, "edieresis" },  // LATIN SMALL LETTER E WITH DIAERESIS +    { 0x00EC, "igrave" },  // LATIN SMALL LETTER I WITH GRAVE +    { 0x00ED, "iacute" },  // LATIN SMALL LETTER I WITH ACUTE +    { 0x00EE, "icircumflex" },  // LATIN SMALL LETTER I WITH CIRCUMFLEX +    { 0x00EF, "idieresis" },  // LATIN SMALL LETTER I WITH DIAERESIS +    { 0x00F0, "eth" },  // LATIN SMALL LETTER ETH +    { 0x00F1, "ntilde" },  // LATIN SMALL LETTER N WITH TILDE +    { 0x00F2, "ograve" },  // LATIN SMALL LETTER O WITH GRAVE +    { 0x00F3, "oacute" },  // LATIN SMALL LETTER O WITH ACUTE +    { 0x00F4, "ocircumflex" },  // LATIN SMALL LETTER O WITH CIRCUMFLEX +    { 0x00F5, "otilde" },  // LATIN SMALL LETTER O WITH TILDE +    { 0x00F6, "odieresis" },  // LATIN SMALL LETTER O WITH DIAERESIS +    { 0x00F7, "divide" },  // DIVISION SIGN +    { 0x00F8, "oslash" },  // LATIN SMALL LETTER O WITH STROKE +    { 0x00F9, "ugrave" },  // LATIN SMALL LETTER U WITH GRAVE +    { 0x00FA, "uacute" },  // LATIN SMALL LETTER U WITH ACUTE +    { 0x00FB, "ucircumflex" },  // LATIN SMALL LETTER U WITH CIRCUMFLEX +    { 0x00FC, "udieresis" },  // LATIN SMALL LETTER U WITH DIAERESIS +    { 0x00FD, "yacute" },  // LATIN SMALL LETTER Y WITH ACUTE +    { 0x00FE, "thorn" },  // LATIN SMALL LETTER THORN +    { 0x00FF, "ydieresis" },  // LATIN SMALL LETTER Y WITH DIAERESIS +    { 0x0100, "Amacron" },  // LATIN CAPITAL LETTER A WITH MACRON +    { 0x0101, "amacron" },  // LATIN SMALL LETTER A WITH MACRON +    { 0x0102, "Abreve" },  // LATIN CAPITAL LETTER A WITH BREVE +    { 0x0103, "abreve" },  // LATIN SMALL LETTER A WITH BREVE +    { 0x0104, "Aogonek" },  // LATIN CAPITAL LETTER A WITH OGONEK +    { 0x0105, "aogonek" },  // LATIN SMALL LETTER A WITH OGONEK +    { 0x0106, "Cacute" },  // LATIN CAPITAL LETTER C WITH ACUTE +    { 0x0107, "cacute" },  // LATIN SMALL LETTER C WITH ACUTE +    { 0x0108, "Ccircumflex" },  // LATIN CAPITAL LETTER C WITH CIRCUMFLEX +    { 0x0109, "ccircumflex" },  // LATIN SMALL LETTER C WITH CIRCUMFLEX +    { 0x010A, "Cdotaccent" },  // LATIN CAPITAL LETTER C WITH DOT ABOVE +    { 0x010B, "cdotaccent" },  // LATIN SMALL LETTER C WITH DOT ABOVE +    { 0x010C, "Ccaron" },  // LATIN CAPITAL LETTER C WITH CARON +    { 0x010D, "ccaron" },  // LATIN SMALL LETTER C WITH CARON +    { 0x010E, "Dcaron" },  // LATIN CAPITAL LETTER D WITH CARON +    { 0x010F, "dcaron" },  // LATIN SMALL LETTER D WITH CARON +    { 0x0110, "Dcroat" },  // LATIN CAPITAL LETTER D WITH STROKE +    { 0x0111, "dcroat" },  // LATIN SMALL LETTER D WITH STROKE +    { 0x0112, "Emacron" },  // LATIN CAPITAL LETTER E WITH MACRON +    { 0x0113, "emacron" },  // LATIN SMALL LETTER E WITH MACRON +    { 0x0114, "Ebreve" },  // LATIN CAPITAL LETTER E WITH BREVE +    { 0x0115, "ebreve" },  // LATIN SMALL LETTER E WITH BREVE +    { 0x0116, "Edotaccent" },  // LATIN CAPITAL LETTER E WITH DOT ABOVE +    { 0x0117, "edotaccent" },  // LATIN SMALL LETTER E WITH DOT ABOVE +    { 0x0118, "Eogonek" },  // LATIN CAPITAL LETTER E WITH OGONEK +    { 0x0119, "eogonek" },  // LATIN SMALL LETTER E WITH OGONEK +    { 0x011A, "Ecaron" },  // LATIN CAPITAL LETTER E WITH CARON +    { 0x011B, "ecaron" },  // LATIN SMALL LETTER E WITH CARON +    { 0x011C, "Gcircumflex" },  // LATIN CAPITAL LETTER G WITH CIRCUMFLEX +    { 0x011D, "gcircumflex" },  // LATIN SMALL LETTER G WITH CIRCUMFLEX +    { 0x011E, "Gbreve" },  // LATIN CAPITAL LETTER G WITH BREVE +    { 0x011F, "gbreve" },  // LATIN SMALL LETTER G WITH BREVE +    { 0x0120, "Gdotaccent" },  // LATIN CAPITAL LETTER G WITH DOT ABOVE +    { 0x0121, "gdotaccent" },  // LATIN SMALL LETTER G WITH DOT ABOVE +    { 0x0122, "Gcommaaccent" },  // LATIN CAPITAL LETTER G WITH CEDILLA +    { 0x0123, "gcommaaccent" },  // LATIN SMALL LETTER G WITH CEDILLA +    { 0x0124, "Hcircumflex" },  // LATIN CAPITAL LETTER H WITH CIRCUMFLEX +    { 0x0125, "hcircumflex" },  // LATIN SMALL LETTER H WITH CIRCUMFLEX +    { 0x0126, "Hbar" },  // LATIN CAPITAL LETTER H WITH STROKE +    { 0x0127, "hbar" },  // LATIN SMALL LETTER H WITH STROKE +    { 0x0128, "Itilde" },  // LATIN CAPITAL LETTER I WITH TILDE +    { 0x0129, "itilde" },  // LATIN SMALL LETTER I WITH TILDE +    { 0x012A, "Imacron" },  // LATIN CAPITAL LETTER I WITH MACRON +    { 0x012B, "imacron" },  // LATIN SMALL LETTER I WITH MACRON +    { 0x012C, "Ibreve" },  // LATIN CAPITAL LETTER I WITH BREVE +    { 0x012D, "ibreve" },  // LATIN SMALL LETTER I WITH BREVE +    { 0x012E, "Iogonek" },  // LATIN CAPITAL LETTER I WITH OGONEK +    { 0x012F, "iogonek" },  // LATIN SMALL LETTER I WITH OGONEK +    { 0x0130, "Idotaccent" },  // LATIN CAPITAL LETTER I WITH DOT ABOVE +    { 0x0131, "dotlessi" },  // LATIN SMALL LETTER DOTLESS I +    { 0x0132, "IJ" },  // LATIN CAPITAL LIGATURE IJ +    { 0x0133, "ij" },  // LATIN SMALL LIGATURE IJ +    { 0x0134, "Jcircumflex" },  // LATIN CAPITAL LETTER J WITH CIRCUMFLEX +    { 0x0135, "jcircumflex" },  // LATIN SMALL LETTER J WITH CIRCUMFLEX +    { 0x0136, "Kcommaaccent" },  // LATIN CAPITAL LETTER K WITH CEDILLA +    { 0x0137, "kcommaaccent" },  // LATIN SMALL LETTER K WITH CEDILLA +    { 0x0138, "kgreenlandic" },  // LATIN SMALL LETTER KRA +    { 0x0139, "Lacute" },  // LATIN CAPITAL LETTER L WITH ACUTE +    { 0x013A, "lacute" },  // LATIN SMALL LETTER L WITH ACUTE +    { 0x013B, "Lcommaaccent" },  // LATIN CAPITAL LETTER L WITH CEDILLA +    { 0x013C, "lcommaaccent" },  // LATIN SMALL LETTER L WITH CEDILLA +    { 0x013D, "Lcaron" },  // LATIN CAPITAL LETTER L WITH CARON +    { 0x013E, "lcaron" },  // LATIN SMALL LETTER L WITH CARON +    { 0x013F, "Ldot" },  // LATIN CAPITAL LETTER L WITH MIDDLE DOT +    { 0x0140, "ldot" },  // LATIN SMALL LETTER L WITH MIDDLE DOT +    { 0x0141, "Lslash" },  // LATIN CAPITAL LETTER L WITH STROKE +    { 0x0142, "lslash" },  // LATIN SMALL LETTER L WITH STROKE +    { 0x0143, "Nacute" },  // LATIN CAPITAL LETTER N WITH ACUTE +    { 0x0144, "nacute" },  // LATIN SMALL LETTER N WITH ACUTE +    { 0x0145, "Ncommaaccent" },  // LATIN CAPITAL LETTER N WITH CEDILLA +    { 0x0146, "ncommaaccent" },  // LATIN SMALL LETTER N WITH CEDILLA +    { 0x0147, "Ncaron" },  // LATIN CAPITAL LETTER N WITH CARON +    { 0x0148, "ncaron" },  // LATIN SMALL LETTER N WITH CARON +    { 0x0149, "napostrophe" },  // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +    { 0x014A, "Eng" },  // LATIN CAPITAL LETTER ENG +    { 0x014B, "eng" },  // LATIN SMALL LETTER ENG +    { 0x014C, "Omacron" },  // LATIN CAPITAL LETTER O WITH MACRON +    { 0x014D, "omacron" },  // LATIN SMALL LETTER O WITH MACRON +    { 0x014E, "Obreve" },  // LATIN CAPITAL LETTER O WITH BREVE +    { 0x014F, "obreve" },  // LATIN SMALL LETTER O WITH BREVE +    { 0x0150, "Ohungarumlaut" },  // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +    { 0x0151, "ohungarumlaut" },  // LATIN SMALL LETTER O WITH DOUBLE ACUTE +    { 0x0152, "OE" },  // LATIN CAPITAL LIGATURE OE +    { 0x0153, "oe" },  // LATIN SMALL LIGATURE OE +    { 0x0154, "Racute" },  // LATIN CAPITAL LETTER R WITH ACUTE +    { 0x0155, "racute" },  // LATIN SMALL LETTER R WITH ACUTE +    { 0x0156, "Rcommaaccent" },  // LATIN CAPITAL LETTER R WITH CEDILLA +    { 0x0157, "rcommaaccent" },  // LATIN SMALL LETTER R WITH CEDILLA +    { 0x0158, "Rcaron" },  // LATIN CAPITAL LETTER R WITH CARON +    { 0x0159, "rcaron" },  // LATIN SMALL LETTER R WITH CARON +    { 0x015A, "Sacute" },  // LATIN CAPITAL LETTER S WITH ACUTE +    { 0x015B, "sacute" },  // LATIN SMALL LETTER S WITH ACUTE +    { 0x015C, "Scircumflex" },  // LATIN CAPITAL LETTER S WITH CIRCUMFLEX +    { 0x015D, "scircumflex" },  // LATIN SMALL LETTER S WITH CIRCUMFLEX +    { 0x015E, "Scedilla" },  // LATIN CAPITAL LETTER S WITH CEDILLA +    { 0x015F, "scedilla" },  // LATIN SMALL LETTER S WITH CEDILLA +    { 0x0160, "Scaron" },  // LATIN CAPITAL LETTER S WITH CARON +    { 0x0161, "scaron" },  // LATIN SMALL LETTER S WITH CARON +    { 0x0162, "Tcommaaccent" },  // LATIN CAPITAL LETTER T WITH CEDILLA +    { 0x0163, "tcommaaccent" },  // LATIN SMALL LETTER T WITH CEDILLA +    { 0x0164, "Tcaron" },  // LATIN CAPITAL LETTER T WITH CARON +    { 0x0165, "tcaron" },  // LATIN SMALL LETTER T WITH CARON +    { 0x0166, "Tbar" },  // LATIN CAPITAL LETTER T WITH STROKE +    { 0x0167, "tbar" },  // LATIN SMALL LETTER T WITH STROKE +    { 0x0168, "Utilde" },  // LATIN CAPITAL LETTER U WITH TILDE +    { 0x0169, "utilde" },  // LATIN SMALL LETTER U WITH TILDE +    { 0x016A, "Umacron" },  // LATIN CAPITAL LETTER U WITH MACRON +    { 0x016B, "umacron" },  // LATIN SMALL LETTER U WITH MACRON +    { 0x016C, "Ubreve" },  // LATIN CAPITAL LETTER U WITH BREVE +    { 0x016D, "ubreve" },  // LATIN SMALL LETTER U WITH BREVE +    { 0x016E, "Uring" },  // LATIN CAPITAL LETTER U WITH RING ABOVE +    { 0x016F, "uring" },  // LATIN SMALL LETTER U WITH RING ABOVE +    { 0x0170, "Uhungarumlaut" },  // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +    { 0x0171, "uhungarumlaut" },  // LATIN SMALL LETTER U WITH DOUBLE ACUTE +    { 0x0172, "Uogonek" },  // LATIN CAPITAL LETTER U WITH OGONEK +    { 0x0173, "uogonek" },  // LATIN SMALL LETTER U WITH OGONEK +    { 0x0174, "Wcircumflex" },  // LATIN CAPITAL LETTER W WITH CIRCUMFLEX +    { 0x0175, "wcircumflex" },  // LATIN SMALL LETTER W WITH CIRCUMFLEX +    { 0x0176, "Ycircumflex" },  // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +    { 0x0177, "ycircumflex" },  // LATIN SMALL LETTER Y WITH CIRCUMFLEX +    { 0x0178, "Ydieresis" },  // LATIN CAPITAL LETTER Y WITH DIAERESIS +    { 0x0179, "Zacute" },  // LATIN CAPITAL LETTER Z WITH ACUTE +    { 0x017A, "zacute" },  // LATIN SMALL LETTER Z WITH ACUTE +    { 0x017B, "Zdotaccent" },  // LATIN CAPITAL LETTER Z WITH DOT ABOVE +    { 0x017C, "zdotaccent" },  // LATIN SMALL LETTER Z WITH DOT ABOVE +    { 0x017D, "Zcaron" },  // LATIN CAPITAL LETTER Z WITH CARON +    { 0x017E, "zcaron" },  // LATIN SMALL LETTER Z WITH CARON +    { 0x017F, "longs" },  // LATIN SMALL LETTER LONG S +    { 0x0192, "florin" },  // LATIN SMALL LETTER F WITH HOOK +    { 0x01A0, "Ohorn" },  // LATIN CAPITAL LETTER O WITH HORN +    { 0x01A1, "ohorn" },  // LATIN SMALL LETTER O WITH HORN +    { 0x01AF, "Uhorn" },  // LATIN CAPITAL LETTER U WITH HORN +    { 0x01B0, "uhorn" },  // LATIN SMALL LETTER U WITH HORN +    { 0x01E6, "Gcaron" },  // LATIN CAPITAL LETTER G WITH CARON +    { 0x01E7, "gcaron" },  // LATIN SMALL LETTER G WITH CARON +    { 0x01FA, "Aringacute" },  // LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +    { 0x01FB, "aringacute" },  // LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE +    { 0x01FC, "AEacute" },  // LATIN CAPITAL LETTER AE WITH ACUTE +    { 0x01FD, "aeacute" },  // LATIN SMALL LETTER AE WITH ACUTE +    { 0x01FE, "Oslashacute" },  // LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +    { 0x01FF, "oslashacute" },  // LATIN SMALL LETTER O WITH STROKE AND ACUTE +    { 0x0218, "Scommaaccent" },  // LATIN CAPITAL LETTER S WITH COMMA BELOW +    { 0x0219, "scommaaccent" },  // LATIN SMALL LETTER S WITH COMMA BELOW +    { 0x021A, "Tcommaaccent" },  // LATIN CAPITAL LETTER T WITH COMMA BELOW;Duplicate +    { 0x021B, "tcommaaccent" },  // LATIN SMALL LETTER T WITH COMMA BELOW;Duplicate +    { 0x02BC, "afii57929" },  // MODIFIER LETTER APOSTROPHE +    { 0x02BD, "afii64937" },  // MODIFIER LETTER REVERSED COMMA +    { 0x02C6, "circumflex" },  // MODIFIER LETTER CIRCUMFLEX ACCENT +    { 0x02C7, "caron" },  // CARON +    { 0x02C9, "macron" },  // MODIFIER LETTER MACRON;Duplicate +    { 0x02D8, "breve" },  // BREVE +    { 0x02D9, "dotaccent" },  // DOT ABOVE +    { 0x02DA, "ring" },  // RING ABOVE +    { 0x02DB, "ogonek" },  // OGONEK +    { 0x02DC, "tilde" },  // SMALL TILDE +    { 0x02DD, "hungarumlaut" },  // DOUBLE ACUTE ACCENT +    { 0x0300, "gravecomb" },  // COMBINING GRAVE ACCENT +    { 0x0301, "acutecomb" },  // COMBINING ACUTE ACCENT +    { 0x0303, "tildecomb" },  // COMBINING TILDE +    { 0x0309, "hookabovecomb" },  // COMBINING HOOK ABOVE +    { 0x0323, "dotbelowcomb" },  // COMBINING DOT BELOW +    { 0x0384, "tonos" },  // GREEK TONOS +    { 0x0385, "dieresistonos" },  // GREEK DIALYTIKA TONOS +    { 0x0386, "Alphatonos" },  // GREEK CAPITAL LETTER ALPHA WITH TONOS +    { 0x0387, "anoteleia" },  // GREEK ANO TELEIA +    { 0x0388, "Epsilontonos" },  // GREEK CAPITAL LETTER EPSILON WITH TONOS +    { 0x0389, "Etatonos" },  // GREEK CAPITAL LETTER ETA WITH TONOS +    { 0x038A, "Iotatonos" },  // GREEK CAPITAL LETTER IOTA WITH TONOS +    { 0x038C, "Omicrontonos" },  // GREEK CAPITAL LETTER OMICRON WITH TONOS +    { 0x038E, "Upsilontonos" },  // GREEK CAPITAL LETTER UPSILON WITH TONOS +    { 0x038F, "Omegatonos" },  // GREEK CAPITAL LETTER OMEGA WITH TONOS +    { 0x0390, "iotadieresistonos" },  // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +    { 0x0391, "Alpha" },  // GREEK CAPITAL LETTER ALPHA +    { 0x0392, "Beta" },  // GREEK CAPITAL LETTER BETA +    { 0x0393, "Gamma" },  // GREEK CAPITAL LETTER GAMMA +    { 0x0394, "Delta" },  // GREEK CAPITAL LETTER DELTA;Duplicate +    { 0x0395, "Epsilon" },  // GREEK CAPITAL LETTER EPSILON +    { 0x0396, "Zeta" },  // GREEK CAPITAL LETTER ZETA +    { 0x0397, "Eta" },  // GREEK CAPITAL LETTER ETA +    { 0x0398, "Theta" },  // GREEK CAPITAL LETTER THETA +    { 0x0399, "Iota" },  // GREEK CAPITAL LETTER IOTA +    { 0x039A, "Kappa" },  // GREEK CAPITAL LETTER KAPPA +    { 0x039B, "Lambda" },  // GREEK CAPITAL LETTER LAMDA +    { 0x039C, "Mu" },  // GREEK CAPITAL LETTER MU +    { 0x039D, "Nu" },  // GREEK CAPITAL LETTER NU +    { 0x039E, "Xi" },  // GREEK CAPITAL LETTER XI +    { 0x039F, "Omicron" },  // GREEK CAPITAL LETTER OMICRON +    { 0x03A0, "Pi" },  // GREEK CAPITAL LETTER PI +    { 0x03A1, "Rho" },  // GREEK CAPITAL LETTER RHO +    { 0x03A3, "Sigma" },  // GREEK CAPITAL LETTER SIGMA +    { 0x03A4, "Tau" },  // GREEK CAPITAL LETTER TAU +    { 0x03A5, "Upsilon" },  // GREEK CAPITAL LETTER UPSILON +    { 0x03A6, "Phi" },  // GREEK CAPITAL LETTER PHI +    { 0x03A7, "Chi" },  // GREEK CAPITAL LETTER CHI +    { 0x03A8, "Psi" },  // GREEK CAPITAL LETTER PSI +    { 0x03A9, "Omega" },  // GREEK CAPITAL LETTER OMEGA;Duplicate +    { 0x03AA, "Iotadieresis" },  // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +    { 0x03AB, "Upsilondieresis" },  // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +    { 0x03AC, "alphatonos" },  // GREEK SMALL LETTER ALPHA WITH TONOS +    { 0x03AD, "epsilontonos" },  // GREEK SMALL LETTER EPSILON WITH TONOS +    { 0x03AE, "etatonos" },  // GREEK SMALL LETTER ETA WITH TONOS +    { 0x03AF, "iotatonos" },  // GREEK SMALL LETTER IOTA WITH TONOS +    { 0x03B0, "upsilondieresistonos" },  // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +    { 0x03B1, "alpha" },  // GREEK SMALL LETTER ALPHA +    { 0x03B2, "beta" },  // GREEK SMALL LETTER BETA +    { 0x03B3, "gamma" },  // GREEK SMALL LETTER GAMMA +    { 0x03B4, "delta" },  // GREEK SMALL LETTER DELTA +    { 0x03B5, "epsilon" },  // GREEK SMALL LETTER EPSILON +    { 0x03B6, "zeta" },  // GREEK SMALL LETTER ZETA +    { 0x03B7, "eta" },  // GREEK SMALL LETTER ETA +    { 0x03B8, "theta" },  // GREEK SMALL LETTER THETA +    { 0x03B9, "iota" },  // GREEK SMALL LETTER IOTA +    { 0x03BA, "kappa" },  // GREEK SMALL LETTER KAPPA +    { 0x03BB, "lambda" },  // GREEK SMALL LETTER LAMDA +    { 0x03BC, "mu" },  // GREEK SMALL LETTER MU;Duplicate +    { 0x03BD, "nu" },  // GREEK SMALL LETTER NU +    { 0x03BE, "xi" },  // GREEK SMALL LETTER XI +    { 0x03BF, "omicron" },  // GREEK SMALL LETTER OMICRON +    { 0x03C0, "pi" },  // GREEK SMALL LETTER PI +    { 0x03C1, "rho" },  // GREEK SMALL LETTER RHO +    { 0x03C2, "sigma1" },  // GREEK SMALL LETTER FINAL SIGMA +    { 0x03C3, "sigma" },  // GREEK SMALL LETTER SIGMA +    { 0x03C4, "tau" },  // GREEK SMALL LETTER TAU +    { 0x03C5, "upsilon" },  // GREEK SMALL LETTER UPSILON +    { 0x03C6, "phi" },  // GREEK SMALL LETTER PHI +    { 0x03C7, "chi" },  // GREEK SMALL LETTER CHI +    { 0x03C8, "psi" },  // GREEK SMALL LETTER PSI +    { 0x03C9, "omega" },  // GREEK SMALL LETTER OMEGA +    { 0x03CA, "iotadieresis" },  // GREEK SMALL LETTER IOTA WITH DIALYTIKA +    { 0x03CB, "upsilondieresis" },  // GREEK SMALL LETTER UPSILON WITH DIALYTIKA +    { 0x03CC, "omicrontonos" },  // GREEK SMALL LETTER OMICRON WITH TONOS +    { 0x03CD, "upsilontonos" },  // GREEK SMALL LETTER UPSILON WITH TONOS +    { 0x03CE, "omegatonos" },  // GREEK SMALL LETTER OMEGA WITH TONOS +    { 0x03D1, "theta1" },  // GREEK THETA SYMBOL +    { 0x03D2, "Upsilon1" },  // GREEK UPSILON WITH HOOK SYMBOL +    { 0x03D5, "phi1" },  // GREEK PHI SYMBOL +    { 0x03D6, "omega1" },  // GREEK PI SYMBOL +    { 0x0401, "afii10023" },  // CYRILLIC CAPITAL LETTER IO +    { 0x0402, "afii10051" },  // CYRILLIC CAPITAL LETTER DJE +    { 0x0403, "afii10052" },  // CYRILLIC CAPITAL LETTER GJE +    { 0x0404, "afii10053" },  // CYRILLIC CAPITAL LETTER UKRAINIAN IE +    { 0x0405, "afii10054" },  // CYRILLIC CAPITAL LETTER DZE +    { 0x0406, "afii10055" },  // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +    { 0x0407, "afii10056" },  // CYRILLIC CAPITAL LETTER YI +    { 0x0408, "afii10057" },  // CYRILLIC CAPITAL LETTER JE +    { 0x0409, "afii10058" },  // CYRILLIC CAPITAL LETTER LJE +    { 0x040A, "afii10059" },  // CYRILLIC CAPITAL LETTER NJE +    { 0x040B, "afii10060" },  // CYRILLIC CAPITAL LETTER TSHE +    { 0x040C, "afii10061" },  // CYRILLIC CAPITAL LETTER KJE +    { 0x040E, "afii10062" },  // CYRILLIC CAPITAL LETTER SHORT U +    { 0x040F, "afii10145" },  // CYRILLIC CAPITAL LETTER DZHE +    { 0x0410, "afii10017" },  // CYRILLIC CAPITAL LETTER A +    { 0x0411, "afii10018" },  // CYRILLIC CAPITAL LETTER BE +    { 0x0412, "afii10019" },  // CYRILLIC CAPITAL LETTER VE +    { 0x0413, "afii10020" },  // CYRILLIC CAPITAL LETTER GHE +    { 0x0414, "afii10021" },  // CYRILLIC CAPITAL LETTER DE +    { 0x0415, "afii10022" },  // CYRILLIC CAPITAL LETTER IE +    { 0x0416, "afii10024" },  // CYRILLIC CAPITAL LETTER ZHE +    { 0x0417, "afii10025" },  // CYRILLIC CAPITAL LETTER ZE +    { 0x0418, "afii10026" },  // CYRILLIC CAPITAL LETTER I +    { 0x0419, "afii10027" },  // CYRILLIC CAPITAL LETTER SHORT I +    { 0x041A, "afii10028" },  // CYRILLIC CAPITAL LETTER KA +    { 0x041B, "afii10029" },  // CYRILLIC CAPITAL LETTER EL +    { 0x041C, "afii10030" },  // CYRILLIC CAPITAL LETTER EM +    { 0x041D, "afii10031" },  // CYRILLIC CAPITAL LETTER EN +    { 0x041E, "afii10032" },  // CYRILLIC CAPITAL LETTER O +    { 0x041F, "afii10033" },  // CYRILLIC CAPITAL LETTER PE +    { 0x0420, "afii10034" },  // CYRILLIC CAPITAL LETTER ER +    { 0x0421, "afii10035" },  // CYRILLIC CAPITAL LETTER ES +    { 0x0422, "afii10036" },  // CYRILLIC CAPITAL LETTER TE +    { 0x0423, "afii10037" },  // CYRILLIC CAPITAL LETTER U +    { 0x0424, "afii10038" },  // CYRILLIC CAPITAL LETTER EF +    { 0x0425, "afii10039" },  // CYRILLIC CAPITAL LETTER HA +    { 0x0426, "afii10040" },  // CYRILLIC CAPITAL LETTER TSE +    { 0x0427, "afii10041" },  // CYRILLIC CAPITAL LETTER CHE +    { 0x0428, "afii10042" },  // CYRILLIC CAPITAL LETTER SHA +    { 0x0429, "afii10043" },  // CYRILLIC CAPITAL LETTER SHCHA +    { 0x042A, "afii10044" },  // CYRILLIC CAPITAL LETTER HARD SIGN +    { 0x042B, "afii10045" },  // CYRILLIC CAPITAL LETTER YERU +    { 0x042C, "afii10046" },  // CYRILLIC CAPITAL LETTER SOFT SIGN +    { 0x042D, "afii10047" },  // CYRILLIC CAPITAL LETTER E +    { 0x042E, "afii10048" },  // CYRILLIC CAPITAL LETTER YU +    { 0x042F, "afii10049" },  // CYRILLIC CAPITAL LETTER YA +    { 0x0430, "afii10065" },  // CYRILLIC SMALL LETTER A +    { 0x0431, "afii10066" },  // CYRILLIC SMALL LETTER BE +    { 0x0432, "afii10067" },  // CYRILLIC SMALL LETTER VE +    { 0x0433, "afii10068" },  // CYRILLIC SMALL LETTER GHE +    { 0x0434, "afii10069" },  // CYRILLIC SMALL LETTER DE +    { 0x0435, "afii10070" },  // CYRILLIC SMALL LETTER IE +    { 0x0436, "afii10072" },  // CYRILLIC SMALL LETTER ZHE +    { 0x0437, "afii10073" },  // CYRILLIC SMALL LETTER ZE +    { 0x0438, "afii10074" },  // CYRILLIC SMALL LETTER I +    { 0x0439, "afii10075" },  // CYRILLIC SMALL LETTER SHORT I +    { 0x043A, "afii10076" },  // CYRILLIC SMALL LETTER KA +    { 0x043B, "afii10077" },  // CYRILLIC SMALL LETTER EL +    { 0x043C, "afii10078" },  // CYRILLIC SMALL LETTER EM +    { 0x043D, "afii10079" },  // CYRILLIC SMALL LETTER EN +    { 0x043E, "afii10080" },  // CYRILLIC SMALL LETTER O +    { 0x043F, "afii10081" },  // CYRILLIC SMALL LETTER PE +    { 0x0440, "afii10082" },  // CYRILLIC SMALL LETTER ER +    { 0x0441, "afii10083" },  // CYRILLIC SMALL LETTER ES +    { 0x0442, "afii10084" },  // CYRILLIC SMALL LETTER TE +    { 0x0443, "afii10085" },  // CYRILLIC SMALL LETTER U +    { 0x0444, "afii10086" },  // CYRILLIC SMALL LETTER EF +    { 0x0445, "afii10087" },  // CYRILLIC SMALL LETTER HA +    { 0x0446, "afii10088" },  // CYRILLIC SMALL LETTER TSE +    { 0x0447, "afii10089" },  // CYRILLIC SMALL LETTER CHE +    { 0x0448, "afii10090" },  // CYRILLIC SMALL LETTER SHA +    { 0x0449, "afii10091" },  // CYRILLIC SMALL LETTER SHCHA +    { 0x044A, "afii10092" },  // CYRILLIC SMALL LETTER HARD SIGN +    { 0x044B, "afii10093" },  // CYRILLIC SMALL LETTER YERU +    { 0x044C, "afii10094" },  // CYRILLIC SMALL LETTER SOFT SIGN +    { 0x044D, "afii10095" },  // CYRILLIC SMALL LETTER E +    { 0x044E, "afii10096" },  // CYRILLIC SMALL LETTER YU +    { 0x044F, "afii10097" },  // CYRILLIC SMALL LETTER YA +    { 0x0451, "afii10071" },  // CYRILLIC SMALL LETTER IO +    { 0x0452, "afii10099" },  // CYRILLIC SMALL LETTER DJE +    { 0x0453, "afii10100" },  // CYRILLIC SMALL LETTER GJE +    { 0x0454, "afii10101" },  // CYRILLIC SMALL LETTER UKRAINIAN IE +    { 0x0455, "afii10102" },  // CYRILLIC SMALL LETTER DZE +    { 0x0456, "afii10103" },  // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +    { 0x0457, "afii10104" },  // CYRILLIC SMALL LETTER YI +    { 0x0458, "afii10105" },  // CYRILLIC SMALL LETTER JE +    { 0x0459, "afii10106" },  // CYRILLIC SMALL LETTER LJE +    { 0x045A, "afii10107" },  // CYRILLIC SMALL LETTER NJE +    { 0x045B, "afii10108" },  // CYRILLIC SMALL LETTER TSHE +    { 0x045C, "afii10109" },  // CYRILLIC SMALL LETTER KJE +    { 0x045E, "afii10110" },  // CYRILLIC SMALL LETTER SHORT U +    { 0x045F, "afii10193" },  // CYRILLIC SMALL LETTER DZHE +    { 0x0462, "afii10146" },  // CYRILLIC CAPITAL LETTER YAT +    { 0x0463, "afii10194" },  // CYRILLIC SMALL LETTER YAT +    { 0x0472, "afii10147" },  // CYRILLIC CAPITAL LETTER FITA +    { 0x0473, "afii10195" },  // CYRILLIC SMALL LETTER FITA +    { 0x0474, "afii10148" },  // CYRILLIC CAPITAL LETTER IZHITSA +    { 0x0475, "afii10196" },  // CYRILLIC SMALL LETTER IZHITSA +    { 0x0490, "afii10050" },  // CYRILLIC CAPITAL LETTER GHE WITH UPTURN +    { 0x0491, "afii10098" },  // CYRILLIC SMALL LETTER GHE WITH UPTURN +    { 0x04D9, "afii10846" },  // CYRILLIC SMALL LETTER SCHWA +    { 0x05B0, "afii57799" },  // HEBREW POINT SHEVA +    { 0x05B1, "afii57801" },  // HEBREW POINT HATAF SEGOL +    { 0x05B2, "afii57800" },  // HEBREW POINT HATAF PATAH +    { 0x05B3, "afii57802" },  // HEBREW POINT HATAF TQAMATS +    { 0x05B4, "afii57793" },  // HEBREW POINT HIRIQ +    { 0x05B5, "afii57794" },  // HEBREW POINT TSERE +    { 0x05B6, "afii57795" },  // HEBREW POINT SEGOL +    { 0x05B7, "afii57798" },  // HEBREW POINT PATAH +    { 0x05B8, "afii57797" },  // HEBREW POINT TQAMATS +    { 0x05B9, "afii57806" },  // HEBREW POINT HOLAM +    { 0x05BB, "afii57796" },  // HEBREW POINT TQUBUTS +    { 0x05BC, "afii57807" },  // HEBREW POINT DAGESH OR MAPIQ +    { 0x05BD, "afii57839" },  // HEBREW POINT METEG +    { 0x05BE, "afii57645" },  // HEBREW PUNCTUATION MATQAF +    { 0x05BF, "afii57841" },  // HEBREW POINT RAFE +    { 0x05C0, "afii57842" },  // HEBREW PUNCTUATION PASEQ +    { 0x05C1, "afii57804" },  // HEBREW POINT SHIN DOT +    { 0x05C2, "afii57803" },  // HEBREW POINT SIN DOT +    { 0x05C3, "afii57658" },  // HEBREW PUNCTUATION SOF PASUQ +    { 0x05D0, "afii57664" },  // HEBREW LETTER ALEF +    { 0x05D1, "afii57665" },  // HEBREW LETTER BET +    { 0x05D2, "afii57666" },  // HEBREW LETTER GIMEL +    { 0x05D3, "afii57667" },  // HEBREW LETTER DALET +    { 0x05D4, "afii57668" },  // HEBREW LETTER HE +    { 0x05D5, "afii57669" },  // HEBREW LETTER VAV +    { 0x05D6, "afii57670" },  // HEBREW LETTER ZAYIN +    { 0x05D7, "afii57671" },  // HEBREW LETTER HET +    { 0x05D8, "afii57672" },  // HEBREW LETTER TET +    { 0x05D9, "afii57673" },  // HEBREW LETTER YOD +    { 0x05DA, "afii57674" },  // HEBREW LETTER FINAL KAF +    { 0x05DB, "afii57675" },  // HEBREW LETTER KAF +    { 0x05DC, "afii57676" },  // HEBREW LETTER LAMED +    { 0x05DD, "afii57677" },  // HEBREW LETTER FINAL MEM +    { 0x05DE, "afii57678" },  // HEBREW LETTER MEM +    { 0x05DF, "afii57679" },  // HEBREW LETTER FINAL NUN +    { 0x05E0, "afii57680" },  // HEBREW LETTER NUN +    { 0x05E1, "afii57681" },  // HEBREW LETTER SAMEKH +    { 0x05E2, "afii57682" },  // HEBREW LETTER AYIN +    { 0x05E3, "afii57683" },  // HEBREW LETTER FINAL PE +    { 0x05E4, "afii57684" },  // HEBREW LETTER PE +    { 0x05E5, "afii57685" },  // HEBREW LETTER FINAL TSADI +    { 0x05E6, "afii57686" },  // HEBREW LETTER TSADI +    { 0x05E7, "afii57687" },  // HEBREW LETTER TQOF +    { 0x05E8, "afii57688" },  // HEBREW LETTER RESH +    { 0x05E9, "afii57689" },  // HEBREW LETTER SHIN +    { 0x05EA, "afii57690" },  // HEBREW LETTER TAV +    { 0x05F0, "afii57716" },  // HEBREW LIGATURE YIDDISH DOUBLE VAV +    { 0x05F1, "afii57717" },  // HEBREW LIGATURE YIDDISH VAV YOD +    { 0x05F2, "afii57718" },  // HEBREW LIGATURE YIDDISH DOUBLE YOD +    { 0x060C, "afii57388" },  // ARABIC COMMA +    { 0x061B, "afii57403" },  // ARABIC SEMICOLON +    { 0x061F, "afii57407" },  // ARABIC TQUESTION MARK +    { 0x0621, "afii57409" },  // ARABIC LETTER HAMZA +    { 0x0622, "afii57410" },  // ARABIC LETTER ALEF WITH MADDA ABOVE +    { 0x0623, "afii57411" },  // ARABIC LETTER ALEF WITH HAMZA ABOVE +    { 0x0624, "afii57412" },  // ARABIC LETTER WAW WITH HAMZA ABOVE +    { 0x0625, "afii57413" },  // ARABIC LETTER ALEF WITH HAMZA BELOW +    { 0x0626, "afii57414" },  // ARABIC LETTER YEH WITH HAMZA ABOVE +    { 0x0627, "afii57415" },  // ARABIC LETTER ALEF +    { 0x0628, "afii57416" },  // ARABIC LETTER BEH +    { 0x0629, "afii57417" },  // ARABIC LETTER TEH MARBUTA +    { 0x062A, "afii57418" },  // ARABIC LETTER TEH +    { 0x062B, "afii57419" },  // ARABIC LETTER THEH +    { 0x062C, "afii57420" },  // ARABIC LETTER JEEM +    { 0x062D, "afii57421" },  // ARABIC LETTER HAH +    { 0x062E, "afii57422" },  // ARABIC LETTER KHAH +    { 0x062F, "afii57423" },  // ARABIC LETTER DAL +    { 0x0630, "afii57424" },  // ARABIC LETTER THAL +    { 0x0631, "afii57425" },  // ARABIC LETTER REH +    { 0x0632, "afii57426" },  // ARABIC LETTER ZAIN +    { 0x0633, "afii57427" },  // ARABIC LETTER SEEN +    { 0x0634, "afii57428" },  // ARABIC LETTER SHEEN +    { 0x0635, "afii57429" },  // ARABIC LETTER SAD +    { 0x0636, "afii57430" },  // ARABIC LETTER DAD +    { 0x0637, "afii57431" },  // ARABIC LETTER TAH +    { 0x0638, "afii57432" },  // ARABIC LETTER ZAH +    { 0x0639, "afii57433" },  // ARABIC LETTER AIN +    { 0x063A, "afii57434" },  // ARABIC LETTER GHAIN +    { 0x0640, "afii57440" },  // ARABIC TATWEEL +    { 0x0641, "afii57441" },  // ARABIC LETTER FEH +    { 0x0642, "afii57442" },  // ARABIC LETTER TQAF +    { 0x0643, "afii57443" },  // ARABIC LETTER KAF +    { 0x0644, "afii57444" },  // ARABIC LETTER LAM +    { 0x0645, "afii57445" },  // ARABIC LETTER MEEM +    { 0x0646, "afii57446" },  // ARABIC LETTER NOON +    { 0x0647, "afii57470" },  // ARABIC LETTER HEH +    { 0x0648, "afii57448" },  // ARABIC LETTER WAW +    { 0x0649, "afii57449" },  // ARABIC LETTER ALEF MAKSURA +    { 0x064A, "afii57450" },  // ARABIC LETTER YEH +    { 0x064B, "afii57451" },  // ARABIC FATHATAN +    { 0x064C, "afii57452" },  // ARABIC DAMMATAN +    { 0x064D, "afii57453" },  // ARABIC KASRATAN +    { 0x064E, "afii57454" },  // ARABIC FATHA +    { 0x064F, "afii57455" },  // ARABIC DAMMA +    { 0x0650, "afii57456" },  // ARABIC KASRA +    { 0x0651, "afii57457" },  // ARABIC SHADDA +    { 0x0652, "afii57458" },  // ARABIC SUKUN +    { 0x0660, "afii57392" },  // ARABIC-INDIC DIGIT ZERO +    { 0x0661, "afii57393" },  // ARABIC-INDIC DIGIT ONE +    { 0x0662, "afii57394" },  // ARABIC-INDIC DIGIT TWO +    { 0x0663, "afii57395" },  // ARABIC-INDIC DIGIT THREE +    { 0x0664, "afii57396" },  // ARABIC-INDIC DIGIT FOUR +    { 0x0665, "afii57397" },  // ARABIC-INDIC DIGIT FIVE +    { 0x0666, "afii57398" },  // ARABIC-INDIC DIGIT SIX +    { 0x0667, "afii57399" },  // ARABIC-INDIC DIGIT SEVEN +    { 0x0668, "afii57400" },  // ARABIC-INDIC DIGIT EIGHT +    { 0x0669, "afii57401" },  // ARABIC-INDIC DIGIT NINE +    { 0x066A, "afii57381" },  // ARABIC PERCENT SIGN +    { 0x066D, "afii63167" },  // ARABIC FIVE POINTED STAR +    { 0x0679, "afii57511" },  // ARABIC LETTER TTEH +    { 0x067E, "afii57506" },  // ARABIC LETTER PEH +    { 0x0686, "afii57507" },  // ARABIC LETTER TCHEH +    { 0x0688, "afii57512" },  // ARABIC LETTER DDAL +    { 0x0691, "afii57513" },  // ARABIC LETTER RREH +    { 0x0698, "afii57508" },  // ARABIC LETTER JEH +    { 0x06A4, "afii57505" },  // ARABIC LETTER VEH +    { 0x06AF, "afii57509" },  // ARABIC LETTER GAF +    { 0x06BA, "afii57514" },  // ARABIC LETTER NOON GHUNNA +    { 0x06D2, "afii57519" },  // ARABIC LETTER YEH BARREE +    { 0x06D5, "afii57534" },  // ARABIC LETTER AE +    { 0x1E80, "Wgrave" },  // LATIN CAPITAL LETTER W WITH GRAVE +    { 0x1E81, "wgrave" },  // LATIN SMALL LETTER W WITH GRAVE +    { 0x1E82, "Wacute" },  // LATIN CAPITAL LETTER W WITH ACUTE +    { 0x1E83, "wacute" },  // LATIN SMALL LETTER W WITH ACUTE +    { 0x1E84, "Wdieresis" },  // LATIN CAPITAL LETTER W WITH DIAERESIS +    { 0x1E85, "wdieresis" },  // LATIN SMALL LETTER W WITH DIAERESIS +    { 0x1EF2, "Ygrave" },  // LATIN CAPITAL LETTER Y WITH GRAVE +    { 0x1EF3, "ygrave" },  // LATIN SMALL LETTER Y WITH GRAVE +    { 0x200C, "afii61664" },  // ZERO WIDTH NON-JOINER +    { 0x200D, "afii301" },  // ZERO WIDTH JOINER +    { 0x200E, "afii299" },  // LEFT-TO-RIGHT MARK +    { 0x200F, "afii300" },  // RIGHT-TO-LEFT MARK +    { 0x2012, "figuredash" },  // FIGURE DASH +    { 0x2013, "endash" },  // EN DASH +    { 0x2014, "emdash" },  // EM DASH +    { 0x2015, "afii00208" },  // HORIZONTAL BAR +    { 0x2017, "underscoredbl" },  // DOUBLE LOW LINE +    { 0x2018, "quoteleft" },  // LEFT SINGLE TQUOTATION MARK +    { 0x2019, "quoteright" },  // RIGHT SINGLE TQUOTATION MARK +    { 0x201A, "quotesinglbase" },  // SINGLE LOW-9 TQUOTATION MARK +    { 0x201B, "quotereversed" },  // SINGLE HIGH-REVERSED-9 TQUOTATION MARK +    { 0x201C, "quotedblleft" },  // LEFT DOUBLE TQUOTATION MARK +    { 0x201D, "quotedblright" },  // RIGHT DOUBLE TQUOTATION MARK +    { 0x201E, "quotedblbase" },  // DOUBLE LOW-9 TQUOTATION MARK +    { 0x2020, "dagger" },  // DAGGER +    { 0x2021, "daggerdbl" },  // DOUBLE DAGGER +    { 0x2022, "bullet" },  // BULLET +    { 0x2024, "onedotenleader" },  // ONE DOT LEADER +    { 0x2025, "twodotenleader" },  // TWO DOT LEADER +    { 0x2026, "ellipsis" },  // HORIZONTAL ELLIPSIS +    { 0x202C, "afii61573" },  // POP DIRECTIONAL FORMATTING +    { 0x202D, "afii61574" },  // LEFT-TO-RIGHT OVERRIDE +    { 0x202E, "afii61575" },  // RIGHT-TO-LEFT OVERRIDE +    { 0x2030, "perthousand" },  // PER MILLE SIGN +    { 0x2032, "minute" },  // PRIME +    { 0x2033, "second" },  // DOUBLE PRIME +    { 0x2039, "guilsinglleft" },  // SINGLE LEFT-POINTING ANGLE TQUOTATION MARK +    { 0x203A, "guilsinglright" },  // SINGLE RIGHT-POINTING ANGLE TQUOTATION MARK +    { 0x203C, "exclamdbl" },  // DOUBLE EXCLAMATION MARK +    { 0x2044, "fraction" },  // FRACTION SLASH +    { 0x2070, "zerosuperior" },  // SUPERSCRIPT ZERO +    { 0x2074, "foursuperior" },  // SUPERSCRIPT FOUR +    { 0x2075, "fivesuperior" },  // SUPERSCRIPT FIVE +    { 0x2076, "sixsuperior" },  // SUPERSCRIPT SIX +    { 0x2077, "sevensuperior" },  // SUPERSCRIPT SEVEN +    { 0x2078, "eightsuperior" },  // SUPERSCRIPT EIGHT +    { 0x2079, "ninesuperior" },  // SUPERSCRIPT NINE +    { 0x207D, "parenleftsuperior" },  // SUPERSCRIPT LEFT PARENTHESIS +    { 0x207E, "parenrightsuperior" },  // SUPERSCRIPT RIGHT PARENTHESIS +    { 0x207F, "nsuperior" },  // SUPERSCRIPT LATIN SMALL LETTER N +    { 0x2080, "zeroinferior" },  // SUBSCRIPT ZERO +    { 0x2081, "oneinferior" },  // SUBSCRIPT ONE +    { 0x2082, "twoinferior" },  // SUBSCRIPT TWO +    { 0x2083, "threeinferior" },  // SUBSCRIPT THREE +    { 0x2084, "fourinferior" },  // SUBSCRIPT FOUR +    { 0x2085, "fiveinferior" },  // SUBSCRIPT FIVE +    { 0x2086, "sixinferior" },  // SUBSCRIPT SIX +    { 0x2087, "seveninferior" },  // SUBSCRIPT SEVEN +    { 0x2088, "eightinferior" },  // SUBSCRIPT EIGHT +    { 0x2089, "nineinferior" },  // SUBSCRIPT NINE +    { 0x208D, "parenleftinferior" },  // SUBSCRIPT LEFT PARENTHESIS +    { 0x208E, "parenrightinferior" },  // SUBSCRIPT RIGHT PARENTHESIS +    { 0x20A1, "colonmonetary" },  // COLON SIGN +    { 0x20A3, "franc" },  // FRENCH FRANC SIGN +    { 0x20A4, "lira" },  // LIRA SIGN +    { 0x20A7, "peseta" },  // PESETA SIGN +    { 0x20AA, "afii57636" },  // NEW SHETQEL SIGN +    { 0x20AB, "dong" },  // DONG SIGN +    { 0x20AC, "Euro" },  // EURO SIGN +    { 0x2105, "afii61248" },  // CARE OF +    { 0x2111, "Ifraktur" },  // BLACK-LETTER CAPITAL I +    { 0x2113, "afii61289" },  // SCRIPT SMALL L +    { 0x2116, "afii61352" },  // NUMERO SIGN +    { 0x2118, "weierstrass" },  // SCRIPT CAPITAL P +    { 0x211C, "Rfraktur" },  // BLACK-LETTER CAPITAL R +    { 0x211E, "prescription" },  // PRESCRIPTION TAKE +    { 0x2122, "trademark" },  // TRADE MARK SIGN +    { 0x2126, "Omega" },  // OHM SIGN +    { 0x212E, "estimated" },  // ESTIMATED SYMBOL +    { 0x2135, "aleph" },  // ALEF SYMBOL +    { 0x2153, "onethird" },  // VULGAR FRACTION ONE THIRD +    { 0x2154, "twothirds" },  // VULGAR FRACTION TWO THIRDS +    { 0x215B, "oneeighth" },  // VULGAR FRACTION ONE EIGHTH +    { 0x215C, "threeeighths" },  // VULGAR FRACTION THREE EIGHTHS +    { 0x215D, "fiveeighths" },  // VULGAR FRACTION FIVE EIGHTHS +    { 0x215E, "seveneighths" },  // VULGAR FRACTION SEVEN EIGHTHS +    { 0x2190, "arrowleft" },  // LEFTWARDS ARROW +    { 0x2191, "arrowup" },  // UPWARDS ARROW +    { 0x2192, "arrowright" },  // RIGHTWARDS ARROW +    { 0x2193, "arrowdown" },  // DOWNWARDS ARROW +    { 0x2194, "arrowboth" },  // LEFT RIGHT ARROW +    { 0x2195, "arrowupdn" },  // UP DOWN ARROW +    { 0x21A8, "arrowupdnbse" },  // UP DOWN ARROW WITH BASE +    { 0x21B5, "carriagereturn" },  // DOWNWARDS ARROW WITH CORNER LEFTWARDS +    { 0x21D0, "arrowdblleft" },  // LEFTWARDS DOUBLE ARROW +    { 0x21D1, "arrowdblup" },  // UPWARDS DOUBLE ARROW +    { 0x21D2, "arrowdblright" },  // RIGHTWARDS DOUBLE ARROW +    { 0x21D3, "arrowdbldown" },  // DOWNWARDS DOUBLE ARROW +    { 0x21D4, "arrowdblboth" },  // LEFT RIGHT DOUBLE ARROW +    { 0x2200, "universal" },  // FOR ALL +    { 0x2202, "partialdiff" },  // PARTIAL DIFFERENTIAL +    { 0x2203, "existential" },  // THERE EXISTS +    { 0x2205, "emptyset" },  // EMPTY SET +    { 0x2206, "Delta" },  // INCREMENT +    { 0x2207, "gradient" },  // NABLA +    { 0x2208, "element" },  // ELEMENT OF +    { 0x2209, "notelement" },  // NOT AN ELEMENT OF +    { 0x220B, "suchthat" },  // CONTAINS AS MEMBER +    { 0x220F, "product" },  // N-ARY PRODUCT +    { 0x2211, "summation" },  // N-ARY SUMMATION +    { 0x2212, "minus" },  // MINUS SIGN +    { 0x2215, "fraction" },  // DIVISION SLASH;Duplicate +    { 0x2217, "asteriskmath" },  // ASTERISK OPERATOR +    { 0x2219, "periodcentered" },  // BULLET OPERATOR;Duplicate +    { 0x221A, "radical" },  // STQUARE ROOT +    { 0x221D, "proportional" },  // PROPORTIONAL TO +    { 0x221E, "infinity" },  // INFINITY +    { 0x221F, "orthogonal" },  // RIGHT ANGLE +    { 0x2220, "angle" },  // ANGLE +    { 0x2227, "logicaland" },  // LOGICAL AND +    { 0x2228, "logicalor" },  // LOGICAL OR +    { 0x2229, "intersection" },  // INTERSECTION +    { 0x222A, "union" },  // UNION +    { 0x222B, "integral" },  // INTEGRAL +    { 0x2234, "therefore" },  // THEREFORE +    { 0x223C, "similar" },  // TILDE OPERATOR +    { 0x2245, "congruent" },  // APPROXIMATELY ETQUAL TO +    { 0x2248, "approxequal" },  // ALMOST ETQUAL TO +    { 0x2260, "notequal" },  // NOT ETQUAL TO +    { 0x2261, "equivalence" },  // IDENTICAL TO +    { 0x2264, "lessequal" },  // LESS-THAN OR ETQUAL TO +    { 0x2265, "greaterequal" },  // GREATER-THAN OR ETQUAL TO +    { 0x2282, "propersubset" },  // SUBSET OF +    { 0x2283, "propersuperset" },  // SUPERSET OF +    { 0x2284, "notsubset" },  // NOT A SUBSET OF +    { 0x2286, "reflexsubset" },  // SUBSET OF OR ETQUAL TO +    { 0x2287, "reflexsuperset" },  // SUPERSET OF OR ETQUAL TO +    { 0x2295, "circleplus" },  // CIRCLED PLUS +    { 0x2297, "circlemultiply" },  // CIRCLED TIMES +    { 0x22A5, "perpendicular" },  // UP TACK +    { 0x22C5, "dotmath" },  // DOT OPERATOR +    { 0x2302, "house" },  // HOUSE +    { 0x2310, "revlogicalnot" },  // REVERSED NOT SIGN +    { 0x2320, "integraltp" },  // TOP HALF INTEGRAL +    { 0x2321, "integralbt" },  // BOTTOM HALF INTEGRAL +    { 0x2329, "angleleft" },  // LEFT-POINTING ANGLE BRACKET +    { 0x232A, "angleright" },  // RIGHT-POINTING ANGLE BRACKET +    { 0x2500, "SF100000" },  // BOX DRAWINGS LIGHT HORIZONTAL +    { 0x2502, "SF110000" },  // BOX DRAWINGS LIGHT VERTICAL +    { 0x250C, "SF010000" },  // BOX DRAWINGS LIGHT DOWN AND RIGHT +    { 0x2510, "SF030000" },  // BOX DRAWINGS LIGHT DOWN AND LEFT +    { 0x2514, "SF020000" },  // BOX DRAWINGS LIGHT UP AND RIGHT +    { 0x2518, "SF040000" },  // BOX DRAWINGS LIGHT UP AND LEFT +    { 0x251C, "SF080000" },  // BOX DRAWINGS LIGHT VERTICAL AND RIGHT +    { 0x2524, "SF090000" },  // BOX DRAWINGS LIGHT VERTICAL AND LEFT +    { 0x252C, "SF060000" },  // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL +    { 0x2534, "SF070000" },  // BOX DRAWINGS LIGHT UP AND HORIZONTAL +    { 0x253C, "SF050000" },  // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL +    { 0x2550, "SF430000" },  // BOX DRAWINGS DOUBLE HORIZONTAL +    { 0x2551, "SF240000" },  // BOX DRAWINGS DOUBLE VERTICAL +    { 0x2552, "SF510000" },  // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE +    { 0x2553, "SF520000" },  // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE +    { 0x2554, "SF390000" },  // BOX DRAWINGS DOUBLE DOWN AND RIGHT +    { 0x2555, "SF220000" },  // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE +    { 0x2556, "SF210000" },  // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE +    { 0x2557, "SF250000" },  // BOX DRAWINGS DOUBLE DOWN AND LEFT +    { 0x2558, "SF500000" },  // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE +    { 0x2559, "SF490000" },  // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE +    { 0x255A, "SF380000" },  // BOX DRAWINGS DOUBLE UP AND RIGHT +    { 0x255B, "SF280000" },  // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE +    { 0x255C, "SF270000" },  // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE +    { 0x255D, "SF260000" },  // BOX DRAWINGS DOUBLE UP AND LEFT +    { 0x255E, "SF360000" },  // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE +    { 0x255F, "SF370000" },  // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE +    { 0x2560, "SF420000" },  // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT +    { 0x2561, "SF190000" },  // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE +    { 0x2562, "SF200000" },  // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE +    { 0x2563, "SF230000" },  // BOX DRAWINGS DOUBLE VERTICAL AND LEFT +    { 0x2564, "SF470000" },  // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE +    { 0x2565, "SF480000" },  // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE +    { 0x2566, "SF410000" },  // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL +    { 0x2567, "SF450000" },  // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE +    { 0x2568, "SF460000" },  // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE +    { 0x2569, "SF400000" },  // BOX DRAWINGS DOUBLE UP AND HORIZONTAL +    { 0x256A, "SF540000" },  // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE +    { 0x256B, "SF530000" },  // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE +    { 0x256C, "SF440000" },  // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL +    { 0x2580, "upblock" },  // UPPER HALF BLOCK +    { 0x2584, "dnblock" },  // LOWER HALF BLOCK +    { 0x2588, "block" },  // FULL BLOCK +    { 0x258C, "lfblock" },  // LEFT HALF BLOCK +    { 0x2590, "rtblock" },  // RIGHT HALF BLOCK +    { 0x2591, "ltshade" },  // LIGHT SHADE +    { 0x2592, "shade" },  // MEDIUM SHADE +    { 0x2593, "dkshade" },  // DARK SHADE +    { 0x25A0, "filledbox" },  // BLACK STQUARE +    { 0x25A1, "H22073" },  // WHITE STQUARE +    { 0x25AA, "H18543" },  // BLACK SMALL STQUARE +    { 0x25AB, "H18551" },  // WHITE SMALL STQUARE +    { 0x25AC, "filledrect" },  // BLACK RECTANGLE +    { 0x25B2, "triagup" },  // BLACK UP-POINTING TRIANGLE +    { 0x25BA, "triagrt" },  // BLACK RIGHT-POINTING POINTER +    { 0x25BC, "triagdn" },  // BLACK DOWN-POINTING TRIANGLE +    { 0x25C4, "triaglf" },  // BLACK LEFT-POINTING POINTER +    { 0x25CA, "lozenge" },  // LOZENGE +    { 0x25CB, "circle" },  // WHITE CIRCLE +    { 0x25CF, "H18533" },  // BLACK CIRCLE +    { 0x25D8, "invbullet" },  // INVERSE BULLET +    { 0x25D9, "invcircle" },  // INVERSE WHITE CIRCLE +    { 0x25E6, "openbullet" },  // WHITE BULLET +    { 0x263A, "smileface" },  // WHITE SMILING FACE +    { 0x263B, "invsmileface" },  // BLACK SMILING FACE +    { 0x263C, "sun" },  // WHITE SUN WITH RAYS +    { 0x2640, "female" },  // FEMALE SIGN +    { 0x2642, "male" },  // MALE SIGN +    { 0x2660, "spade" },  // BLACK SPADE SUIT +    { 0x2663, "club" },  // BLACK CLUB SUIT +    { 0x2665, "heart" },  // BLACK HEART SUIT +    { 0x2666, "diamond" },  // BLACK DIAMOND SUIT +    { 0x266A, "musicalnote" },  // EIGHTH NOTE +    { 0x266B, "musicalnotedbl" },  // BEAMED EIGHTH NOTES +    // The names below are in the PU area of Unicode, but needed to get a correct mapping of the symbol font +    { 0xF6D9, "copyrightserif" }, +    { 0xF6DA, "registerserif" }, +    { 0xF6DB, "trademarkserif" }, +    { 0xF8E5, "radicalex" }, +    { 0xF8E6, "arrowvertex" }, +    { 0xF8E7, "arrowhorizex" }, +    { 0xF8E8, "registersans" }, +    { 0xF8E9, "copyrightsans" }, +    { 0xF8EA, "trademarksans" }, +    { 0xF8EB, "parenlefttp" }, +    { 0xF8EC, "parenleftex" }, +    { 0xF8ED, "parenleftbt" }, +    { 0xF8EE, "bracketlefttp" }, +    { 0xF8EF, "bracketleftex" }, +    { 0xF8F0, "bracketleftbt" }, +    { 0xF8F1, "bracelefttp" }, +    { 0xF8F2, "braceleftmid" }, +    { 0xF8F3, "braceleftbt" }, +    { 0xF8F4, "braceex" }, +    { 0xF8F5, "integralex" }, +    { 0xF8F6, "parenrighttp" }, +    { 0xF8F7, "parenrightex" }, +    { 0xF8F8, "parenrightbt" }, +    { 0xF8F9, "bracketrighttp" }, +    { 0xF8FA, "bracketrightex" }, +    { 0xF8FB, "bracketrightbt" }, +    { 0xF8FC, "bracerighttp" }, +    { 0xF8FD, "bracerightmid" }, +    { 0xF8FE, "bracerightbt" }, +    // End of extensions needed for symbols +    { 0xFB00, "ff" },  // LATIN SMALL LIGATURE FF +    { 0xFB01, "fi" },  // LATIN SMALL LIGATURE FI +    { 0xFB02, "fl" },  // LATIN SMALL LIGATURE FL +    { 0xFB03, "ffi" },  // LATIN SMALL LIGATURE FFI +    { 0xFB04, "ffl" },  // LATIN SMALL LIGATURE FFL +    { 0xFB1F, "afii57705" },  // HEBREW LIGATURE YIDDISH YOD YOD PATAH +    { 0xFB2A, "afii57694" },  // HEBREW LETTER SHIN WITH SHIN DOT +    { 0xFB2B, "afii57695" },  // HEBREW LETTER SHIN WITH SIN DOT +    { 0xFB35, "afii57723" },  // HEBREW LETTER VAV WITH DAGESH +    { 0xFB4B, "afii57700" },  // HEBREW LETTER VAV WITH HOLAM +    // end of stuff from glyphlist.txt +    { 0xFFFF, 0 } +}; + +// --------------------------------------------------------------------- +// postscript font substitution dictionary. We assume every postscript printer has at least +// Helvetica, Times, Courier and Symbol + +struct psfont { +    const char *psname; +    float slant; +    float xscale; +}; + +static const psfont Arial[] = { +    {"Arial", 0, 84.04 }, +    { "Arial-Italic", 0, 84.04 }, +    { "Arial-Bold", 0, 88.65 }, +    { "Arial-BoldItalic", 0, 88.65 } +}; + +static const psfont AvantGarde[] = { +    { "AvantGarde-Book", 0, 87.43 }, +    { "AvantGarde-BookOblique", 0, 88.09 }, +    { "AvantGarde-Demi", 0, 88.09 }, +    { "AvantGarde-DemiOblique", 0, 87.43 }, +}; + +static const psfont Bookman [] = { +    { "Bookman-Light", 0, 93.78 }, +    { "Bookman-LightItalic", 0, 91.42 }, +    { "Bookman-Demi", 0, 99.86 }, +    { "Bookman-DemiItalic", 0, 101.54 } +}; + +static const psfont Charter [] = { +    { "CharterBT-Roman", 0, 84.04 }, +    { "CharterBT-Italic", 0.0, 81.92 }, +    { "CharterBT-Bold", 0, 88.99 }, +    { "CharterBT-BoldItalic", 0.0, 88.20 } +}; + +static const psfont Courier [] = { +    { "Courier", 0, 100. }, +    { "Courier-Oblique", 0, 100. }, +    { "Courier-Bold", 0, 100. }, +    { "Courier-BoldOblique", 0, 100. } +}; + +static const psfont Garamond [] = { +    { "Garamond-Antiqua", 0, 78.13 }, +    { "Garamond-Kursiv", 0, 78.13 }, +    { "Garamond-Halbfett", 0, 78.13 }, +    { "Garamond-KursivHalbfett", 0, 78.13 } +}; + +static const psfont GillSans [] = { // ### some estimated value for xstretch +    { "GillSans", 0, 82 }, +    { "GillSans-Italic", 0, 82 }, +    { "GillSans-Bold", 0, 82 }, +    { "GillSans-BoldItalic", 0, 82 } +}; + +static const psfont Helvetica [] = { +    { "Helvetica", 0, 84.04 }, +    { "Helvetica-Oblique", 0, 84.04 }, +    { "Helvetica-Bold", 0, 88.65 }, +    { "Helvetica-BoldOblique", 0, 88.65 } +}; + +static const psfont Letter [] = { +    { "LetterGothic", 0, 83.32 }, +    { "LetterGothic-Italic", 0, 83.32 }, +    { "LetterGothic-Bold", 0, 83.32 }, +    { "LetterGothic-Bold", 0.2, 83.32 } +}; + +static const psfont LucidaSans [] = { +    { "LucidaSans", 0, 94.36 }, +    { "LucidaSans-Oblique", 0, 94.36 }, +    { "LucidaSans-Demi", 0, 98.10 }, +    { "LucidaSans-DemiOblique", 0, 98.08 } +}; + +static const psfont LucidaSansTT [] = { +    { "LucidaSans-Typewriter", 0, 100.50 }, +    { "LucidaSans-TypewriterOblique", 0, 100.50 }, +    { "LucidaSans-TypewriterBold", 0, 100.50 }, +    { "LucidaSans-TypewriterBoldOblique", 0, 100.50 } +}; + +static const psfont LucidaBright [] = { +    { "LucidaBright", 0, 93.45 }, +    { "LucidaBright-Italic", 0, 91.98 }, +    { "LucidaBright-Demi", 0, 96.22 }, +    { "LucidaBright-DemiItalic", 0, 96.98 } +}; + +static const psfont Palatino [] = { +    { "Palatino-Roman", 0, 82.45 }, +    { "Palatino-Italic", 0, 76.56 }, +    { "Palatino-Bold", 0, 83.49 }, +    { "Palatino-BoldItalic", 0, 81.51 } +}; + +static const psfont Symbol [] = { +    { "Symbol", 0, 82.56 }, +    { "Symbol", 0.2, 82.56 }, +    { "Symbol", 0, 82.56 }, +    { "Symbol", 0.2, 82.56 } +}; + +static const psfont Tahoma [] = { +    { "Tahoma", 0, 83.45 }, +    { "Tahoma", 0.2, 83.45 }, +    { "Tahoma-Bold", 0, 95.59 }, +    { "Tahoma-Bold", 0.2, 95.59 } +}; + +static const psfont Times [] = { +    { "Times-Roman", 0, 82.45 }, +    { "Times-Italic", 0, 82.45 }, +    { "Times-Bold", 0, 82.45 }, +    { "Times-BoldItalic", 0, 82.45 } +}; + +static const psfont Verdana [] = { +    { "Verdana", 0, 96.06 }, +    { "Verdana-Italic", 0, 96.06 }, +    { "Verdana-Bold", 0, 107.12 }, +    { "Verdana-BoldItalic", 0, 107.10 } +}; + +static const psfont Utopia [] = { // ### +    { "Utopia-Regular", 0, 84.70 }, +    { "Utopia-Regular", 0.2, 84.70 }, +    { "Utopia-Bold", 0, 88.01 }, +    { "Utopia-Bold", 0.2, 88.01 } +}; + +static const psfont * const SansSerifReplacements[] = { +    Helvetica, 0 +        }; +static const psfont * const SerifReplacements[] = { +    Times, 0 +        }; +static const psfont * const FixedReplacements[] = { +    Courier, 0 +        }; +static const psfont * const TahomaReplacements[] = { +    Verdana, AvantGarde, Helvetica, 0 +        }; +static const psfont * const VerdanaReplacements[] = { +    Tahoma, AvantGarde, Helvetica, 0 +        }; + +static const struct { +    const char * input; // spaces are stripped in here, and everything lowercase +    const psfont * ps; +    const psfont *const * tqreplacements; +} postscriptFonts [] = { +    { "arial", Arial, SansSerifReplacements }, +    { "arialmt", Arial, SansSerifReplacements }, +    { "arialtqunicodems", Arial, SansSerifReplacements }, +    { "avantgarde", AvantGarde, SansSerifReplacements }, +    { "bookman", Bookman, SerifReplacements }, +    { "charter", Charter, SansSerifReplacements }, +    { "bitstreamcharter", Charter, SansSerifReplacements }, +        { "bitstreamcyberbit", Times, SerifReplacements }, // ### +    { "courier", Courier, 0 }, +    { "couriernew", Courier, 0 }, +    { "fixed", Courier, 0 }, +    { "garamond", Garamond, SerifReplacements }, +    { "gillsans", GillSans, SansSerifReplacements }, +    { "helvetica", Helvetica, 0 }, +    { "letter", Letter, FixedReplacements }, +    { "lucida", LucidaSans, SansSerifReplacements }, +    { "lucidasans", LucidaSans, SansSerifReplacements }, +    { "lucidabright", LucidaBright, SerifReplacements }, +    { "lucidasanstypewriter", LucidaSansTT, FixedReplacements }, +    { "luciduxsans", LucidaSans, SansSerifReplacements }, +    { "luciduxserif", LucidaBright, SerifReplacements }, +    { "luciduxmono", LucidaSansTT, FixedReplacements }, +    { "palatino", Palatino, SerifReplacements }, +    { "symbol", Symbol, 0 }, +    { "tahoma", Tahoma, TahomaReplacements }, +    { "terminal", Courier, 0 }, +    { "times", Times, 0 }, +    { "timesnewroman", Times, 0 }, +    { "verdana", Verdana, VerdanaReplacements }, +    { "utopia", Utopia, SerifReplacements }, +    { 0, 0, 0 } +}; + + +// ------------------------------End of static data ---------------------------------- + +// make sure DSC comments are not longer than 255 chars per line. +static TQString wrapDSC( const TQString &str ) +{ +    TQString dsc = str.simplifyWhiteSpace(); +    const uint wrapAt = 254; +    TQString wrapped; +    if ( dsc.length() < wrapAt ) +	wrapped = dsc; +    else { +	wrapped = dsc.left( wrapAt ); +	TQString tmp = dsc.mid( wrapAt ); +	while ( tmp.length() > wrapAt-3 ) { +	    wrapped += "\n%%+" + tmp.left( wrapAt-3 ); +	    tmp = tmp.mid( wrapAt-3 ); +	} +	wrapped += "\n%%+" + tmp; +    } +    return wrapped + "\n"; +} + +static TQString toString( const float num ) +{ +    return TQString::number( num, 'f', 3 ); +} + +// ----------------------------- Internal class declarations ----------------------------- + +class TQPSPrinterFontPrivate; + +class TQPSPrinterPrivate { +public: +    TQPSPrinterPrivate( TQPrinter *prt, int filedes ); +    ~TQPSPrinterPrivate(); + +    void matrixSetup( TQPainter * ); +    void clippingSetup( TQPainter * ); +    void setClippingOff( TQPainter * ); +    void orientationSetup(); +    void resetDrawingTools( TQPainter * ); +    void emitHeader( bool finished ); +    void setFont( const TQFont &, int script ); +    void drawImage( TQPainter *, float x, float y, float w, float h, const TQImage &img, const TQImage &tqmask ); +    void initPage( TQPainter *paint ); +    void flushPage( bool last = FALSE ); + +    TQPrinter   *printer; +    int         pageCount; +    bool        dirtyMatrix; +    bool        dirtyNewPage; +    bool        epsf; +    TQString     fontsUsed; + +    // outstream is the stream the build up pages are copied to. It points to buffer +    // at the start, and is reset to use the outDevice after emitHeader has been called. +    TQTextStream outStream; + +    // stores the descriptions of the first pages. outStream operates on this buffer +    // until we call emitHeader +    TQBuffer *buffer; +    int pagesInBuffer; + +    // the tqdevice the output is in the end streamed to. +    TQIODevice * outDevice; +    int fd; + +    // buffer for the current page. Needed becaus we might have page fonts. +    TQBuffer *pageBuffer; +    TQTextStream pageStream; + +    TQDict<TQString> headerFontNames; +    TQDict<TQString> pageFontNames; +    TQDict<TQPSPrinterFontPrivate> fonts; +    TQPSPrinterFontPrivate *currentFontFile; +    int headerFontNumber; +    int pageFontNumber; +    TQBuffer * fontBuffer; +    TQTextStream fontStream; +    bool dirtyClipping; +    bool firstClipOnPage; +    TQRect boundingBox; +    TQImage * savedImage; +    TQPen cpen; +    TQBrush cbrush; +    bool dirtypen; +    bool dirtybrush; +    TQColor bkColor; +    bool dirtyBkColor; +    TQt::BGMode bkMode; +    bool dirtyBkMode; +#ifndef TQT_NO_TEXTCODEC +    TQTextCodec * currentFontCodec; +#endif +    TQString currentFont; +    TQFontMetrics fm; +    int textY; +    TQFont currentUsed; +    int scriptUsed; +    TQFont currentSet; +    float scale; + +    TQStringList fontpath; +}; + + +class TQPSPrinterFontPrivate { +public: +    TQPSPrinterFontPrivate(); +    virtual ~TQPSPrinterFontPrivate() {} +    virtual TQString postScriptFontName() { return psname; } +    virtual TQString defineFont( TQTextStream &stream, const TQString &ps, const TQFont &f, const TQString &key, +                             TQPSPrinterPrivate *d ); +    virtual void download(TQTextStream& s, bool global); +    virtual void drawText( TQTextStream &stream, const TQPoint &p, TQTextEngine *engine, int item, +                           const TQString &text, TQPSPrinterPrivate *d, TQPainter *paint); +    virtual unsigned short mapUnicode( unsigned short tqunicode ); +    void downloadMapping( TQTextStream &s, bool global ); +    TQString glyphName( unsigned short glyphindex, bool *glyphSet = 0 ); +    virtual void restore(); + +    virtual unsigned short tqunicode_for_glyph(int glyphindex) { return glyphindex; } +    virtual unsigned short glyph_for_tqunicode(unsigned short tqunicode) { return tqunicode; } +    unsigned short insertIntoSubset( unsigned short tqunicode ); +    virtual bool embedded() { return FALSE; } + +    bool operator == ( const TQPSPrinterFontPrivate &other ) { +	return other.psname == psname; +    } +    inline void setSymbol() { symbol = TRUE; } + +protected: +    TQString psname; +    TQStringList tqreplacementList; + +    TQMap<unsigned short, unsigned short> subset;      // tqunicode subset in the global font +    TQMap<unsigned short, unsigned short> page_subset; // subset added in this page +    int subsetCount; +    int pageSubsetCount; +    bool global_dict; +    bool downloaded; +    bool symbol; +}; + +// ------------------- end of class declarations --------------------------- + +// -------------------------------------------------------------- +//   beginning of font related methods +// -------------------------------------------------------------- + + +static int getPsFontType( const TQFontEngine *fe ) +{ +    int weight = fe->fontDef.weight; +    bool italic = fe->fontDef.italic; + +    int type = 0; // used to look up in the psname array +    // get the right modification, or build something +    if ( weight > TQFont::Normal && italic ) +	type = 3; +    else if ( weight > TQFont::Normal ) +	type = 2; +    else if ( italic ) +	type = 1; +    return type; +} + +static int addPsFontNameExtension( const TQFontEngine *fe, TQString &ps, const psfont *psf = 0 ) +{ +    int type = getPsFontType( fe ); + +    if ( psf ) { +	ps = TQString::tqfromLatin1( psf[type].psname ); +    } else { +	switch ( type ) { +	case 1: +	    ps.append( TQString::tqfromLatin1("-Italic") ); +	    break; +	case 2: +	    ps.append( TQString::tqfromLatin1("-Bold") ); +	    break; +	case 3: +	    ps.append( TQString::tqfromLatin1("-BoldItalic") ); +	    break; +	case 0: +	default: +	    break; +	} +    } +    return type; +} + +static TQString makePSFontName( const TQFontEngine *fe, int *listpos = 0, int *ftype = 0 ) +{ +  TQString ps; +  int i; + +  TQString family = fe->fontDef.family.lower(); + +  // try to make a "good" postscript name +  ps = family.simplifyWhiteSpace(); +  i = 0; +  while( (unsigned int)i < ps.length() ) { +    if ( i != 0 && ps[i] == '[') { +      if ( ps[i-1] == ' ' ) +	ps.truncate (i-1); +      else +	ps.truncate (i); +      break; +    } +    if ( i == 0 || ps[i-1] == ' ' ) { +      ps[i] = ps[i].upper(); +      if ( i ) +        ps.remove( i-1, 1 ); +      else +        i++; +    } else { +      i++; +    } +  } + +  if ( ps.isEmpty() ) +      ps = "Helvetica"; + +  // see if the table has a better name +  i = 0; +  TQString lowerName = ps.lower(); +  while( postscriptFonts[i].input && +         postscriptFonts[i].input != lowerName ) +    i++; +  const psfont *psf = postscriptFonts[i].ps; + +  int type = addPsFontNameExtension( fe, ps, psf ); + +  if ( listpos ) +      *listpos = i; +  if ( ftype ) +      *ftype = type; +  return ps; +} + +static void appendReplacements( TQStringList &list, const psfont * const * tqreplacements, int type, float xscale = 100. ) +{ +    // iterate through the tqreplacement fonts +    while ( *tqreplacements ) { +        const psfont *psf = *tqreplacements; +        TQString ps = "[ /" + TQString::tqfromLatin1( psf[type].psname ) + " " + +		     toString( xscale / psf[type].xscale ) + " " + +		     toString( psf[type].slant ) + " ]"; +        list.append( ps ); +        ++tqreplacements; +    } +} + +static TQStringList makePSFontNameList( const TQFontEngine *fe, const TQString &psname = TQString::null, bool useNameForLookup = FALSE ) +{ +    int i; +    int type; +    TQStringList list; +    TQString ps = psname; + +    if ( !ps.isEmpty() && !useNameForLookup ) { +        TQString best = "[ /" + ps + " 1.0 0.0 ]"; +        list.append( best ); +    } + +    ps = makePSFontName( fe, &i, &type ); + +    const psfont *psf = postscriptFonts[i].ps; +    const psfont * const * tqreplacements = postscriptFonts[i].tqreplacements; +    float xscale = 100; +    if ( psf ) { +        // xscale for the "right" font is always 1. We scale the tqreplacements... +        xscale = psf->xscale; +        ps = "[ /" + TQString::tqfromLatin1( psf[type].psname ) + " 1.0 " + +             toString( psf[type].slant ) + " ]"; +    } else { +        ps = "[ /" + ps + " 1.0 0.0 ]"; +        // only add default tqreplacement fonts in case this font was unknown. +        if ( fe->fontDef.fixedPitch ) { +            tqreplacements = FixedReplacements; +        } else { +            tqreplacements = SansSerifReplacements; +            // 100 is courier, but most fonts are not as wide as courier. Using 100 +            // here would make letters overlap for some fonts. This value is empirical. +            xscale = 83; +        } +    } +    list.append( ps ); + +    if ( tqreplacements ) +        appendReplacements( list, tqreplacements, type, xscale); +    return list; +} + +static void emitPSFontNameList( TQTextStream &s, const TQString &psname, const TQStringList &list ) +{ +    s << "/" << psname << "List [\n"; +    s << list.join("\n  "); +    s << "\n] d\n"; +} + +static inline float pointSize( const TQFont &f, float scale ) +{ +    float psize; +    if ( f.pointSize() != -1 ) +	psize = f.pointSize()/scale; +    else +	psize = f.pixelSize(); +    return psize; +} + + +// ========================== FONT CLASSES  =============== + + +TQPSPrinterFontPrivate::TQPSPrinterFontPrivate() +{ +    global_dict = FALSE; +    downloaded  = FALSE; +    symbol = FALSE; +    // map 0 to .notdef +    subset.insert( 0, 0 ); +    subsetCount = 1; +    pageSubsetCount = 0; +} + +unsigned short TQPSPrinterFontPrivate::insertIntoSubset( unsigned short u ) +{ +    unsigned short retval = 0; +    if ( subset.tqfind(u) == subset.end() ) { +        if ( !downloaded ) { // we need to add to the page subset +            subset.insert( u, subsetCount ); // mark it as used +            //printf("GLOBAL SUBSET ADDED %04x = %04x\n",u, subsetCount); +            retval = subsetCount; +            subsetCount++; +        } else if ( page_subset.tqfind(u) == page_subset.end() ) { +            page_subset.insert( u, pageSubsetCount ); // mark it as used +            //printf("PAGE SUBSET ADDED %04x = %04x\n",u, pageSubsetCount); +            retval = pageSubsetCount + (subsetCount/256 + 1) * 256; +            pageSubsetCount++; +        } +    } else { +        qWarning("TQPSPrinterFont::internal error"); +    } +    return retval; +} + +void TQPSPrinterFontPrivate::restore() +{ +    page_subset.clear(); +    pageSubsetCount = 0; +    //qDebug("restore for font %s\n",psname.latin1()); +} + +static inline const char *toHex( uchar u ) +{ +    static char hexVal[3]; +    int i = 1; +    while ( i >= 0 ) { +	ushort hex = (u & 0x000f); +	if ( hex < 0x0a ) +	    hexVal[i] = '0'+hex; +	else +	    hexVal[i] = 'A'+(hex-0x0a); +	u = u >> 4; +	i--; +    } +    hexVal[2] = '\0'; +    return hexVal; +} + +static inline const char *toHex( ushort u ) +{ +    static char hexVal[5]; +    int i = 3; +    while ( i >= 0 ) { +	ushort hex = (u & 0x000f); +	if ( hex < 0x0a ) +	    hexVal[i] = '0'+hex; +	else +	    hexVal[i] = 'A'+(hex-0x0a); +	u = u >> 4; +	i--; +    } +    hexVal[4] = '\0'; +    return hexVal; +} + +static inline const char * toInt( int i ) +{ +    static char intVal[20]; +    intVal[19] = 0; +    int pos = 19; +    if ( i == 0 ) { +	intVal[--pos] = '0'; +    } else { +	bool neg = FALSE; +	if ( i < 0 ) { +	    neg = TRUE; +	    i = -i; +	} +	while ( i ) { +	    int dec = i%10; +	    intVal[--pos] = '0'+dec; +	    i /= 10; +	} +	if ( neg ) +	    intVal[--pos] = '-'; +    } +    return intVal+pos; +} + +void TQPSPrinterFontPrivate::drawText( TQTextStream &stream, const TQPoint &p, TQTextEngine *engine, int item, +                                 const TQString &text, TQPSPrinterPrivate *d, TQPainter *paint) +{ +    int len = engine->length( item ); +    TQScriptItem &si = engine->items[item]; + +    int x = p.x() + si.x; +    int y = p.y() + si.y; +    if ( y != d->textY || d->textY == 0 ) +        stream << y << " Y"; +    d->textY = y; + +    stream << "<"; +    if ( si.analysis.bidiLevel % 2 ) { +	for ( int i = len-1; i >=0; i-- ) +	    stream << toHex( mapUnicode(text.tqunicode()[i].tqunicode()) ); +    } else { +	for ( int i = 0; i < len; i++ ) +	    stream << toHex( mapUnicode(text.tqunicode()[i].tqunicode()) ); +    } +    stream << ">"; + +    stream << si.width << " " << x; + +    if ( paint->font().underline() ) +        stream << ' ' << y + d->fm.underlinePos() + d->fm.lineWidth() +               << " " << d->fm.lineWidth() << " Tl"; +    if ( paint->font().strikeOut() ) +        stream << ' ' << y + d->fm.strikeOutPos() +               << " " << d->fm.lineWidth() << " Tl"; +    stream << " AT\n"; + +} + + +TQString TQPSPrinterFontPrivate::defineFont( TQTextStream &stream, const TQString &ps, const TQFont &f, const TQString &key, +                                   TQPSPrinterPrivate *d ) +{ +    TQString fontName; +    fontName.sprintf( "/%s-Uni", ps.latin1()); + +    if ( d->buffer ) { +        ++d->headerFontNumber; +        d->fontStream << "/F" << d->headerFontNumber << " " +                      << pointSize( f, d->scale ) << fontName << " DF\n"; +        fontName.sprintf( "F%d", d->headerFontNumber ); +        d->headerFontNames.insert( key, new TQString( fontName ) ); +    } else { +        ++d->pageFontNumber; +        stream << "/F" << d->pageFontNumber << " " +               << pointSize( f, d->scale ) << fontName << " DF\n"; +        fontName.sprintf( "F%d", d->pageFontNumber ); +        d->pageFontNames.insert( key, new TQString( fontName ) ); +    } +    return fontName; +} + +unsigned short TQPSPrinterFontPrivate::mapUnicode( unsigned short tqunicode ) +{ +    TQMap<unsigned short, unsigned short>::iterator res; +    res = subset.tqfind( tqunicode ); +    unsigned short offset = 0; +    bool found = FALSE; +    if ( res != subset.end() ) { +        found = TRUE; +    } else { +        if ( downloaded ) { +            res = page_subset.tqfind( tqunicode ); +            offset = (subsetCount/256 + 1) * 256; +            if ( res != page_subset.end() ) +                found = TRUE; +        } +    } +    if ( !found ) { +        return insertIntoSubset( tqunicode ); +    } +    //qDebug("mapping tqunicode %x to %x", tqunicode, offset+*res); +    return offset + *res; +} + +// This map is used for symbol fonts to get the correct glyph names for the latin range +static const unsigned short symbol_map[0x100] = { +    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, +    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, +    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, +    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, +    0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220b, +    0x0028, 0x0029, 0x2217, 0x002b, 0x002c, 0x2212, 0x002e, 0x002f, +    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, +    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + +    0x2245, 0x0391, 0x0392, 0x03a7, 0x0394, 0x0395, 0x03a6, 0x0393, +    0x0397, 0x0399, 0x03d1, 0x039a, 0x039b, 0x039c, 0x039d, 0x039f, +    0x03a0, 0x0398, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03c2, 0x03a9, +    0x039e, 0x03a8, 0x0396, 0x005b, 0x2234, 0x005d, 0x22a5, 0x005f, +    0xf8e5, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3, +    0x03b7, 0x03b9, 0x03d5, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03bf, +    0x03c0, 0x03b8, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03d6, 0x03c9, +    0x03be, 0x03c8, 0x03b6, 0x007b, 0x007c, 0x007d, 0x223c, 0x007f, + +    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, +    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, +    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, +    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, +    0x20ac, 0x03d2, 0x2023, 0x2264, 0x2044, 0x221e, 0x0192, 0x2263, +    0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193, +    0x00b0, 0x00b1, 0x2033, 0x2265, 0x00d7, 0x221d, 0x2202, 0x2022, +    0x00f7, 0x2260, 0x2261, 0x2248, 0x2026, 0xf8e6, 0xf8e7, 0x21b5, + +    0x2135, 0x2111, 0x211c, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229, +    0x222a, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209, +    0x2220, 0x2207, 0xf6da, 0xf6d9, 0xf6db, 0x220f, 0x221a, 0x22c5, +    0x00ac, 0x2227, 0x2228, 0x21d4, 0x21d0, 0x21d1, 0x21d2, 0x21d3, +    0x25ca, 0x2329, 0xf8e8, 0xf8e9, 0xf8ea, 0x2211, 0xf8eb, 0xf8ec, +    0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0, 0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4, +    0x0000, 0x232a, 0x222b, 0x2320, 0xf8f5, 0x2321, 0xf8f6, 0xf8f7, +    0xf8f8, 0xf8f9, 0xf8fa, 0xf8fb, 0xf8fc, 0xf8fd, 0xf8fe, 0x0000, +}; + +TQString TQPSPrinterFontPrivate::glyphName( unsigned short glyphindex, bool *glyphSet ) +{ +    TQString glyphname; +    int l = 0; +    unsigned short tqunicode = tqunicode_for_glyph( glyphindex ); +    if (symbol && tqunicode < 0x100) { +	// map from latin1 to symbol +	tqunicode = symbol_map[tqunicode]; +    } +    if ( !tqunicode && glyphindex ) { +	glyphname = "gl"; +	glyphname += toHex( glyphindex ); +    } else { +	while( tqunicodetoglyph[l].u < tqunicode ) +	    l++; +	if ( tqunicodetoglyph[l].u == tqunicode ) { +	    glyphname = tqunicodetoglyph[l].g; +	    if ( glyphSet ) { +		int other = 0; +		switch ( tqunicode ) { +		    // some glyph names are duplicate in postscript. Make sure we give the +		    // duplicate a different name to avoid infinite recursion +		case 0x0394: +		    other = 0x2206; +		    break; +		case 0x03a9: +		    other = 0x2126; +		    break; +		case 0x0162: +		    other = 0x021a; +		    break; +		case 0x2215: +		    other = 0x2044; +		    break; +		case 0x00ad: +		    other = 0x002d; +		    break; +		case 0x02c9: +		    other = 0x00af; +		    break; +		case 0x03bc: +		    other = 0x00b5; +		    break; +		case 0x2219: +		    other = 0x00b7; +		    break; +		case 0x00a0: +		    other = 0x0020; +		    break; +		case 0x0163: +		    other = 0x021b; +		    break; +		default: +		    break; +		} +		if ( other ) { +		    int oglyph = glyph_for_tqunicode( other ); +		    if( oglyph && oglyph != glyphindex && glyphSet[oglyph] ) { + 			glyphname = "uni"; + 			glyphname += toHex( tqunicode ); +		    } +		} +	    } + 	} else { +	    glyphname = "uni"; +	    glyphname += toHex( tqunicode ); +	} +    } +    return glyphname; +} + +void TQPSPrinterFontPrivate::download(TQTextStream &s, bool global) +{ +    //printf("defining mapping for printer font %s\n",psname.latin1()); +    downloadMapping( s, global ); +} + +void TQPSPrinterFontPrivate::downloadMapping( TQTextStream &s, bool global ) +{ +    uchar rangeOffset = 0; +    uchar numRanges = (uchar)(subsetCount/256 + 1); +    uchar range; +    TQMap<unsigned short, unsigned short> *subsetDict = ⊂ +    if ( !global ) { +        rangeOffset = numRanges; +        numRanges = pageSubsetCount/256 + 1; +        subsetDict = &page_subset; +    } +    // build up inverse table +    unsigned short *inverse = new unsigned short[numRanges * 256]; +    memset( inverse, 0, numRanges * 256 * sizeof( unsigned short ) ); + +    TQMap<unsigned short, unsigned short>::iterator it; +    for ( it = subsetDict->begin(); it != subsetDict->end(); ++it) { +        const unsigned short &mapped = *it; +        inverse[mapped] = it.key(); +    } + +    TQString vector; +    TQString glyphname; + +    for (range=0; range < numRanges; range++) { +        //printf("outputing range %04x\n",range*256); +        vector = "%% Font Page "; +	vector += toHex((uchar)(range + rangeOffset)); +        vector += "\n/"; +        vector += psname; +        vector += "-ENC-"; +	vector += toHex((uchar)(range + rangeOffset)); +	vector += " [\n"; + +        TQString line; +        for(int k=0; k<256; k++ ) { +            int c = range*256 + k; +            unsigned short glyph = inverse[c]; +            glyphname = glyphName( glyph ); +            if ( line.length() + glyphname.length() > 76 ) { +                vector += line; +		vector += "\n"; +                line = ""; +            } +            line += "/" + glyphname; +        } +        vector += line; +	vector += "] def\n"; +        s << vector; +    } + +    delete [] inverse; + +    // DEFINE BASE FONTS + +    for (range=0; range < numRanges; range++) { +        s << "/"; +        s << psname; +        s << "-Uni-"; +        s << toHex((uchar)(range + rangeOffset)); +        s << " "; +        s << psname; +        s << "-ENC-"; +        s << toHex((uchar)(range + rangeOffset)); +        if ( embedded() && embedFonts ) { +            s << " /"; +            s << psname; +            s << " MFEmb\n"; +        } else { +            s << " " << psname << "List"; +            s << " MF\n"; +        } +    } + +    // === write header === +    //   int VMMin; +    //   int VMMax; + +    s << wrapDSC( "%%BeginFont: " + psname ) +      << "%!PS-AdobeFont-1.0 Composite Font\n" +      << wrapDSC( "%%FontName: " + psname + "-Uni" ) +      << "%%Creator: Composite font created by TQt\n"; + +    /* Start the dictionary which will eventually */ +    /* become the font. */ +    s << "25 dict begin\n"; // need to verify. Sivan + +    s << "/FontName /"; +    s << psname; +    s << "-Uni"; +    s << " def\n"; +    s << "/PaintType 0 def\n"; + +    // This is concatenated with the base fonts, so it should perform +    // no transformation. Sivan +    s << "/FontMatrix[1 0 0 1 0 0]def\n"; + +    s << "/FontType "; +    s << 0; +    s << " def\n"; + +    // now come composite font structures +    // FMapTypes: +    // 2: 8/8, 8 bits select the font, 8 the glyph + +    s << "/FMapType 2 def\n"; + +    // The encoding in a composite font is used for indirection. +    // Every char is split into a font-number and a character-selector. +    // PostScript prints glyph number character-selector from the font +    // FDepVector[ Encoding[ font-number ] ]. + +    s << "/Encoding ["; +    for (range=0; range < rangeOffset + numRanges; range++) { +        if (range % 16 == 0) +            s << "\n"; +        else +            s << " "; +        s << range; +    } +    s << "]def\n"; + +  // Descendent fonts + +    s << "/FDepVector [\n"; +    for (range=0; range < rangeOffset + numRanges; range++) { +        s << "/"; +        s << psname; +        s << "-Uni-"; +        s << toHex( range ); +        s << " tqfindfont\n"; +    } +    s << "]def\n"; + +  // === trailer === + +    s << "FontName currentdict end definefont pop\n"; +    s << "%%EndFont\n"; +} + + +// ================== TTF ==================== + +typedef TQ_UINT8  BYTE; +typedef TQ_UINT16 USHORT; +typedef TQ_UINT16 uFWord; +typedef TQ_INT16 SHORT; +typedef TQ_INT16 FWord; +typedef TQ_UINT32   ULONG; +typedef TQ_INT32  FIXED; + +typedef struct { +  TQ_INT16 whole; +  TQ_UINT16 fraction; +} Fixed; // 16.16 bit fixed-point number + +static float f2dot14( ushort s ) +{ +    float f = ((float)( s & 0x3fff ))/ 16384.; +    f += (s & 0x8000) ? ( (s & 0x4000) ? -1 : -2 ) : ( (s & 0x4000) ? 1 : 0 ); +    return f; +} + +typedef struct { +  int*    epts_ctr;                     /* array of contour endpoints */ +  int     num_pts, num_ctr;             /* number of points, number of coutours */ +  FWord*  xcoor, *ycoor;                /* arrays of x and y coordinates */ +  BYTE*   tt_flags;                     /* array of TrueType flags */ +  double* area_ctr; +  char*   check_ctr; +  int*    ctrset;               /* in contour index followed by out contour index */ +} charproc_data; + + +class TQPSPrinterFontTTF +    : public TQPSPrinterFontPrivate { +public: +    TQPSPrinterFontTTF(const TQFontEngine *f, TQByteArray& data); +    virtual void    download(TQTextStream& s, bool global); +    virtual void drawText( TQTextStream &stream, const TQPoint &p, TQTextEngine *engine, int item, +                           const TQString &text, TQPSPrinterPrivate *d, TQPainter *paint); +    //  virtual ~TQPSPrinterFontTTF(); + +    virtual bool embedded() { return TRUE; } +private: +    TQByteArray     data; +    TQMemArray<ushort> uni2glyph; // to speed up lookups +    TQMemArray<ushort> glyph2uni; // to speed up lookups +    bool           defective; // if we can't process this file + +    BYTE*   getTable(const char *); +    void uni2glyphSetup(); +    unsigned short tqunicode_for_glyph(int glyphindex); +    unsigned short glyph_for_tqunicode(unsigned short tqunicode); +    int   topost(FWord x) { return (int)( ((int)(x) * 1000 + HUPM) / unitsPerEm ); } + +#ifdef TQ_PRINTER_USE_TYPE42 +    void sfnts_pputBYTE(BYTE n,TQTextStream& s, +			int& string_len, int& line_len, bool& in_string); +    void sfnts_pputUSHORT(USHORT n,TQTextStream& s, +			  int& string_len, int& line_len, bool& in_string); +    void sfnts_pputULONG(ULONG n,TQTextStream& s, +			 int& string_len, int& line_len, bool& in_string); +    void sfnts_end_string(TQTextStream& s, +			  int& string_len, int& line_len, bool& in_string); +    void sfnts_new_table(ULONG length,TQTextStream& s, +			 int& string_len, int& line_len, bool& in_string); +    void sfnts_glyf_table(ULONG oldoffset, +			  ULONG correct_total_length, +			  TQTextStream& s, +			  int& string_len, int& line_len, bool& in_string); +    void download_sfnts(TQTextStream& s); +#endif + +    void subsetGlyph(int charindex,bool* glyphset); + +    void charproc(int charindex, TQTextStream& s, bool *glyphSet); +    BYTE* charprocFindGlyphData(int charindex); +    void charprocComposite(BYTE *glyph, TQTextStream& s, bool *glyphSet); +    void charprocLoad(BYTE *glyph, charproc_data* cd); + +    int target_type;                      /* 42 or 3 */ + +    int numTables;                        /* number of tables present */ +    TQString PostName;                     /* Font's PostScript name */ +    TQString FullName;                     /* Font's full name */ +    TQString FamilyName;                   /* Font's family name */ +    TQString Style;                        /* Font's style string */ +    TQString Copyright;                    /* Font's copyright string */ +    TQString Version;                      /* Font's version string */ +    TQString Trademark;                    /* Font's trademark string */ +    int llx,lly,urx,ury;          /* bounding box */ + +    Fixed TTVersion;                      /* Truetype version number from offset table */ +    Fixed MfrRevision;                    /* Revision number of this font */ + +    BYTE *offset_table;           /* Offset table in memory */ +    BYTE *post_table;                     /* 'post' table in memory */ + +    BYTE *loca_table;                     /* 'loca' table in memory */ +    BYTE *glyf_table;                     /* 'glyf' table in memory */ +    BYTE *hmtx_table;                     /* 'hmtx' table in memory */ + +    USHORT numberOfHMetrics; +    int unitsPerEm;                       /* unitsPerEm converted to int */ +    int HUPM;                             /* half of above */ + +    int numGlyphs;                        /* from 'post' table */ + +    int indexToLocFormat;         /* short or long offsets */ + +}; + + +static ULONG getULONG(BYTE *p) +{ +  int x; +  ULONG val=0; + +  for(x=0; x<4; x++) { +    val *= 0x100; +    val += p[x]; +  } + +  return val; +} + +static USHORT getUSHORT(BYTE *p) +{ +  int x; +  USHORT val=0; + +  for(x=0; x<2; x++) { +    val *= 0x100; +    val += p[x]; +  } + +  return val; +} + +static Fixed getFixed(BYTE *s) +{ +  Fixed val={0,0}; + +  val.whole = ((s[0] * 256) + s[1]); +  val.fraction = ((s[2] * 256) + s[3]); + +  return val; +} + +static FWord getFWord(BYTE* s)  { return (FWord)  getUSHORT(s); } +static uFWord getuFWord(BYTE* s) { return (uFWord) getUSHORT(s); } +static SHORT getSHORT(BYTE* s)  { return (SHORT)  getUSHORT(s); } + +#if 0 +static const char * const Apple_CharStrings[]={ +  ".notdef",".null","nonmarkingreturn","space","exclam","quotedbl","numbersign", +  "dollar","percent","ampersand","quotesingle","parenleft","parenright", +  "asterisk","plus", "comma","hyphen","period","slash","zero","one","two", +  "three","four","five","six","seven","eight","nine","colon","semicolon", +  "less","equal","greater","question","at","A","B","C","D","E","F","G","H","I", +  "J","K", "L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z", +  "bracketleft","backslash","bracketright","asciicircum","underscore","grave", +  "a","b","c","d","e","f","g","h","i","j","k", "l","m","n","o","p","q","r","s", +  "t","u","v","w","x","y","z","braceleft","bar","braceright","asciitilde", +  "Adieresis","Aring","Ccedilla","Eacute","Ntilde","Odieresis","Udieresis", +  "aacute","agrave","acircumflex","adieresis","atilde","aring","ccedilla", +  "eacute","egrave","ecircumflex","edieresis","iacute","igrave","icircumflex", +  "idieresis","ntilde","oacute","ograve","ocircumflex","odieresis","otilde", +  "uacute","ugrave","ucircumflex","udieresis","dagger","degree","cent", +  "sterling","section","bullet","paragraph","germandbls","registered", +  "copyright","trademark","acute","dieresis","notequal","AE","Oslash", +  "infinity","plusminus","lessequal","greaterequal","yen","mu","partialdiff", +  "summation","product","pi","integral","ordfeminine","ordmasculine","Omega", +  "ae","oslash","questiondown","exclamdown","logicalnot","radical","florin", +  "approxequal","Delta","guillemotleft","guillemotright","ellipsis", +  "nobreakspace","Agrave","Atilde","Otilde","OE","oe","endash","emdash", +  "quotedblleft","quotedblright","quoteleft","quoteright","divide","lozenge", +  "ydieresis","Ydieresis","fraction","currency","guilsinglleft","guilsinglright", +  "fi","fl","daggerdbl","periodcentered","quotesinglbase","quotedblbase", +  "perthousand","Acircumflex","Ecircumflex","Aacute","Edieresis","Egrave", +  "Iacute","Icircumflex","Idieresis","Igrave","Oacute","Ocircumflex","apple", +  "Ograve","Uacute","Ucircumflex","Ugrave","dotlessi","circumflex","tilde", +  "macron","breve","dotaccent","ring","cedilla","hungarumlaut","ogonek","caron", +  "Lslash","lslash","Scaron","scaron","Zcaron","zcaron","brokenbar","Eth","eth", +  "Yacute","yacute","Thorn","thorn","minus","multiply","onesuperior", +  "twosuperior","threesuperior","onehalf","onequarter","threequarters","franc", +  "Gbreve","gbreve","Idot","Scedilla","scedilla","Cacute","cacute","Ccaron", +  "ccaron","dmacron","markingspace","capslock","shift","propeller","enter", +  "markingtabrtol","markingtabltor","control","markingdeleteltor", +  "markingdeletertol","option","escape","parbreakltor","parbreakrtol", +  "newpage","checkmark","linebreakltor","linebreakrtol","markingnobreakspace", +  "diamond","appleoutline"}; +#endif + +// #define DEBUG_TRUETYPE + +TQPSPrinterFontTTF::TQPSPrinterFontTTF(const TQFontEngine *f, TQByteArray& d) +{ +  data = d; +  defective = FALSE; + +  BYTE *ptr; + +  target_type = 3;  // will work on any printer +  //target_type = 42; // works with gs, faster, better quality + +#ifdef TQ_PRINTER_USE_TYPE42 +  char* environment_preference = getenv("TQT_TTFTOPS"); +  if (environment_preference) { +    if (TQString(environment_preference) == "42") +      target_type = 42; +    else if (TQString(environment_preference) == "3") +      target_type = 3; +    else +      qWarning("The value of TQT_TTFTOPS must be 42 or 3"); +  } +#endif +  offset_table = (unsigned char*) data.data(); /* first 12 bytes */ + +  /* Determine how many directory entries there are. */ +  numTables = getUSHORT( offset_table + 4 ); + +  /* Extract information from the "Offset" table. */ +  TTVersion = getFixed( offset_table ); + +  /* Load the "head" table and extract information from it. */ +  ptr = getTable("head"); +  if ( !ptr ) { +      defective = TRUE; +      return; +  } +  MfrRevision = getFixed( ptr + 4 );            /* font revision number */ +  unitsPerEm = getUSHORT( ptr + 18 ); +  HUPM = unitsPerEm / 2; +#ifdef DEBUG_TRUETYPE +  printf("unitsPerEm=%d",(int)unitsPerEm); +#endif +  llx = topost( getFWord( ptr + 36 ) );         /* bounding box info */ +  lly = topost( getFWord( ptr + 38 ) ); +  urx = topost( getFWord( ptr + 40 ) ); +  ury = topost( getFWord( ptr + 42 ) ); +  indexToLocFormat = getSHORT( ptr + 50 );      /* size of 'loca' data */ +  if(indexToLocFormat != 0 && indexToLocFormat != 1) { +    qWarning("TrueType font is unusable because indexToLocFormat != 0"); +    defective = TRUE; +    return; +  } +  if( getSHORT(ptr+52) != 0 ) { +    qWarning("TrueType font is unusable because glyphDataFormat != 0"); +    defective = TRUE; +    return; +  } + +  // === Load information from the "name" table === + +  /* Set default values to avoid future references to */ +  /* undefined pointers. */ + +  psname = FullName = FamilyName = Version = Style = "unknown"; +  Copyright = "No copyright notice"; +  Trademark = "No trademark notice"; + +  BYTE* table_ptr = getTable("name");           /* pointer to table */ +  if ( !table_ptr ) { +      defective = TRUE; +      qDebug("couldn't tqfind name table" ); +      return; +  } +  int numrecords = getUSHORT( table_ptr + 2 );  /* number of names */ +  char* strings = (char *)table_ptr + getUSHORT( table_ptr + 4 ); /* start of string storage */ + +  BYTE* ptr2 = table_ptr + 6; +  for(int x=0; x < numrecords; x++,ptr2+=12) { +      int platform = getUSHORT(ptr2); +    //int encoding = getUSHORT(ptr2+2); +    //int language = getUSHORT(ptr2+4); +    int nameid   = getUSHORT(ptr2+6); +    int length   = getUSHORT(ptr2+8); +    int offset   = getUSHORT(ptr2+10); + +    if( platform == 1 && nameid == 0 ) +      Copyright.setLatin1(strings+offset,length); + +    if( platform == 1 && nameid == 1 ) +      FamilyName.setLatin1(strings+offset,length); + +    if( platform == 1 && nameid == 2 ) +      Style.setLatin1(strings+offset,length); + +    if( platform == 1 && nameid == 4 ) +      FullName.setLatin1(strings+offset,length); + +    if( platform == 1 && nameid == 5 ) +      Version.setLatin1(strings+offset,length); + +    if( platform == 1 && nameid == 6 ) +      psname.setLatin1(strings+offset,length); + +    if( platform == 1 && nameid == 7 ) +      Trademark.setLatin1(strings+offset,length); + +  } +  psname.tqreplace(' ', '-'); +  psname.tqreplace("/", ""); +  if (psname.isEmpty()) +      psname = makePSFontName(f); + +  //read_cmap(font); + +  /* We need to have the PostScript table around. */ + +  post_table = getTable("post"); +#if 0 +  if ( post_table ) { +      Fixed post_format = getFixed( post_table ); + +      if( post_format.whole != 2 || post_format.fraction != 0 ) { +          qWarning("TrueType font does not have a format 2.0 'post' table"); +          qWarning("post format is %d.%d",post_format.whole,post_format.fraction); +          // Sivan Feb 2001: no longer defective. +          // defective = TRUE; +      } +  } +#endif +  BYTE *maxp = getTable("maxp"); +  if ( !maxp ) { +      defective = TRUE; +      qDebug("no maxp table in font"); +      return; +  } +  numGlyphs = getUSHORT( maxp + 4 ); +//  qDebug("number of glyphs is %d", numGlyphs); +  tqreplacementList = makePSFontNameList( f, psname ); +  uni2glyphSetup(); +} + + +void TQPSPrinterFontTTF::drawText( TQTextStream &stream, const TQPoint &p, TQTextEngine *engine, int item, +				  const TQString &text, TQPSPrinterPrivate *d, TQPainter *paint) +{ +    // we draw glyphs here to get correct shaping of arabic and indic +    TQScriptItem &si = engine->items[item]; +    engine->tqshape( item ); +    int len = si.num_glyphs; + +    int x = p.x() + si.x; +    int y = p.y() + si.y; +    if ( y != d->textY || d->textY == 0 ) +        stream << y << " Y"; +    d->textY = y; + +    TQCString xyarray; +    int xo = 0; +    int yo = 0; + +    glyph_t *glyphs = engine->glyphs( &si ); +    advance_t *advances = engine->advances( &si ); +    qoffset_t *offsets = engine->offsets( &si ); +#ifdef TQ_WS_X11 +    int type = si.fontEngine->type(); +    bool glyphIndices = (type == TQFontEngine::Xft); +    // This helps us get arabic for XLFD fonts working. In that case we have a Unicode +    // cmap (== 0), and the glyphs array tqcontains the tqshaped string. +    bool useGlyphAsUnicode = (type == TQFontEngine::XLFD && si.fontEngine->cmap() == 0); +#else // TQ_WS_TQWS +    const bool glyphIndices = FALSE; +    const bool useGlyphAsUnicode = TRUE; +#endif +    stream << "<"; +    if ( si.analysis.bidiLevel % 2 ) { +	for ( int i = len-1; i >=0; i-- ) { +	    // map tqunicode is not really the correct name, as we map glyphs, but we also download glyphs, so this works +            unsigned short glyph; +            if (glyphIndices) +                glyph = glyphs[i]; +            else +                glyph = glyph_for_tqunicode(useGlyphAsUnicode ? glyphs[i] : text.tqunicode()[i].tqunicode()); +	    stream << toHex(mapUnicode(glyph)); +	    if ( i != len-1 ) { +		xyarray += toInt( xo + offsets[i].x + advances[i+1] ); +		xyarray += " "; +		xyarray += toInt( yo + offsets[i].y ); +		xyarray += " "; +		xo = -offsets[i].x; +		yo = -offsets[i].y; +	    } +	} +    } else { +	for ( int i = 0; i < len; i++ ) { +	    // map tqunicode is not really the correct name, as we map glyphs, but we also download glyphs, so this works +            unsigned short glyph; +            if (glyphIndices) +                glyph = glyphs[i]; +            else +                glyph = glyph_for_tqunicode(useGlyphAsUnicode ? glyphs[i] : text.tqunicode()[i].tqunicode()); +	    stream << toHex(mapUnicode(glyph)); +	    if ( i ) { +		xyarray += toInt( xo + offsets[i].x + advances[i-1] ); +		xyarray += " "; +		xyarray += toInt( yo + offsets[i].y ); +		xyarray += " "; +		xo = -offsets[i].x; +		yo = -offsets[i].y; +	    } +	} +    } +    stream << ">"; + +    stream << "[" << xyarray << "0 0]"; +    stream << si.width << " " << x; + +    if ( paint->font().underline() ) +        stream << ' ' << y + d->fm.underlinePos() + d->fm.lineWidth() +               << " " << d->fm.lineWidth() << " Tl"; +    if ( paint->font().strikeOut() ) +        stream << ' ' << y + d->fm.strikeOutPos() +               << " " << d->fm.lineWidth() << " Tl"; +    stream << " XYT\n"; + +} + + +void TQPSPrinterFontTTF::download(TQTextStream& s,bool global) +{ +    emitPSFontNameList( s, psname, tqreplacementList); +    if ( !embedFonts ) { +        downloadMapping(s, global); +        return; +    } +     +    //qDebug("downloading ttf font %s", psname.latin1() ); +    //qDebug("target type=%d", target_type); +    global_dict = global; +    TQMap<unsigned short, unsigned short> *subsetDict = ⊂ +    if ( !global ) +        subsetDict = &page_subset; + +    downloaded  = TRUE; + +    if (defective) { +        s << "% Font "; +        s << FullName; +        s << " cannot be downloaded\n"; +        return; +    } + +    // === write header === +    int VMMin; +    int VMMax; + +    s << wrapDSC( "%%BeginFont: " + FullName ); +    if( target_type == 42 ) { +        s << "%!PS-TrueTypeFont-" +          << TTVersion.whole +          << "." +          << TTVersion.fraction +          << "-" +          << MfrRevision.whole +          << "." +          << MfrRevision.fraction +          << "\n"; +    } else { +        /* If it is not a Type 42 font, we will use a different format. */ +        s << "%!PS-Adobe-3.0 Resource-Font\n"; +    }     /* See RBIIp 641 */ + +    if( Copyright != (char*)NULL ) { +        s << wrapDSC( "%%Copyright: " + Copyright ); +    } + +    if( target_type == 42 ) +        s << "%%Creator: Converted from TrueType to type 42 by TQt\n"; +    else +        s << "%%Creator: Converted from TrueType by TQt\n"; + +    /* If VM usage information is available, print it. */ +    if( target_type == 42 && post_table) +    { +        VMMin = (int)getULONG( post_table + 16 ); +        VMMax = (int)getULONG( post_table + 20 ); +        if( VMMin > 0 && VMMax > 0 ) +            s << "%%VMUsage: " << VMMin << " " << VMMax << "\n"; +    } + +    /* Start the dictionary which will eventually */ +    /* become the font. */ +    if( target_type != 3 ) { +        s << "15 dict begin\n"; +    }  else { +        s << "25 dict begin\n"; + +        /* Type 3 fonts will need some subroutines here. */ +        s << "/_d{bind def}bind def\n"; +        s << "/_m{moveto}_d\n"; +        s << "/_l{lineto}_d\n"; +        s << "/_cl{closepath eofill}_d\n"; +        s << "/_c{curveto}_d\n"; +        s << "/_sc{7 -1 roll{setcachetqdevice}{pop pop pop pop pop pop}ifelse}_d\n"; +        s << "/_e{exec}_d\n"; +    } + +    s << "/FontName /"; +    s << psname; +    s << " def\n"; +    s << "/PaintType 0 def\n"; + +    if(target_type == 42) +        s << "/FontMatrix[1 0 0 1 0 0]def\n"; +    else +        s << "/FontMatrix[.001 0 0 .001 0 0]def\n"; + +    s << "/FontBBox["; +    s<< llx; +    s << " "; +    s<< lly; +    s << " "; +    s<< urx; +    s << " "; +    s<< ury; +    s << "]def\n"; + +    s << "/FontType "; +    s<< target_type; +    s << " def\n"; + +    // === write encoding === + +    s << "/Encoding StandardEncoding def\n"; + +    // === write fontinfo dict === + +    /* We create a sub dictionary named "FontInfo" where we */ +    /* store information which though it is not used by the */ +    /* interpreter, is useful to some programs which will */ +    /* be printing with the font. */ +    s << "/FontInfo 10 dict dup begin\n"; + +    /* These names come from the TrueType font's "name" table. */ +    s << "/FamilyName ("; +    s << FamilyName; +    s << ") def\n"; + +    s << "/FullName ("; +    s << FullName; +    s << ") def\n"; + +    s << "/Notice ("; +    s << Copyright; +    s << " "; +    s << Trademark; +    s << ") def\n"; + +    /* This information is not quite correct. */ +    s << "/Weight ("; +    s << Style; +    s << ") def\n"; + +    /* Some fonts have this as "version". */ +    s << "/Version ("; +    s << Version; +    s << ") def\n"; + +    /* Some information from the "post" table. */ +    if ( post_table ) { +        Fixed ItalicAngle = getFixed( post_table + 4 ); +        s << "/ItalicAngle "; +        s << ItalicAngle.whole; +        s << "."; +        s << ItalicAngle.fraction; +        s << " def\n"; + +        s << "/isFixedPitch "; +        s << (getULONG( post_table + 12 ) ? "true" : "false" ); +        s << " def\n"; + +        s << "/UnderlinePosition "; +        s << (int)getFWord( post_table + 8 ); +        s << " def\n"; + +        s << "/UnderlineThickness "; +        s << (int)getFWord( post_table + 10 ); +        s << " def\n"; +    } +    s << "end readonly def\n"; + +#ifdef TQ_PRINTER_USE_TYPE42 +    /* If we are generating a type 42 font, */ +    /* emmit the sfnts array. */ +    if( target_type == 42 ) +        download_sfnts(s); +#endif +    /* If we are generating a Type 3 font, we will need to */ +    /* have the 'loca' and 'glyf' tables arround while */ +    /* we are generating the CharStrings. */ +    if(target_type == 3) +    { +        BYTE *ptr;                        /* We need only one value */ +        ptr = getTable("hhea"); +        numberOfHMetrics = getUSHORT(ptr + 34); + +        loca_table = getTable("loca"); +        glyf_table = getTable("glyf"); +        hmtx_table = getTable("hmtx"); +    } + +    // ===  CharStrings array === + +    // subsetting. We turn a char subset into a glyph subset +    // and we mark as used the base glyphs of used composite glyphs. + +    bool glyphset[65536]; +    for(int c=0; c < 65536; c++) +        glyphset[c] = FALSE; +    glyphset[0] = TRUE; // always output .notdef + +    TQMap<unsigned short, unsigned short>::iterator it; +    for( it = subsetDict->begin(); it != subsetDict->end(); ++it ) { +	subsetGlyph( it.key(), glyphset ); +    } +    int nGlyphs = numGlyphs; +    if ( target_type == 3 ) { +        nGlyphs = 0;; +        for(int c=0; c < 65536; c++) +            if ( glyphset[c] ) nGlyphs++; +    } + +    s << "/CharStrings "; +    s << nGlyphs; +    s << " dict dup begin\n"; + +    // Emmit one key-value pair for each glyph. +    for(int x=0; x < 65536; x++) { +        if(target_type == 42) { +            s << "/"; +            s << glyphName( x ); +            s << " "; +            s << x; +            s << " def\n"; +        } else { /* type 3 */ +            if (!glyphset[x]) continue; + +	    //qDebug("emitting charproc for glyph %d, name=%s", x, glyphName(x).latin1() ); +            s << "/"; +            s << glyphName( x, glyphset ); +            s << "{"; +            charproc(x,s, glyphset); +            s << "}_d\n";     /* "} bind def" */ +        } +    } + +    s << "end readonly def\n"; + +    // === trailer === + +    /* If we are generating a type 3 font, we need to provide */ +    /* a BuildGlyph and BuildChar proceedures. */ +    if( target_type == 3 ) { +        s << "\n"; + +        s << "/BuildGlyph\n"; +        s << " {exch begin\n";              /* start font dictionary */ +        s << " CharStrings exch\n"; +        s << " 2 copy known not{pop /.notdef}if\n"; +        s << " true 3 1 roll get exec\n"; +        s << " end}_d\n"; + +        s << "\n"; + +        /* This proceedure is for compatiblity with */ +        /* level 1 interpreters. */ +        s << "/BuildChar {\n"; +        s << " 1 index /Encoding get exch get\n"; +        s << " 1 index /BuildGlyph get exec\n"; +        s << "}_d\n"; + +        s << "\n"; + +    } + +    /* If we are generating a type 42 font, we need to check to see */ +    /* if this PostScript interpreter understands type 42 fonts.  If */ +    /* it doesn't, we will hope that the Apple TrueType rasterizer */ +    /* has been loaded and we will adjust the font accordingly. */ +    /* I found out how to do this by examining a TrueType font */ +    /* generated by a Macintosh.  That is where the TrueType interpreter */ +    /* setup instructions and part of BuildGlyph came from. */ +    else if( target_type == 42 ) { +        s << "\n"; + +        /* If we have no "resourcestatus" command, or FontType 42 */ +        /* is unknown, leave "true" on the stack. */ +        s << "systemdict/resourcestatus known\n"; +        s << " {42 /FontType resourcestatus\n"; +        s << "   {pop pop false}{true}ifelse}\n"; +        s << " {true}ifelse\n"; + +        /* If true, execute code to produce an error message if */ +        /* we can't tqfind Apple's TrueDict in VM. */ +        s << "{/TrueDict where{pop}{(%%[ Error: no TrueType rasterizer ]%%)= flush}ifelse\n"; + +        /* Since we are expected to use Apple's TrueDict TrueType */ +        /* reasterizer, change the font type to 3. */ +        s << "/FontType 3 def\n"; + +        /* Define a string to hold the state of the Apple */ +        /* TrueType interpreter. */ +        s << " /TrueState 271 string def\n"; + +        /* It looks like we get information about the resolution */ +        /* of the printer and store it in the TrueState string. */ +        s << " TrueDict begin sfnts save\n"; +        s << " 72 0 matrix defaultmatrix dtransform dup\n"; +        s << " mul exch dup mul add sqrt cvi 0 72 matrix\n"; +        s << " defaultmatrix dtransform dup mul exch dup\n"; +        s << " mul add sqrt cvi 3 -1 roll restore\n"; +        s << " TrueState initer end\n"; + +        /* This BuildGlyph procedure will look the name up in the */ +        /* CharStrings array, and then check to see if what it gets */ +        /* is a procedure.  If it is, it executes it, otherwise, it */ +        /* lets the TrueType rasterizer loose on it. */ + +        /* When this proceedure is executed the stack tqcontains */ +        /* the font dictionary and the character name.  We */ +        /* exchange arguments and move the dictionary to the */ +        /* dictionary stack. */ +        s << " /BuildGlyph{exch begin\n"; +        /* stack: charname */ + +        /* Put two copies of CharStrings on the stack and consume */ +        /* one testing to see if the charname is defined in it, */ +        /* leave the answer on the stack. */ +        s << "  CharStrings dup 2 index known\n"; +        /* stack: charname CharStrings bool */ + +        /* Exchange the CharStrings dictionary and the charname, */ +        /* but if the answer was false, tqreplace the character name */ +        /* with ".notdef". */ +        s << "    {exch}{exch pop /.notdef}ifelse\n"; +        /* stack: CharStrings charname */ + +        /* Get the value from the CharStrings dictionary and see */ +        /* if it is executable. */ +        s << "  get dup xcheck\n"; +        /* stack: CharStrings_entry */ + +        /* If is a proceedure.  Execute according to RBIIp 277-278. */ +        s << "    {currentdict systemdict begin begin exec end end}\n"; + +        /* Is a TrueType character index, let the rasterizer at it. */ +        s << "    {TrueDict begin /bander load cvlit exch TrueState render end}\n"; + +        s << "    ifelse\n"; + +        /* Pop the font's dictionary off the stack. */ +        s << " end}bind def\n"; + +        /* This is the level 1 compatibility BuildChar procedure. */ +        /* See RBIIp 281. */ +        s << " /BuildChar{\n"; +        s << "  1 index /Encoding get exch get\n"; +        s << "  1 index /BuildGlyph get exec\n"; +        s << " }bind def\n"; + +        /* Here we close the condition which is true */ +        /* if the printer has no built-in TrueType */ +        /* rasterizer. */ +        s << "}if\n"; +        s << "\n"; +    } /* end of if Type 42 not understood. */ + +    s << "FontName currentdict end definefont pop\n"; + +    downloadMapping(s, global); +    s << "%%EndFont\n"; +} + +BYTE* TQPSPrinterFontTTF::getTable(const char* name) +{ +    BYTE *ptr; +    int x; + +    /* We must search the table directory. */ +    ptr = offset_table + 12; +    x=0; +    while (x != numTables) { +        if( strncmp((const char *)ptr,name,4) == 0 ) { +            ULONG offset; +            //ULONG length; +            BYTE *table; + +            offset = getULONG( ptr + 8 ); +            //length = getULONG( ptr + 12 ); + +            table = offset_table + offset; +            return table; +        } + +        x++; +        ptr += 16; +    } + +    return 0; +} + +void TQPSPrinterFontTTF::uni2glyphSetup() +{ +  uni2glyph.resize(65536); +  int i; +  for (i=0; i<65536; i++) uni2glyph[i] = 0x0000; +  glyph2uni.resize(65536); +  for (i=0; i<65536; i++) glyph2uni[i] = 0x0000; + +  unsigned char* cmap = getTable("cmap"); +  int pos = 0; + +  //USHORT version = getUSHORT(cmap + pos); +  pos += 2; +  USHORT nmaps   = getUSHORT(cmap + pos); pos += 2; + +  //fprintf(stderr,"cmap version %d (should be 0), %d maps\n",version,nmaps); + +  ULONG offset = 0; +  int map = -1; +  bool symbol = TRUE; +  for (i=0; i<nmaps; i++) { +    USHORT platform = getUSHORT(cmap+pos); pos+=2; +    USHORT encoding = getUSHORT(cmap+pos); pos+=2; +           offset   = getULONG( cmap+pos); pos+=4; +           //fprintf(stderr,"[%d] plat %d enc %d\n",i,platform,encoding); +	   if (platform == 3 && encoding == 1) { +	       map = i; +	       symbol = FALSE; +	       break; // tqunicode +	   } +	   if (platform == 3 && encoding == 0) { +	       // symbol, continue looking +	       map = i; +	   } +  } +  if (map==nmaps) { +    qWarning("Font does not have tqunicode encoding\n"); +    return; // no tqunicode encoding! +  } + +  pos = 8*map; +  //fprintf(stderr,"Doing Unicode encoding\n"); + +  pos = offset; +  USHORT format = getUSHORT(cmap+pos); pos+=2; +  //fprintf(stderr,"Unicode cmap format %d\n",format); + +  if (format != 4) { +    //qWarning("Unicode cmap format is not 4"); +    return; +  } + +  pos += 2; // length +  pos += 2; // version +  USHORT segcount = getUSHORT(cmap+pos) / 2; pos+=2; + +  //fprintf(stderr,"Unicode cmap seg count %d\n",segcount); + +  // skip search data +  pos += 2; +  pos += 2; +  pos += 2; + +  unsigned char* endcode    = cmap + offset + 14; +  unsigned char* startcode  = cmap + offset + 16 + 2*segcount; +  unsigned char* iddelta    = cmap + offset + 16 + 4*segcount; +  unsigned char* idrangeoff = cmap + offset + 16 + 6*segcount; +  //unsigned char* glyphid    = cmap + offset + 16 + 8*segcount; +  for (i=0; i<segcount; i++) { +    USHORT endcode_i    = getUSHORT(endcode   +2*i); +    USHORT startcode_i  = getUSHORT(startcode +2*i); +    SHORT iddelta_i    = getSHORT(iddelta   +2*i); +    USHORT idrangeoff_i = getUSHORT(idrangeoff+2*i); + +//     fprintf(stderr,"[%d] %04x-%04x (%x %x)\n", +//         i,startcode_i,endcode_i,iddelta_i,idrangeoff_i); +    if (endcode_i == 0xffff) break; // last dummy segment + +    if (idrangeoff_i == 0) { +      for (USHORT c = startcode_i; c <= endcode_i; c++) { +        USHORT g = c + iddelta_i; // glyph index +        if ( g != 0 ) { +            uni2glyph[g] = c; +            glyph2uni[c] = g; +        } +      } +    } else { +      for (USHORT c = startcode_i; c <= endcode_i; c++) { +        USHORT g = getUSHORT(idrangeoff+2*i +                             + 2*(c - startcode_i) +                             + idrangeoff_i); +        if ( g != 0 ) { +            uni2glyph[g] = c; +            glyph2uni[c] = g; +        } +      } +    } +  } +  if (symbol && glyph2uni[0x40] == 0 && glyph2uni[0xf040] != 0) { +      // map 0xf000-0xf0ff into latin1 range. +      for (int i = 0; i < 0x100; ++i) { +	  if (!glyph2uni[i]) +	      glyph2uni[i] = glyph2uni[i+0xf000]; + +      } +  } +} + +USHORT TQPSPrinterFontTTF::tqunicode_for_glyph(int glyphindex) +{ +  return uni2glyph[glyphindex]; +} + +USHORT TQPSPrinterFontTTF::glyph_for_tqunicode(unsigned short tqunicode) +{ +  return glyph2uni[tqunicode]; +} + +#ifdef TQ_PRINTER_USE_TYPE42 +// ****************** SNFTS ROUTINES ******* + +/*------------------------------------------------------------------- +** sfnts routines +** These routines generate the PostScript "sfnts" array which +** tqcontains one or more strings which contain a reduced version +** of the TrueType font. +** +** A number of functions are required to accomplish this rather +** complicated task. +-------------------------------------------------------------------*/ + +// Write a BYTE as a hexadecimal value as part of the sfnts array. + +void TQPSPrinterFontTTF::sfnts_pputBYTE(BYTE n,TQTextStream& s, +                                  int& string_len, int& line_len, bool& in_string) +{ +  static const char hexdigits[]="0123456789ABCDEF"; + +  if(!in_string) { +    s << "<"; +    string_len = 0; +    line_len++; +    in_string = TRUE; +  } + +  s << hexdigits[ n / 16 ] ; +  s << hexdigits[ n % 16 ] ; +  string_len++; +  line_len+=2; + +  if(line_len > 70) { +    s << "\n"; +    line_len=0; +  } +} + +// Write a USHORT as a hexadecimal value as part of the sfnts array. + +void TQPSPrinterFontTTF::sfnts_pputUSHORT(USHORT n,TQTextStream& s, +                                  int& string_len, int& line_len, bool& in_string) +{ +  sfnts_pputBYTE(n / 256,s, string_len, line_len, in_string); +  sfnts_pputBYTE(n % 256,s, string_len, line_len, in_string); +} + + +// Write a ULONG as part of the sfnts array. + +void TQPSPrinterFontTTF::sfnts_pputULONG(ULONG n,TQTextStream& s, +                                  int& string_len, int& line_len, bool& in_string) +{ +  int x1 = n % 256;   n /= 256; +  int x2 = n % 256;   n /= 256; +  int x3 = n % 256;   n /= 256; + +  sfnts_pputBYTE(n,s , string_len, line_len, in_string); +  sfnts_pputBYTE(x3,s, string_len, line_len, in_string); +  sfnts_pputBYTE(x2,s, string_len, line_len, in_string); +  sfnts_pputBYTE(x1,s, string_len, line_len, in_string); +} + +/* +** This is called whenever it is +** necessary to end a string in the sfnts array. +** +** (The array must be broken into strings which are +** no longer than 64K characters.) +*/ +void TQPSPrinterFontTTF::sfnts_end_string(TQTextStream& s, +                                    int& string_len, int& line_len, bool& in_string) +{ +  if(in_string) { +    string_len=0;               /* fool sfnts_pputBYTE() */ + +    // s << "\n% dummy byte:\n"; + +    // extra byte for pre-2013 compatibility +    sfnts_pputBYTE(0, s, string_len, line_len, in_string); + +    s << ">"; +    line_len++; +  } + +  in_string=FALSE; +} + +/* +** This is called at the start of each new table. +** The argement is the length in bytes of the table +** which will follow.  If the new table will not fit +** in the current string, a new one is started. +*/ +void TQPSPrinterFontTTF::sfnts_new_table(ULONG length,TQTextStream& s, +                                   int& string_len, int& line_len, bool& in_string) +{ +  if( (string_len + length) > 65528 ) +    sfnts_end_string(s, string_len, line_len, in_string); +} + +/* +** We may have to break up the 'glyf' table.  That is the reason +** why we provide this special routine to copy it into the sfnts +** array. +*/ +void TQPSPrinterFontTTF::sfnts_glyf_table(ULONG oldoffset, +                                    ULONG correct_total_length, +                                    TQTextStream& s, +                                    int& string_len, int& line_len, bool& in_string) + +{ +  int x; +  ULONG off; +  ULONG length; +  int c; +  ULONG total=0;                /* running total of bytes written to table */ + +  loca_table = getTable("loca"); + +  int font_off = oldoffset; + +  /* Copy the glyphs one by one */ +  for(x=0; x < numGlyphs; x++) { +    /* Read the glyph offset from the index-to-location table. */ +    if(indexToLocFormat == 0) { +      off = getUSHORT( loca_table + (x * 2) ); +      off *= 2; +      length = getUSHORT( loca_table + ((x+1) * 2) ); +      length *= 2; +      length -= off; +    } else { +      off = getULONG( loca_table + (x * 4) ); +      length = getULONG( loca_table + ((x+1) * 4) ); +      length -= off; +    } + +    //  fprintf(stderr,"glyph length=%d",(int)length); + +    /* Start new string if necessary. */ +    sfnts_new_table( (int)length, s, string_len, line_len, in_string ); + +    /* +    ** Make sure the glyph is padded out to a +    ** two byte boundary. +    */ +    if( length % 2 ) { +      qWarning("TrueType font tqcontains a 'glyf' table without 2 byte padding"); +      defective = TRUE; +      return; +    } + +    /* Copy the bytes of the glyph. */ +    while( length-- ) { +      c = offset_table[ font_off ]; +      font_off++; + +      sfnts_pputBYTE(c, s, string_len, line_len, in_string); +      total++;          /* add to running total */ +    } +  } + +  /* Pad out to full length from table directory */ +  while( total < correct_total_length ) { +    sfnts_pputBYTE(0, s, string_len, line_len, in_string); +    total++; +  } + +  /* Look for unexplainable descrepancies between sizes */ +  if( total != correct_total_length ) { +    qWarning("TQPSPrinterFontTTF::sfnts_glyf_table: total != correct_total_length"); +    defective = TRUE; +    return; +  } +} + +/* +** Here is the routine which ties it all together. +** +** Create the array called "sfnts" which +** holds the actual TrueType data. +*/ + +void TQPSPrinterFontTTF::download_sfnts(TQTextStream& s) +{ +  // tables worth including in a type 42 font +  char *table_names[]= { +    "cvt ", +    "fpgm", +    "glyf", +    "head", +    "hhea", +    "hmtx", +    "loca", +    "maxp", +    "prep" +  }; + +  struct {                      /* The location of each of */ +    ULONG oldoffset;    /* the above tables. */ +    ULONG newoffset; +    ULONG length; +    ULONG checksum; +  } tables[9]; + +  int c;                        /* Input character. */ +  int diff; +  int count;                    /* How many `important' tables did we tqfind? */ + +  BYTE* ptr = offset_table + 12; // original table directory +  ULONG nextoffset=0; +  count=0; + +  /* +  ** Find the tables we want and store there vital +  ** statistics in tables[]. +  */ +  for(int x=0; x < 9; x++ ) { +    do { +      diff = strncmp( (char*)ptr, table_names[x], 4 ); + +      if( diff > 0 ) {          /* If we are past it. */ +        tables[x].length = 0; +        diff = 0; +      } +      else if( diff < 0 ) {             /* If we haven't hit it yet. */ +        ptr += 16; +      } +      else if( diff == 0 ) {    /* Here it is! */ +        tables[x].newoffset = nextoffset; +        tables[x].checksum = getULONG( ptr + 4 ); +        tables[x].oldoffset = getULONG( ptr + 8 ); +        tables[x].length = getULONG( ptr + 12 ); +        nextoffset += ( ((tables[x].length + 3) / 4) * 4 ); +        count++; +        ptr += 16; +      } +    } while(diff != 0); +  } /* end of for loop which passes over the table directory */ + +  /* Begin the sfnts array. */ + +  s << "/sfnts[<"; + +  bool in_string=TRUE; +  int  string_len=0; +  int  line_len=8; + +  /* Generate the offset table header */ +  /* Start by copying the TrueType version number. */ +  ptr = offset_table; +  for(int x=0; x < 4; x++) +    sfnts_pputBYTE( *(ptr++) , s, string_len, line_len, in_string ); + +  /* Now, generate those silly numTables numbers. */ +  sfnts_pputUSHORT(count,s, string_len, line_len, in_string);           /* number of tables */ +  if( count == 9 ) { +    sfnts_pputUSHORT(7,s, string_len, line_len, in_string);             /* searchRange */ +    sfnts_pputUSHORT(3,s, string_len, line_len, in_string);             /* entrySelector */ +    sfnts_pputUSHORT(81,s, string_len, line_len, in_string);            /* rangeShift */ +  } +  else { +    qWarning("Fewer than 9 tables selected"); +  } + +  /* Now, emmit the table directory. */ +  for(int x=0; x < 9; x++) { +    if( tables[x].length == 0 ) /* Skip missing tables */ +      continue; + +    /* Name */ +    sfnts_pputBYTE( table_names[x][0], s, string_len, line_len, in_string); +    sfnts_pputBYTE( table_names[x][1], s, string_len, line_len, in_string); +    sfnts_pputBYTE( table_names[x][2], s, string_len, line_len, in_string); +    sfnts_pputBYTE( table_names[x][3], s, string_len, line_len, in_string); + +    /* Checksum */ +    sfnts_pputULONG( tables[x].checksum, s, string_len, line_len, in_string ); + +    /* Offset */ +    sfnts_pputULONG( tables[x].newoffset + 12 + (count * 16), s, +                     string_len, line_len, in_string ); + +    /* Length */ +    sfnts_pputULONG( tables[x].length, s, +                     string_len, line_len, in_string ); +  } + +  /* Now, send the tables */ +  for(int x=0; x < 9; x++) { +    if( tables[x].length == 0 ) /* skip tables that aren't there */ +      continue; + +    /* 'glyf' table gets special treatment */ +    if( strcmp(table_names[x],"glyf")==0 ) { +      sfnts_glyf_table(tables[x].oldoffset,tables[x].length, s, +                       string_len, line_len, in_string); +    } else { // other tables should not exceed 64K (not always true; Sivan) +      if( tables[x].length > 65535 ) { +        qWarning("TrueType font has a table which is too long"); +        defective = TRUE; +        return; +      } + +      /* Start new string if necessary. */ +      sfnts_new_table(tables[x].length, s, +                      string_len, line_len, in_string); + +      int font_off = tables[x].oldoffset; +      /* Copy the bytes of the table. */ +      for( int y=0; y < (int)tables[x].length; y++ ) { +        c = offset_table[ font_off ]; +        font_off++; + +        sfnts_pputBYTE(c, s, string_len, line_len, in_string); +      } +    } + +    /* Padd it out to a four byte boundary. */ +    int y=tables[x].length; +    while( (y % 4) != 0 ) { +      sfnts_pputBYTE(0, s, string_len, line_len, in_string); +      y++; +    } + +  } /* End of loop for all tables */ + +  /* Close the array. */ +  sfnts_end_string(s, string_len, line_len, in_string); +  s << "]def\n"; +} +#endif + +// ****************** Type 3 CharProcs ******* + +/* +** This routine is used to break the character +** procedure up into a number of smaller +** procedures.  This is necessary so as not to +** overflow the stack on certain level 1 interpreters. +** +** Prepare to push another item onto the stack, +** starting a new proceedure if necessary. +** +** Not all the stack depth calculations in this routine +** are perfectly accurate, but they do the job. +*/ +static int stack_depth = 0; +static void stack(int num_pts, int newnew, TQTextStream& s) +{ +  if( num_pts > 25 ) {          /* Only do something of we will */ +                                /* have a log of points. */ +    if(stack_depth == 0) { +      s << "{"; +      stack_depth=1; +    } + +    stack_depth += newnew;              /* Account for what we propose to add */ + +    if(stack_depth > 100) { +      s << "}_e{"; +      stack_depth = 3 + newnew; /* A rough estimate */ +    } +  } +} + +static void stack_end(TQTextStream& s)                   /* called at end */ +{ +  if(stack_depth) { +    s << "}_e"; +    stack_depth=0; +  } +} + +// postscript drawing commands + +static void PSMoveto(FWord x, FWord y, TQTextStream& ts) +{ +  ts << x; +  ts << " "; +  ts << y; +  ts << " _m\n"; +} + +static void PSLineto(FWord x, FWord y, TQTextStream& ts) +{ +  ts << x; +  ts << " "; +  ts << y; +  ts << " _l\n"; +} + +/* Emmit a PostScript "curveto" command. */ +static void PSCurveto(FWord* xcoor, FWord* ycoor, +                      FWord x, FWord y, int s, int t, TQTextStream& ts) +{ +  int N, i; +  double sx[3], sy[3], cx[4], cy[4]; + +  N = t-s+2; +  for(i=0; i<N-1; i++) { +    sx[0] = i==0?xcoor[s-1]:(xcoor[i+s]+xcoor[i+s-1])/2; +    sy[0] = i==0?ycoor[s-1]:(ycoor[i+s]+ycoor[i+s-1])/2; +    sx[1] = xcoor[s+i]; +    sy[1] = ycoor[s+i]; +    sx[2] = i==N-2?x:(xcoor[s+i]+xcoor[s+i+1])/2; +    sy[2] = i==N-2?y:(ycoor[s+i]+ycoor[s+i+1])/2; +    cx[3] = sx[2]; +    cy[3] = sy[2]; +    cx[1] = (2*sx[1]+sx[0])/3; +    cy[1] = (2*sy[1]+sy[0])/3; +    cx[2] = (sx[2]+2*sx[1])/3; +    cy[2] = (sy[2]+2*sy[1])/3; + +    ts << (int)cx[1]; +    ts << " "; +    ts << (int)cy[1]; +    ts << " "; +    ts << (int)cx[2]; +    ts << " "; +    ts << (int)cy[2]; +    ts << " "; +    ts << (int)cx[3]; +    ts << " "; +    ts << (int)cy[3]; +    ts << " _c\n"; +  } +} + +/* The PostScript bounding box. */ +/* Variables to hold the character data. */ + +//void load_char(struct TTFONT *font, BYTE *glyph); +//void clear_data(); + +//void PSMoveto(FWord x, FWord y, TQTextStream& ts); +//void PSLineto(FWord x, FWord y, TQTextStream& ts); +//void PSCurveto(FWord x, FWord y, int s, int t, TQTextStream& ts); + +//double area(FWord *x, FWord *y, int n); +//int nextinctr(int co, int ci); +//int nextoutctr(int co); +//int nearout(int ci); +//double intest(int co, int ci); +#define sqr(x) ((x)*(x)) + +#define NOMOREINCTR -1 +#define NOMOREOUTCTR -1 + +/* +** Find the area of a contour? +*/ +static double area(FWord *x, FWord *y, int n) +{ +  int i; +  double sum; + +  sum=x[n-1]*y[0]-y[n-1]*x[0]; +  for (i=0; i<=n-2; i++) sum += x[i]*y[i+1] - y[i]*x[i+1]; +  return sum; +} + +static int nextoutctr(int /*co*/, charproc_data* cd) +{ +  int j; + +  for(j=0; j<cd->num_ctr; j++) +    if (cd->check_ctr[j]==0 && cd->area_ctr[j] < 0) { +      cd->check_ctr[j]=1; +      return j; +    } + +  return NOMOREOUTCTR; +} /* end of nextoutctr() */ + +static int nextinctr(int co, int /*ci*/, charproc_data* cd) +{ +  int j; + +  for(j=0; j<cd->num_ctr; j++) +    if (cd->ctrset[2*j+1]==co) +      if (cd->check_ctr[ cd->ctrset[2*j] ]==0) { +        cd->check_ctr[ cd->ctrset[2*j] ]=1; +        return cd->ctrset[2*j]; +      } + +  return NOMOREINCTR; +} + +static double intest( int co, int ci, charproc_data *cd ) +{ +    int i, j, start, end; +    double r1, r2; +    FWord xi[3], yi[3]; + +    j = start = ( co == 0 ) ? 0 : ( cd->epts_ctr[co - 1] + 1 ); +    end = cd->epts_ctr[co]; +    i = ( ci == 0 ) ? 0 : ( cd->epts_ctr[ci - 1] + 1 ); +    xi[0] = cd->xcoor[i]; +    yi[0] = cd->ycoor[i]; +    r1 = sqr( cd->xcoor[start] - xi[0] ) + sqr( cd->ycoor[start] - yi[0] ); + +    for ( i = start; i <= end; i++ ) { +	r2 = sqr( cd->xcoor[i] - xi[0] ) + sqr( cd->ycoor[i] - yi[0] ); +	if ( r2 < r1 ) { +	    r1 = r2; +	    j = i; +	} +    } +    if ( j == start ) { +	xi[1] = cd->xcoor[end]; +	yi[1] = cd->ycoor[end]; +    } else { +	xi[1] = cd->xcoor[j - 1]; +	yi[1] = cd->ycoor[j - 1]; +    } +    if ( j == end ) { +	xi[2] = cd->xcoor[start]; +	yi[2] = cd->ycoor[start]; +    } else { +	xi[2] = cd->xcoor[j + 1]; +	yi[2] = cd->ycoor[j + 1]; +    } +    return area( xi, yi, 3 ); +} + +/* +** tqfind the nearest out contour to a specified in contour. +*/ +static int nearout(int ci, charproc_data* cd) +{ +  int k = 0;                    /* !!! is this right? */ +  int co; +  double a, a1=0; + +  for (co=0; co < cd->num_ctr; co++) { +    if(cd->area_ctr[co] < 0) { +      a=intest(co,ci, cd); +      if (a<0 && a1==0) { +        k=co; +        a1=a; +      } +      if(a<0 && a1!=0 && a>a1) { +        k=co; +        a1=a; +      } +    } +  } + +  return k; +} /* end of nearout() */ + + +/* +** We call this routine to emmit the PostScript code +** for the character we have loaded with load_char(). +*/ +static void PSConvert(TQTextStream& s, charproc_data* cd) +{ +  int i,j,k,fst,start_offpt; +  int end_offpt=0; + +  cd->area_ctr = new double[cd->num_ctr]; +  memset(cd->area_ctr, 0, (cd->num_ctr*sizeof(double))); + +  cd->check_ctr = new char[cd->num_ctr]; +  memset(cd->check_ctr, 0, (cd->num_ctr*sizeof(char))); + +  cd->ctrset = new int[2*(cd->num_ctr)]; +  memset(cd->ctrset, 0, (cd->num_ctr*2*sizeof(int))); + +  cd->check_ctr[0]=1; +  cd->area_ctr[0]=area(cd->xcoor, cd->ycoor, cd->epts_ctr[0]+1); + +  for (i=1; i<cd->num_ctr; i++) +    cd->area_ctr[i]=area(cd->xcoor+cd->epts_ctr[i-1]+1, +                         cd->ycoor+cd->epts_ctr[i-1]+1, +                         cd->epts_ctr[i]-cd->epts_ctr[i-1]); + +  for (i=0; i<cd->num_ctr; i++) { +    if (cd->area_ctr[i]>0) { +      cd->ctrset[2*i]=i; +      cd->ctrset[2*i+1]=nearout(i,cd); +    } else { +      cd->ctrset[2*i]=-1; +      cd->ctrset[2*i+1]=-1; +    } +  } + +  /* Step thru the coutours. */ +  /* I believe that a contour is a detatched */ +  /* set of curves and lines. */ +  i=j=k=0; +  while (i < cd->num_ctr ) { +    fst = j = (k==0) ? 0 : (cd->epts_ctr[k-1]+1); + +    /* Move to the first point on the contour. */ +    stack(cd->num_pts,3,s); +    PSMoveto(cd->xcoor[j],cd->ycoor[j],s); +    start_offpt = 0;            /* No off curve points yet. */ + +    /* Step thru the remaining points of this contour. */ +    for(j++; j <= cd->epts_ctr[k]; j++) { +      if (!(cd->tt_flags[j]&1)) { /* Off curve */ +        if (!start_offpt) +          { start_offpt = end_offpt = j; } +        else +          end_offpt++; +      } else {                  /* On Curve */ +        if (start_offpt) { +          stack(cd->num_pts,7,s); +          PSCurveto(cd->xcoor,cd->ycoor, +                    cd->xcoor[j],cd->ycoor[j], +                    start_offpt,end_offpt,s); +          start_offpt = 0; +        } else { +          stack(cd->num_pts,3,s); +          PSLineto(cd->xcoor[j], cd->ycoor[j],s); +        } +      } +    } + +    /* Do the final curve or line */ +    /* of this coutour. */ +    if (start_offpt) { +      stack(cd->num_pts,7,s); +      PSCurveto(cd->xcoor,cd->ycoor, +                cd->xcoor[fst],cd->ycoor[fst], +                start_offpt,end_offpt,s); +    } else { +      stack(cd->num_pts,3,s); +      PSLineto(cd->xcoor[fst],cd->ycoor[fst],s); +    } + +    k=nextinctr(i,k,cd); + +    if (k==NOMOREINCTR) +      i=k=nextoutctr(i,cd); + +    if (i==NOMOREOUTCTR) +      break; +  } + +  /* Now, we can fill the whole thing. */ +  stack(cd->num_pts,1,s); +  s << "_cl";           /* "closepath eofill" */ + +  /* Free our work arrays. */ +  delete [] cd->area_ctr; +  delete [] cd->check_ctr; +  delete [] cd->ctrset; +} + + +/* +** Load the simple glyph data pointed to by glyph. +** The pointer "glyph" should point 10 bytes into +** the glyph data. +*/ +void TQPSPrinterFontTTF::charprocLoad(BYTE *glyph, charproc_data* cd) +{ +  int x; +  BYTE c, ct; + +  /* Read the contour endpoints list. */ +  cd->epts_ctr = new int[cd->num_ctr]; +  //cd->epts_ctr = (int *)myalloc(cd->num_ctr,sizeof(int)); +  for (x = 0; x < cd->num_ctr; x++) { +    cd->epts_ctr[x] = getUSHORT(glyph); +    glyph += 2; +  } + +  /* From the endpoint of the last contour, we can */ +  /* determine the number of points. */ +  cd->num_pts = cd->epts_ctr[cd->num_ctr-1]+1; +#ifdef DEBUG_TRUETYPE +  fprintf(stderr,"num_pts=%d\n",cd->num_pts); +#endif + +  /* Skip the instructions. */ +  x = getUSHORT(glyph); +  glyph += 2; +  glyph += x; + +  /* Allocate space to hold the data. */ +  //cd->tt_flags = (BYTE *)myalloc(num_pts,sizeof(BYTE)); +  //cd->xcoor    = (FWord *)myalloc(num_pts,sizeof(FWord)); +  //cd->ycoor    = (FWord *)myalloc(num_pts,sizeof(FWord)); +  cd->tt_flags = new BYTE[cd->num_pts]; +  cd->xcoor    = new FWord[cd->num_pts]; +  cd->ycoor    = new FWord[cd->num_pts]; + +  /* Read the flags array, uncompressing it as we go. */ +  /* There is danger of overflow here. */ +  for (x = 0; x < cd->num_pts; ) { +    cd->tt_flags[x++] = c = *(glyph++); + +    if (c&8) {          /* If next byte is repeat count, */ +      ct = *(glyph++); + +      if( (x + ct) > cd->num_pts ) { +        qWarning("Fatal Error in TT flags"); +        return; +      } + +      while (ct--) +        cd->tt_flags[x++] = c; +    } +  } + +  /* Read the x coordinates */ +  for (x = 0; x < cd->num_pts; x++) { +    if (cd->tt_flags[x] & 2) {          /* one byte value with */ +                                        /* external sign */ +      c = *(glyph++); +      cd->xcoor[x] = (cd->tt_flags[x] & 0x10) ? c : (-1 * (int)c); +    } else if(cd->tt_flags[x] & 0x10) { /* repeat last */ +      cd->xcoor[x] = 0; +    } else {                            /* two byte signed value */ +      cd->xcoor[x] = getFWord(glyph); +      glyph+=2; +    } +  } + +  /* Read the y coordinates */ +  for(x = 0; x < cd->num_pts; x++) { +    if (cd->tt_flags[x] & 4) {          /* one byte value with */ +                                        /* external sign */ +      c = *(glyph++); +      cd->ycoor[x] = (cd->tt_flags[x] & 0x20) ? c : (-1 * (int)c); +    } else if (cd->tt_flags[x] & 0x20) {        /* repeat last value */ +      cd->ycoor[x] = 0; +    } else {                    /* two byte signed value */ +      cd->ycoor[x] = getUSHORT(glyph); +      glyph+=2; +    } +  } + +  /* Convert delta values to absolute values. */ +  for(x = 1; x < cd->num_pts; x++) { +    cd->xcoor[x] += cd->xcoor[x-1]; +    cd->ycoor[x] += cd->ycoor[x-1]; +  } + +  for(x=0; x < cd->num_pts; x++) { +    cd->xcoor[x] = topost(cd->xcoor[x]); +    cd->ycoor[x] = topost(cd->ycoor[x]); +  } +} + +#define ARG_1_AND_2_ARE_WORDS 1 +#define ARGS_ARE_XY_VALUES 2 +#define ROUND_XY_TO_GRID 4 +#define WE_HAVE_A_SCALE 8 +/* RESERVED 16 */ +#define MORE_COMPONENTS 32 +#define WE_HAVE_AN_X_AND_Y_SCALE 64 +#define WE_HAVE_A_TWO_BY_TWO 128 +#define WE_HAVE_INSTRUCTIONS 256 +#define USE_MY_METRICS 512 + +void TQPSPrinterFontTTF::subsetGlyph(int charindex,bool* glyphset) +{ +  USHORT flags; +  USHORT glyphIndex; +  charproc_data cd; + +  glyphset[charindex] = TRUE; +  //printf("subsetting %s ==> ",glyphName(charindex).latin1()); + +  /* Get a pointer to the data. */ +  BYTE* glyph = charprocFindGlyphData( charindex ); + +  /* If the character is blank, it has no bounding box, */ +  /* otherwise read the bounding box. */ +  if( glyph == (BYTE*)NULL ) { +    cd.num_ctr=0; +  } else { +    cd.num_ctr = getSHORT(glyph); +    /* Advance the pointer past bounding box. */ +    glyph += 10; +  } + +  if( cd.num_ctr < 0 ) { // composite +    /* Once around this loop for each component. */ +    do { +      flags = getUSHORT(glyph); /* read the flags word */ +      glyph += 2; +      glyphIndex = getUSHORT(glyph);    /* read the glyphindex word */ +      glyph += 2; + +      glyphset[ glyphIndex ] = TRUE; +      subsetGlyph( glyphIndex, glyphset ); +      //printf("subset tqcontains: %d %s ",glyphIndex, glyphName(glyphIndex).latin1()); + +      if(flags & ARG_1_AND_2_ARE_WORDS) { +        glyph += 2; +        glyph += 2; +      } else { +        glyph += 1; +        glyph += 1; +      } + +      if(flags & WE_HAVE_A_SCALE) { +        glyph += 2; +      } else if(flags & WE_HAVE_AN_X_AND_Y_SCALE) { +        glyph += 2; +        glyph += 2; +      } else if(flags & WE_HAVE_A_TWO_BY_TWO) { +        glyph += 2; +        glyph += 2; +        glyph += 2; +        glyph += 2; +      } else { +      } +    } while(flags & MORE_COMPONENTS); +  } +  //printf("\n"); +} + + +/* +** Emmit PostScript code for a composite character. +*/ +void TQPSPrinterFontTTF::charprocComposite(BYTE *glyph, TQTextStream& s, bool *glyphSet) +{ +  USHORT flags; +  USHORT glyphIndex; +  int arg1; +  int arg2; +  float xscale = 1; +  float yscale = 1; +#ifdef DEBUG_TRUETYPE +  float scale01 = 0; +  float scale10 = 0; +#endif + +  /* Once around this loop for each component. */ +  do { +      flags = getUSHORT(glyph);   /* read the flags word */ +      glyph += 2; + +      glyphIndex = getUSHORT(glyph);      /* read the glyphindex word */ +      glyph += 2; + +      if(flags & ARG_1_AND_2_ARE_WORDS) { +                                /* The tt spec. seems to say these are signed. */ +	  arg1 = getSHORT(glyph); +	  glyph += 2; +	  arg2 = getSHORT(glyph); +	  glyph += 2; +      } else {                    /* The tt spec. does not clearly indicate */ +                                /* whether these values are signed or not. */ +	  arg1 = (char)*(glyph++); +	  arg2 = (char)*(glyph++); +      } + +      if(flags & WE_HAVE_A_SCALE) { +	  xscale = yscale = f2dot14( getUSHORT(glyph) ); +	  glyph += 2; +      } else if(flags & WE_HAVE_AN_X_AND_Y_SCALE) { +	  xscale = f2dot14( getUSHORT(glyph) ); +	  glyph += 2; +	  yscale = f2dot14( getUSHORT(glyph) ); +	  glyph += 2; +      } else if(flags & WE_HAVE_A_TWO_BY_TWO) { +	  xscale = f2dot14( getUSHORT(glyph) ); +	  glyph += 2; +#ifdef DEBUG_TRUETYPE +	  scale01 = f2dot14( getUSHORT(glyph) ); +#endif +	  glyph += 2; +#ifdef DEBUG_TRUETYPE +	  scale10 = f2dot14( getUSHORT(glyph) ); +#endif +	  glyph += 2; +	  yscale = f2dot14( getUSHORT(glyph) ); +	  glyph += 2; +      } + +      /* Debugging */ +#ifdef DEBUG_TRUETYPE +      s << "% flags=" << flags << ", arg1=" << arg1 << ", arg2=" << arg2 << ", xscale=" << xscale << ", yscale=" << yscale << +	  ", scale01=" << scale01 << ", scale10=" << scale10 << endl; +#endif + + +      if ( (flags & ARGS_ARE_XY_VALUES) != ARGS_ARE_XY_VALUES ) { +	  s << "% unimplemented shift, arg1=" << arg1; +	  s << ", arg2=" << arg2 << "\n"; +	  arg1 = arg2 = 0; +      } + +      /* If we have an (X,Y) shif and it is non-zero, */ +      /* translate the coordinate system. */ +      if ( flags & (WE_HAVE_A_TWO_BY_TWO|WE_HAVE_AN_X_AND_Y_SCALE) ) { +#if 0 +	  // code similar to this would be needed for two_by_two +	  s << "gsave [ " << xscale << " " << scale01 << " " << scale10 << " " +	    << yscale << " " << topost(arg1) << " " << topost(arg2) << "] SM\n"; +#endif +	  if ( flags & WE_HAVE_A_TWO_BY_TWO ) +	      s << "% Two by two transformation, unimplemented\n"; +	  s << "gsave " << topost(arg1); +	  s << " " << topost(arg2); +	  s << " translate\n"; +	  s << xscale << " " << yscale << " scale\n"; +      } else if ( flags & ARGS_ARE_XY_VALUES && ( arg1 != 0 || arg2 != 0 ) ) { +	  s << "gsave " << topost(arg1); +	  s << " " << topost(arg2); +	  s << " translate\n"; +      } + +      /* Invoke the CharStrings procedure to print the component. */ +      s << "false CharStrings /"; +      s << glyphName( glyphIndex, glyphSet ); +      s << " get exec\n"; + +      //  printf("false CharStrings /%s get exec\n", +      //ttfont_CharStrings_getname(font,glyphIndex)); + +      /* If we translated the coordinate system, */ +      /* put it back the way it was. */ +      if( (flags & ARGS_ARE_XY_VALUES && (arg1 != 0 || arg2 != 0) ) || +	  ( flags & (WE_HAVE_A_TWO_BY_TWO|WE_HAVE_AN_X_AND_Y_SCALE) ) ) { +	  s << "grestore "; +      } +  } while (flags & MORE_COMPONENTS); +} + +/* +** Return a pointer to a specific glyph's data. +*/ +BYTE* TQPSPrinterFontTTF::charprocFindGlyphData(int charindex) +{ +  ULONG off; +  ULONG length; + +  /* Read the glyph offset from the index to location table. */ +  if(indexToLocFormat == 0) { +    off = getUSHORT( loca_table + (charindex * 2) ); +    off *= 2; +    length = getUSHORT( loca_table + ((charindex+1) * 2) ); +    length *= 2; +    length -= off; +  } else { +    off = getULONG( loca_table + (charindex * 4) ); +    length = getULONG( loca_table + ((charindex+1) * 4) ); +    length -= off; +  } + +  if(length > 0) +    return glyf_table + off; +  else +    return (BYTE*)NULL; +} + +void TQPSPrinterFontTTF::charproc(int charindex, TQTextStream& s, bool *glyphSet ) +{ +  int llx,lly,urx,ury; +  int advance_width; +  charproc_data cd; + +#ifdef DEBUG_TRUETYPE +  s << "% tt_type3_charproc for "; +  s << charindex; +  s << "\n"; +#endif + +  /* Get a pointer to the data. */ +  BYTE* glyph = charprocFindGlyphData( charindex ); + +  /* If the character is blank, it has no bounding box, */ +  /* otherwise read the bounding box. */ +  if( glyph == (BYTE*)NULL ) { +    llx=lly=urx=ury=0;  /* A blank char has an all zero BoundingBox */ +    cd.num_ctr=0;               /* Set this for later if()s */ +  } else { +    /* Read the number of contours. */ +    cd.num_ctr = getSHORT(glyph); + +    /* Read PostScript bounding box. */ +    llx = getFWord(glyph + 2); +    lly = getFWord(glyph + 4); +    urx = getFWord(glyph + 6); +    ury = getFWord(glyph + 8); + +    /* Advance the pointer. */ +    glyph += 10; +  } + +  /* If it is a simple character, load its data. */ +  if (cd.num_ctr > 0) +    charprocLoad(glyph, &cd); +  else +    cd.num_pts=0; + +  /* Consult the horizontal metrics table to determine */ +  /* the character width. */ +  if( charindex < numberOfHMetrics ) +    advance_width = getuFWord( hmtx_table + (charindex * 4) ); +  else +    advance_width = getuFWord( hmtx_table + ((numberOfHMetrics-1) * 4) ); + +  /* Execute setcachetqdevice in order to inform the font machinery */ +  /* of the character bounding box and advance width. */ +  stack(cd.num_pts,7,s); +  s << topost(advance_width); +  s << " 0 "; +  s << topost(llx); +  s << " "; +  s << topost(lly); +  s << " "; +  s << topost(urx); +  s << " "; +  s << topost(ury); +  s << " _sc\n"; + +  /* If it is a simple glyph, convert it, */ +  /* otherwise, close the stack business. */ +  if( cd.num_ctr > 0 ) {        // simple +    PSConvert(s,&cd); +    delete [] cd.tt_flags; +    delete [] cd.xcoor; +    delete [] cd.ycoor; +    delete [] cd.epts_ctr; +  } else if( cd.num_ctr < 0 ) { // composite +    charprocComposite(glyph,s, glyphSet); +  } + +  stack_end(s); +} /* end of tt_type3_charproc() */ + + +// ================== PFA ==================== + +class TQPSPrinterFontPFA +    : public TQPSPrinterFontPrivate { +public: +    TQPSPrinterFontPFA(const TQFontEngine *f, TQByteArray& data); +    virtual void    download(TQTextStream& s, bool global); +    virtual bool embedded() { return TRUE; } +private: +    TQByteArray     data; +}; + +TQPSPrinterFontPFA::TQPSPrinterFontPFA(const TQFontEngine *f, TQByteArray& d) +{ +  data = d; + +  int pos = 0; +  char* p = data.data(); +  TQString fontname; + +  if (p[ pos ] != '%' || p[ pos+1 ] != '!') { // PFA marker +    qWarning("invalid pfa file"); +    return; +  } + +  char* fontnameptr = strstr(p+pos,"/FontName"); +  if (fontnameptr == NULL) +    return; + +  fontnameptr += strlen("/FontName") + 1; +  while (*fontnameptr == ' ' || *fontnameptr == '/') fontnameptr++; +  int l=0; +  while (fontnameptr[l] != ' ') l++; + +  psname = TQString::tqfromLatin1(fontnameptr,l); +  tqreplacementList = makePSFontNameList( f, psname ); +} + +void TQPSPrinterFontPFA::download(TQTextStream& s, bool global) +{ +    emitPSFontNameList( s, psname, tqreplacementList); + +    if ( !embedFonts ) { +        downloadMapping(s, global); +        return; +    } +     +    //qDebug("downloading pfa font %s", psname.latin1() ); +    char* p = data.data(); +     +    s << "% Font resource\n"; +    for (int i=0; i < (int)data.size(); i++) s << p[i]; +    s << "% End of font resource\n"; +    downloadMapping( s, global ); +} + +// ================== PFB ==================== + +class TQPSPrinterFontPFB +    : public TQPSPrinterFontPrivate { +public: +    TQPSPrinterFontPFB(const TQFontEngine *f, TQByteArray& data); +    virtual void    download(TQTextStream& s, bool global); +    virtual bool embedded() { return TRUE; } +private: +    TQByteArray     data; +}; + +TQPSPrinterFontPFB::TQPSPrinterFontPFB(const TQFontEngine *f, TQByteArray& d) +{ +  data = d; + +  int pos = 0; +  int len; +  //  int typ; +  unsigned char* p = (unsigned char*) data.data(); +  TQString fontname; + +  if (p[ pos ] != 0x80) { // PFB marker +    qWarning("pfb file does not start with 0x80"); +    return; +  } +  pos++; +  //  typ = p[ pos ]; // 1=ascii 2=binary 3=done +  pos++; +  len = p[ pos ];          pos++; +  len |= (p[ pos ] << 8) ; pos++; +  len |= (p[ pos ] << 16); pos++; +  len |= (p[ pos ] << 24); pos++; + +  //printf("font block type %d len %d\n",typ,len); + +  char* fontnameptr = strstr((char*)p+pos,"/FontName"); +  if (fontnameptr == NULL) +    return; + +  fontnameptr += strlen("/FontName") + 1; +  while (*fontnameptr == ' ' || *fontnameptr == '/') fontnameptr++; +  int l=0; +  while (fontnameptr[l] != ' ') l++; + +  psname = TQString::tqfromLatin1(fontnameptr,l); +  tqreplacementList = makePSFontNameList( f, psname ); +} + +void TQPSPrinterFontPFB::download(TQTextStream& s, bool global) +{ +    emitPSFontNameList( s, psname, tqreplacementList); +     +    if ( !embedFonts ) { +        downloadMapping(s, global); +        return; +    } +     +    //qDebug("downloading pfb font %s", psname.latin1() ); +    unsigned char* p = (unsigned char*) data.data(); +    int pos; +    int len; +    int typ; + +    int hexcol = 0; +    int line_length = 64; + +    s << "% Font resource\n"; + +    pos = 0; +    typ = -1; +    while (typ != 3) { // not end of file +	if (p[ pos ] != 0x80) // PFB marker +	    return; // pfb file does not start with 0x80 +	pos++; +	typ = p[ pos ]; // 1=ascii 2=binary 3=done +	pos++; + +	if (typ == 3) break; + +	len = p[ pos ];         pos++; +	len |= (p[ pos ] << 8) ; pos++; +	len |= (p[ pos ] << 16); pos++; +	len |= (p[ pos ] << 24); pos++; + +	//qDebug("font block type %d len %d",typ,len); + +	int end = pos + len; +	if (typ==1) { +	    while (pos < end) { +		if (hexcol > 0) { +		    s << "\n"; +		    hexcol = 0; +		} +		//qWarning(TQString::tqfromLatin1((char*)(p+pos),1)); +		if (p[pos] == '\r' || p[pos] == '\n') { +		    s << "\n"; +		    while (pos < end && (p[pos] == '\r' || p[pos] == '\n')) +			pos++; +		} else { +		    s << TQString::tqfromLatin1((char*)(p+pos),1); +		    pos++; +		} +	    } +	} +	if (typ==2) { +	    static const char *hexchar = "0123456789abcdef"; +	    while (pos < end) { +		/* trim hexadecimal lines to line_length columns */ +		if (hexcol >= line_length) { +		    s << "\n"; +		    hexcol = 0; +		} +		s << TQString::tqfromLatin1(hexchar+((p[pos] >> 4) & 0xf),1) +		  << TQString::tqfromLatin1(hexchar+((p[pos]     ) & 0xf),1); +		pos++; +		hexcol += 2; +	    } +	} +    } +    s << "% End of font resource\n"; +    downloadMapping( s, global ); +} + +// ================== AFontFileNotFound ============ + + + +class TQPSPrinterFontNotFound +  : public TQPSPrinterFontPrivate { +public: +  TQPSPrinterFontNotFound(const TQFontEngine* f); +  virtual void    download(TQTextStream& s, bool global); +private: +  TQByteArray     data; +}; + +TQPSPrinterFontNotFound::TQPSPrinterFontNotFound(const TQFontEngine* f) +{ +    psname = makePSFontName( f ); +    tqreplacementList = makePSFontNameList( f ); +} + +void TQPSPrinterFontNotFound::download(TQTextStream& s, bool) +{ +    //qDebug("downloading not found font %s", psname.latin1() ); +    emitPSFontNameList( s, psname, tqreplacementList ); +    s << "% No embeddable font for "; +    s << psname; +    s << " found\n"; +    TQPSPrinterFontPrivate::download(s, TRUE); +} + +#ifndef TQT_NO_TEXTCODEC +// =================== A font file for asian ============ + +class TQPSPrinterFontAsian +  : public TQPSPrinterFontPrivate { +public: +      TQPSPrinterFontAsian() +	  : TQPSPrinterFontPrivate(), codec( 0 ) {} +      void download(TQTextStream& s, bool global); +      TQString defineFont( TQTextStream &stream, const TQString &ps, const TQFont &f, const TQString &key, +                          TQPSPrinterPrivate *d ); +      void drawText( TQTextStream &stream, const TQPoint &p, TQTextEngine *engine, int item, +                     const TQString &text, TQPSPrinterPrivate *d, TQPainter *paint ); + +      TQString makePSFontName( const TQFontEngine *f, int type ) const; +      virtual TQString extension() const = 0; + +      TQTextCodec *codec; +}; + +TQString TQPSPrinterFontAsian::makePSFontName( const TQFontEngine *f, int type ) const +{ +    TQString ps; +    int i; + +    TQString family = f->fontDef.family.lower(); + +    // try to make a "good" postscript name +    ps = family.simplifyWhiteSpace(); +    i = 0; +    while( (unsigned int)i < ps.length() ) { +        if ( i != 0 && ps[i] == '[') { +          if ( ps[i-1] == ' ' ) +	    ps.truncate (i-1); +          else +	    ps.truncate (i); +          break; +        } +	if ( i == 0 || ps[i-1] == ' ' ) { +	    ps[i] = ps[i].upper(); +	    if ( i ) +		ps.remove( i-1, 1 ); +	    else +		i++; +	} else { +	    i++; +	} +    } + +    switch ( type ) { +	case 1: +	    ps.append( TQString::tqfromLatin1("-Italic") ); +	    break; +	case 2: +	    ps.append( TQString::tqfromLatin1("-Bold") ); +	    break; +	case 3: +	    ps.append( TQString::tqfromLatin1("-BoldItalic") ); +	    break; +	case 0: +	default: +	    break; +    } + +    ps += extension(); + +    return ps; +} + + +TQString TQPSPrinterFontAsian::defineFont( TQTextStream &stream, const TQString &ps, const TQFont &f, +					 const TQString &key, TQPSPrinterPrivate *d) +{ +    TQString fontName; +    TQString fontName2; + +    TQString *tmp = d->headerFontNames.tqfind( ps ); + +    if ( d->buffer ) { +        if ( tmp ) { +            fontName = *tmp; +        } else { +	    fontName.sprintf( "F%d", ++d->headerFontNumber ); +	    d->fontStream << "/" << fontName << " false " << ps << "List MF\n"; +	    d->headerFontNames.insert( ps, new TQString( fontName ) ); +	} +        fontName2.sprintf( "F%d", ++d->headerFontNumber ); +        d->fontStream << "/" << fontName2 << " " +                      << pointSize( f, d->scale ) << "/" << fontName << " DF\n"; +        d->headerFontNames.insert( key, new TQString( fontName2 ) ); +    } else { +        if ( tmp ) { +            fontName = *tmp; +        } else { +	    fontName.sprintf( "F%d", ++d->pageFontNumber ); +	    stream << "/" << fontName << " false " << ps << "List MF\n"; +	    d->pageFontNames.insert( ps, new TQString( fontName ) ); +	} +        fontName2.sprintf( "F%d", ++d->pageFontNumber ); +        stream << "/" << fontName2 << " " +               << pointSize( f, d->scale ) << "/" << fontName << " DF\n"; +        d->pageFontNames.insert( key, new TQString( fontName2 ) ); +    } +    return fontName2; +} + + +void TQPSPrinterFontAsian::download(TQTextStream& s, bool) +{ +    //qDebug("downloading asian font %s", psname.latin1() ); +    s << "% Asian postscript font requested. Using " +      << psname << endl; +    emitPSFontNameList( s, psname, tqreplacementList ); +} + +void TQPSPrinterFontAsian::drawText( TQTextStream &stream, const TQPoint &p, TQTextEngine *engine, int item, +				    const TQString &text, TQPSPrinterPrivate *d, TQPainter *paint) +{ +    int len = engine->length( item ); +    TQScriptItem &si = engine->items[item]; + +    int x = p.x() + si.x; +    int y = p.y() + si.y; +    if ( y != d->textY || d->textY == 0 ) +        stream << y << " Y"; +    d->textY = y; + +    TQString mdf; +    if ( paint->font().underline() ) +        mdf += " " + TQString().setNum( y + d->fm.underlinePos() + d->fm.lineWidth() ) + +               " " + toString( d->fm.lineWidth() ) + " Tl"; +    if ( paint->font().strikeOut() ) +        mdf += " " + TQString().setNum( y + d->fm.strikeOutPos() ) + +               " " + toString( d->fm.lineWidth() ) + " Tl"; +    TQCString mb; +    TQCString out; +    TQString dummy( TQChar(0x20) ); + +    if ( si.analysis.bidiLevel % 2 ) { +	for ( int i = len-1; i >= 0; i-- ) { +	    TQChar ch = text.tqunicode()[i]; +	    if ( !ch.row() ) { +		; // ignore, we should never get here anyway +	    } else { +		if ( codec ) { +		    dummy[0] = ch; +		    mb = codec->fromUnicode( dummy ); +		} else +		    mb = "  "; + +		for ( unsigned int j = 0; j < mb.length (); j++ ) { +		    if ( mb.at(j) == '(' || mb.at(j) == ')' || mb.at(j) == '\\' ) +			out += "\\"; +		    out += mb.at(j); +		} +	    } +	} +    } else { +	for ( int i = 0; i < len; i++ ) { +	    TQChar ch = text.tqunicode()[i]; +	    if ( !ch.row() ) { +		; // ignore, we should never get here anyway +	    } else { +		if ( codec ) { +		    dummy[0] = ch; +		    mb = codec->fromUnicode( dummy ); +		} else +		    mb = "  "; + +		for ( unsigned int j = 0; j < mb.length (); j++ ) { +		    if ( mb.at(j) == '(' || mb.at(j) == ')' || mb.at(j) == '\\' ) +			out += "\\"; +		    out += mb.at(j); +		} +	    } +	} +    } +    stream << "(" << out << ")" << si.width << " " << x << mdf << " AT\n"; +} + +// ----------- Japanese -------------- + +static const psfont Japanese1 [] = { +    { "Ryumin-Light-H", 0, 100. }, +    { "Ryumin-Light-H", 0.2, 100. }, +    { "GothicBBB-Medium-H", 0, 100. }, +    { "GothicBBB-Medium-H", 0.2, 100. } +}; + +static const psfont Japanese1a [] = { +    { "GothicBBB-Medium-H", 0, 100. }, +    { "GothicBBB-Medium-H", 0.2, 100. }, +    { "Ryumin-Light-H", 0, 100. }, +    { "Ryumin-Light-H", 0.2, 100. } +}; + +static const psfont Japanese2 [] = { +    { "GothicBBB-Medium-H", 0, 100. }, +    { "GothicBBB-Medium-H", 0.2, 100. }, +    { "GothicBBB-Medium-H", 0, 100. }, +    { "GothicBBB-Medium-H", 0.2, 100. } +}; + +static const psfont Japanese2a [] = { +    { "Ryumin-Light-H", 0, 100. }, +    { "Ryumin-Light-H", 0.2, 100. }, +    { "Ryumin-Light-H", 0, 100. }, +    { "Ryumin-Light-H", 0.2, 100. } +}; + + +// Wadalab fonts + +static const psfont WadaMin [] = { +    { "WadaMin-Regular-H", 0, 100. }, +    { "WadaMin-Regular-H", 0.2, 100. }, +    { "WadaMin-Bold-H", 0, 100. }, +    { "WadaMin-Bold-H", 0.2, 100. } +}; + +static const psfont WadaGo [] = { +    { "WadaMaruGo-Regular-H", 0, 100. }, +    { "WadaMaruGo-Regular-H", 0.2, 100. }, +    { "WadaGo-Bold-H", 0, 100. }, +    { "WadaGo-Bold-H", 0.2, 100. } +}; + +// Adobe Wadalab + +static const psfont WadaGoAdobe [] = { +    { "WadaMaruGo-RegularH-Hojo-H", 0, 100. }, +    { "WadaMaruGo-RegularH-Hojo-H", 0.2, 100. }, +    { "WadaMaruGo-RegularH-Hojo-H", 0, 100. }, +    { "WadaMaruGo-RegularH-Hojo-H", 0.2, 100. }, +}; +static const psfont WadaMinAdobe [] = { +    { "WadaMin-RegularH-Hojo-H", 0, 100. }, +    { "WadaMin-RegularH-Hojo-H", 0.2, 100. }, +    { "WadaMin-RegularH-Hojo-H", 0, 100. }, +    { "WadaMin-RegularH-Hojo-H", 0.2, 100. }, +}; + + +static const psfont * const Japanese1Replacements[] = { +    Japanese1, Japanese1a, WadaMin, WadaGo, WadaMinAdobe, WadaGoAdobe, 0 +}; +static const psfont * const Japanese2Replacements[] = { +    Japanese2, Japanese2a, WadaMin, WadaGo, WadaMinAdobe, WadaGoAdobe, 0 +}; + +class TQPSPrinterFontJapanese +  : public TQPSPrinterFontAsian { +public: +      TQPSPrinterFontJapanese(const TQFontEngine* f); +      virtual TQString extension() const; +}; + +TQPSPrinterFontJapanese::TQPSPrinterFontJapanese(const TQFontEngine* f) +{ +    codec = TQTextCodec::codecForMib( 63 ); // jisx0208.1983-0 + +    int type = getPsFontType( f ); +    psname = makePSFontName( f, type ); +    TQString best = "[ /" + psname + " 1.0 0.0 ]"; +    tqreplacementList.append( best ); + +    const psfont *const *tqreplacements = ( psname.tqcontains( "Helvetica" ) ? Japanese2Replacements : Japanese1Replacements ); +    appendReplacements( tqreplacementList, tqreplacements, type ); +} + +TQString TQPSPrinterFontJapanese::extension() const +{ +    return "-H"; +} + +// ----------- Korean -------------- + +// sans serif +static const psfont SMGothic [] = { +    { "SMGothic-Medium-KSC-EUC-H", 0, 100. }, +    { "SMGothic-Medium-KSC-EUC-H", 0.2, 100. }, +    { "SMGothic-DemiBold-KSC-EUC-H", 0, 100. }, +    { "SMGothic-DemiBold-KSC-EUC-H", 0.2, 100. } +}; + +// serif +#if 0 // ### this is never used? +static const psfont SMMyungjo [] = { +    { "SMMyungjo-Light-KSC-EUC-H", 0, 100. }, +    { "SMMyungjo-Light-KSC-EUC-H", 0.2, 100. }, +    { "SMMyungjo-Bold-KSC-EUC-H", 0, 100. }, +    { "SMMyungjo-Bold-KSC-EUC-H", 0.2, 100. } +}; +#endif + +static const psfont MKai [] = { +    { "MingMT-Light-KSC-EUC-H", 0, 100. }, +    { "MingMT-Light-KSC-EUC-H", 0.2, 100. }, +    { "MKai-Medium-KSC-EUC-H", 0, 100. }, +    { "MKai-Medium-KSC-EUC-H", 0.2, 100. }, +}; + + +static const psfont Munhwa [] = { +    { "Munhwa-Regular-KSC-EUC-H", 0, 100. }, +    { "Munhwa-Regular-KSC-EUC-H", 0.2, 100. }, +    { "Munhwa-Bold-KSC-EUC-H", 0, 100. }, +    { "Munhwa-Bold-KSC-EUC-H", 0.2, 100. } +}; + +static const psfont MunhwaGothic [] = { +    { "MunhwaGothic-Regular-KSC-EUC-H", 0, 100. }, +    { "MunhwaGothic-Regular-KSC-EUC-H", 0.2, 100. }, +    { "MunhwaGothic-Bold-KSC-EUC-H", 0, 100. }, +    { "MunhwaGothic-Bold-KSC-EUC-H", 0.2, 100. } +}; + +static const psfont MunhwaGungSeo [] = { +    { "MunhwaGungSeo-Light-KSC-EUC-H", 0, 100. }, +    { "MunhwaGungSeo-Light-KSC-EUC-H", 0.2, 100. }, +    { "MunhwaGungSeo-Bold-KSC-EUC-H", 0, 100. }, +    { "MunhwaGungSeo-Bold-KSC-EUC-H", 0.2, 100. } +}; + +static const psfont MunhwaGungSeoHeulim [] = { +    { "MunhwaGungSeoHeulim-Light-KSC-EUC-H", 0, 100. }, +    { "MunhwaGungSeoHeulim-Light-KSC-EUC-H", 0.2, 100. }, +    { "MunhwaGungSeoHeulim-Bold-KSC-EUC-H", 0, 100. }, +    { "MunhwaGungSeoHeulim-Bold-KSC-EUC-H", 0.2, 100. } +}; + +static const psfont MunhwaHoonMin [] = { +    { "MunhwaHoonMin-Regular-KSC-EUC-H", 0, 100. }, +    { "MunhwaHoonMin-Regular-KSC-EUC-H", 0.2, 100. }, +    { "MunhwaHoonMin-Regular-KSC-EUC-H", 0, 100. }, +    { "MunhwaHoonMin-Regular-KSC-EUC-H", 0.2, 100. } +}; + +static const psfont BaekmukGulim [] = { +    { "Baekmuk-Gulim-KSC-EUC-H", 0, 100. }, +    { "Baekmuk-Gulim-KSC-EUC-H", 0.2, 100. }, +    { "Baekmuk-Gulim-KSC-EUC-H", 0, 100. }, +    { "Baekmuk-Gulim-KSC-EUC-H", 0.2, 100. } +}; + +static const psfont * const KoreanReplacements[] = { +    BaekmukGulim, SMGothic, Munhwa, MunhwaGothic, MKai, MunhwaGungSeo, +    MunhwaGungSeoHeulim, MunhwaHoonMin, Helvetica, 0 +}; + +class TQPSPrinterFontKorean +  : public TQPSPrinterFontAsian { +public: +      TQPSPrinterFontKorean(const TQFontEngine* f); +      TQString extension() const; +}; + +TQPSPrinterFontKorean::TQPSPrinterFontKorean(const TQFontEngine* f) +{ +    codec = TQTextCodec::codecForMib( 38 ); // eucKR +    int type = getPsFontType( f ); +    psname = makePSFontName( f, type ); +    TQString best = "[ /" + psname + " 1.0 0.0 ]"; +    tqreplacementList.append( best ); +    appendReplacements( tqreplacementList, KoreanReplacements, type ); +} + +TQString TQPSPrinterFontKorean::extension() const +{ +    return "-KSC-EUC-H"; +} +// ----------- traditional chinese ------------ + +// Arphic Public License Big5 TrueType fonts (on Debian and CLE and others) +static const psfont ShanHeiSun [] = { +    { "ShanHeiSun-Light-ETen-B5-H", 0, 100. }, +    { "ShanHeiSun-Light-ETen-B5-H", 0.2, 100. }, +    { "ShanHeiSun-Light-ETen-B5-H", 0, 100. }, +    { "ShanHeiSun-Light-ETen-B5-H", 0.2, 100. }, +}; +static const psfont ZenKai [] = { +    { "ZenKai-Medium-ETen-B5-H", 0, 100. }, +    { "ZenKai-Medium-Italic-ETen-B5-H", 0.2, 100. }, +    { "ZenKai-Medium-Bold-ETen-B5-H", 0, 100. }, +    { "ZenKai-Medium-BoldItalic-ETen-B5-H", 0.2, 100. }, +}; + +// Fonts on Turbolinux +static const psfont SongB5 [] = { +    { "B5-MSung-Light-ETen-B5-H", 0, 100. }, +    { "B5-MSung-Italic-ETen-B5-H", 0, 100. }, +    { "B5-MSung-Bold-ETen-B5-H", 0, 100. }, +    { "B5-MSung-BoldItalic-ETen-B5-H", 0, 100. }, +}; +static const psfont KaiB5 [] = { +    { "B5-MKai-Medium-ETen-B5-H", 0, 100. }, +    { "B5-MKai-Italic-ETen-B5-H", 0, 100. }, +    { "B5-MKai-Bold-ETen-B5-H", 0, 100. }, +    { "B5-MKai-BoldItalic-ETen-B5-H", 0, 100. }, +}; +static const psfont HeiB5 [] = { +    { "B5-MHei-Medium-ETen-B5-H", 0, 100. }, +    { "B5-MHei-Italic-ETen-B5-H", 0, 100. }, +    { "B5-MHei-Bold-ETen-B5-H", 0, 100. }, +    { "B5-MHei-BoldItalic-ETen-B5-H", 0, 100. }, +}; +static const psfont FangSongB5 [] = { +    { "B5-CFangSong-Light-ETen-B5-H", 0, 100. }, +    { "B5-CFangSong-Italic-ETen-B5-H", 0, 100. }, +    { "B5-CFangSong-Bold-ETen-B5-H", 0, 100. }, +    { "B5-CFangSong-BoldItalic-ETen-B5-H", 0, 100. }, +}; + +// Arphic fonts on Thiz Linux +static const psfont LinGothic [] = { +    { "LinGothic-Light-ETen-B5-H", 0, 100. }, +    { "LinGothic-Light-Italic-ETen-B5-H", 0.2, 100. }, +    { "LinGothic-Light-Bold-ETen-B5-H", 0, 100. }, +    { "LinGothic-Light-BoldItalic-ETen-B5-H", 0.2, 100. }, +}; +static const psfont YenRound [] = { +    { "YenRound-Light-ETen-B5-H", 0, 100. }, +    { "YenRound-Light-Italic-ETen-B5-H", 0.2, 100. }, +    { "YenRound-Light-Bold-ETen-B5-H", 0, 100. }, +    { "YenRound-Light-BoldItalic-ETen-B5-H", 0.2, 100. }, +}; + +// Dr. Wang Hann-Tzong's GPL'ed Big5 TrueType fonts +#if 0 // ### this is never used? +static const psfont HtWFangSong [] = { +    { "HtW-FSong-Light-ETen-B5-H", 0, 100. }, +    { "HtW-FSong-Light-Italic-ETen-B5-H", 0.2, 100. }, +    { "HtW-FSong-Light-Bold-ETen-B5-H", 0, 100. }, +    { "HtW-FSong-Light-BoldItalic-ETen-B5-H", 0.2, 100. }, +}; +#endif + +static const psfont MingB5 [] = { +    { "Ming-Light-ETen-B5-H", 0, 100. }, +    { "Ming-Light-Italic-ETen-B5-H", 0.2, 100. }, +    { "Ming-Light-Bold-ETen-B5-H", 0, 100. }, +    { "Ming-Light-BoldItalic-ETen-B5-H", 0.2, 100. }, +}; + +// Microsoft's Ming/Sung font? +static const psfont MSung [] = { +    { "MSung-Light-ETenms-B5-H", 0, 100. }, +    { "MSung-Light-ETenms-B5-H", 0.2, 100. }, +    { "MSung-Light-ETenms-B5-H", 0, 100. }, +    { "MSung-Light-ETenms-B5-H", 0.2, 100. }, +}; +// "Standard Sung/Ming" font by Taiwan Ministry of Education +static const psfont MOESung [] = { +    { "MOESung-Regular-B5-H", 0, 100. }, +    { "MOESung-Regular-B5-H", 0.2, 100. }, +    { "MOESung-Regular-B5-H", 0, 100. }, +    { "MOESung-Regular-B5-H", 0.2, 100. }, +}; + +static const psfont MOEKai [] = { +    { "MOEKai-Regular-B5-H", 0, 100. }, +    { "MOEKai-Regular-B5-H", 0.2, 100. }, +    { "MOEKai-Regular-B5-H", 0, 100. }, +    { "MOEKai-Regular-B5-H", 0.2, 100. }, +}; + +static const psfont * const TraditionalReplacements[] = { +    MOESung, SongB5, ShanHeiSun, MingB5, MSung, FangSongB5, KaiB5, ZenKai, HeiB5, +    LinGothic, YenRound, MOEKai, Helvetica, 0 +	}; + +#if 0 // ### these are never used? +static const psfont * const SongB5Replacements[] = { +    SongB5, ShanHeiSun, MingB5, MSung, MOESung, Helvetica, 0 +	}; + +static const psfont * const FangSongB5Replacements[] = { +    FangSongB5, HtWFangSong, Courier, 0 +	}; +static const psfont * const KaiB5Replacements[] = { +    KaiB5, ZenKai, Times, 0 +	}; +static const psfont * const HeiB5Replacements[] = { +    HeiB5, LinGothic, YenRound, LucidaSans, 0 +	}; +static const psfont * const YuanB5Replacements[] = { +    YenRound, LinGothic, HeiB5, LucidaSans, 0 +	}; +#endif + + +class TQPSPrinterFontTraditionalChinese +  : public TQPSPrinterFontAsian { +public: +      TQPSPrinterFontTraditionalChinese(const TQFontEngine* f); +      TQString extension() const; +}; + +TQPSPrinterFontTraditionalChinese::TQPSPrinterFontTraditionalChinese(const TQFontEngine* f) +{ +    codec = TQTextCodec::codecForMib( 2026 ); // Big5-0 +    int type = getPsFontType( f ); +    psname = makePSFontName( f, type ); +    TQString best = "[ /" + psname + " 1.0 0.0 ]"; +    tqreplacementList.append( best ); +    appendReplacements( tqreplacementList, TraditionalReplacements, type ); +} + +TQString TQPSPrinterFontTraditionalChinese::extension() const +{ +    return "-ETen-B5-H"; +} + +// ----------- simplified chinese ------------ + +#if 0 +// GB18030 fonts on XteamLinux (?) +static const psfont SimplifiedGBK2K [] = { +    { "MSung-Light-GBK2K-H", 0, 100. }, +    { "MSung-Light-GBK2K-H", 0.2, 100. }, +    { "MKai-Medium-GBK2K-H", 0, 100. }, +    { "MKai-Medium-GBK2K-H", 0.2, 100. }, +}; +#endif + +// GB18030 fonts on Turbolinux +static const psfont SongGBK2K [] = { +    { "MSung-Light-GBK2K-H", 0, 100. }, +    { "MSung-Italic-GBK2K-H", 0, 100. }, +    { "MSung-Bold-GBK2K-H", 0, 100. }, +    { "MSung-BoldItalic-GBK2K-H", 0, 100. }, +}; +static const psfont KaiGBK2K [] = { +    { "MKai-Medium-GBK2K-H", 0, 100. }, +    { "MKai-Italic-GBK2K-H", 0, 100. }, +    { "MKai-Bold-GBK2K-H", 0, 100. }, +    { "MKai-BoldItalic-GBK2K-H", 0, 100. }, +}; +static const psfont HeiGBK2K [] = { +    { "MHei-Medium-GBK2K-H", 0, 100. }, +    { "MHei-Italic-GBK2K-H", 0, 100. }, +    { "MHei-Bold-GBK2K-H", 0, 100. }, +    { "MHei-BoldItalic-GBK2K-H", 0, 100. }, +}; +static const psfont FangSongGBK2K [] = { +    { "CFangSong-Light-GBK2K-H", 0, 100. }, +    { "CFangSong-Italic-GBK2K-H", 0, 100. }, +    { "CFangSong-Bold-GBK2K-H", 0, 100. }, +    { "CFangSong-BoldItalic-GBK2K-H", 0, 100. }, +}; + +static const psfont Simplified [] = { +    { "MSung-Light-GBK-EUC-H", 0, 100. }, +    { "MSung-Light-GBK-EUC-H", 0.2, 100. }, +    { "MKai-Medium-GBK-EUC-H", 0, 100. }, +    { "MKai-Medium-GBK-EUC-H", 0.2, 100. }, +}; + +static const psfont MSungGBK [] = { +    { "MSung-Light-GBK-EUC-H", 0, 100. }, +    { "MSung-Light-GBK-EUC-H", 0.2, 100. }, +    { "MSung-Light-GBK-EUC-H", 0, 100. }, +    { "MSung-Light-GBK-EUC-H", 0.2, 100. }, +}; + +static const psfont FangSong [] = { +    { "CFangSong-Light-GBK-EUC-H", 0, 100. }, +    { "CFangSong-Light-GBK-EUC-H", 0.2, 100. }, +    { "CFangSong-Light-GBK-EUC-H", 0, 100. }, +    { "CFangSong-Light-GBK-EUC-H", 0.2, 100. }, +}; + +// Arphic Public License GB2312 TrueType fonts (on Debian and CLE and others) +static const psfont BousungEG [] = { +    { "BousungEG-Light-GB-GB-EUC-H", 0, 100. }, +    { "BousungEG-Light-GB-GB-EUC-H", 0.2, 100. }, +    { "BousungEG-Light-GB-Bold-GB-EUC-H", 0, 100. }, +    { "BousungEG-Light-GB-Bold-GB-EUC-H", 0.2, 100. }, +}; +static const psfont GBZenKai [] = { +    { "GBZenKai-Medium-GB-GB-EUC-H", 0, 100. }, +    { "GBZenKai-Medium-GB-GB-EUC-H", 0.2, 100. }, +    { "GBZenKai-Medium-GB-Bold-GB-EUC-H", 0, 100. }, +    { "GBZenKai-Medium-GB-Bold-GB-EUC-H", 0.2, 100. }, +}; + +static const psfont * const SimplifiedReplacements[] = { +    SongGBK2K, FangSongGBK2K, KaiGBK2K, HeiGBK2K, +    Simplified, MSungGBK, FangSong, BousungEG, GBZenKai, Helvetica, 0 +	}; +#if 0 +static const psfont * const SongGBK2KReplacements[] = { +    SongGBK2K, MSungGBK, BousungEG, Helvetica, 0 +	}; +#endif +static const psfont * const FangSongGBK2KReplacements[] = { +    FangSongGBK2K, FangSong, Courier, 0 +	}; +static const psfont * const KaiGBK2KReplacements[] = { +    KaiGBK2K, GBZenKai, Times, 0 +	}; +static const psfont * const HeiGBK2KReplacements[] = { +    HeiGBK2K, LucidaSans, 0 +	}; + +class TQPSPrinterFontSimplifiedChinese +  : public TQPSPrinterFontAsian { +public: +      TQPSPrinterFontSimplifiedChinese(const TQFontEngine* f); +      TQString extension() const; +}; + +TQPSPrinterFontSimplifiedChinese::TQPSPrinterFontSimplifiedChinese(const TQFontEngine* f) +{ +    codec = TQTextCodec::codecForMib( 114 ); // GB18030 +    int type = getPsFontType( f ); +    TQString family = f->fontDef.family.lower(); +    if( family.tqcontains("kai",FALSE) ) { +	psname = KaiGBK2K[type].psname; +	appendReplacements( tqreplacementList, KaiGBK2KReplacements, type ); +    } else if( family.tqcontains("fangsong",FALSE) ) { +	psname = FangSongGBK2K[type].psname; +	appendReplacements( tqreplacementList, FangSongGBK2KReplacements, type ); +    } else if( family.tqcontains("hei",FALSE) ) { +	psname = HeiGBK2K[type].psname; +	appendReplacements( tqreplacementList, HeiGBK2KReplacements, type ); +    } else { +	psname = SongGBK2K[type].psname; +	appendReplacements( tqreplacementList, SimplifiedReplacements, type ); +    } +    //qDebug("simplified chinese: fontname is %s, psname=%s", f.family().latin1(), psname.latin1() ); +} + +TQString TQPSPrinterFontSimplifiedChinese::extension() const +{ +    return "-GBK2K-H"; +} + +#endif + + +// ================== TQPSPrinterFont ==================== + +class TQPSPrinterFont { +public: +  TQPSPrinterFont(const TQFont& f, int script, TQPSPrinterPrivate *priv); +  ~TQPSPrinterFont(); +  TQString postScriptFontName()     { return p->postScriptFontName(); } +    TQString defineFont( TQTextStream &stream, const TQString &ps, const TQFont &f, const TQString &key, +                             TQPSPrinterPrivate *d ) +    { return p->defineFont( stream, ps, f, key, d ); } +    void    download(TQTextStream& s, bool global) { p->download(s, global); } +    TQPSPrinterFontPrivate *handle() { return p; } +    TQString xfontname; +private: +  TQByteArray       data; +  TQPSPrinterFontPrivate* p; +}; + +TQPSPrinterFont::~TQPSPrinterFont() +{ +    // the dict in TQFontPrivate does deletion for us. +    //  delete p; +} + + +TQPSPrinterFont::TQPSPrinterFont(const TQFont &f, int script, TQPSPrinterPrivate *priv) +    : p(0) +{ +    TQString fontfilename; +    TQString fontname; + +    enum { NONE, PFB, PFA, TTF } type = NONE; + +    TQFontEngine *engine = f.d->engineForScript( (TQFont::Script) script ); +    // ### implement similar code for TQWS and WIN +    xfontname = makePSFontName( engine ); + +#if defined( TQ_WS_X11 ) +    bool xlfd = FALSE; +    //qDebug("engine = %p name=%s, script=%d", engine, engine ? engine->name() : "(null)", script); + +#ifndef TQT_NO_XFTFREETYPE +    if ( qt_has_xft && engine && engine->type() == TQFontEngine::Xft ) { +        XftPattern *pattern = static_cast<TQFontEngineXft *>( engine )->pattern(); +        char *filename = 0; +        XftPatternGetString (pattern, XFT_FILE, 0, &filename); +        //qDebug("filename for font is '%s'", filename); +        if ( filename ) { +            fontfilename = TQString::fromLocal8Bit( filename ); +            xfontname = fontfilename; +        } +    } else +#endif +    { +        TQString rawName; +        if ( engine && engine != (TQFontEngine *)-1 ) +            rawName = engine->name(); +        int index = rawName.tqfind('-'); +        if (index == 0) { +            // this is an XLFD font name +            for (int i=0; i < 6; i++) { +                index = rawName.tqfind('-',index+1); +            } +            xfontname = rawName.mid(0,index); +            if ( xfontname.endsWith( "*" ) ) +                xfontname.truncate( xfontname.length() - 1 ); +            xlfd = TRUE; +        } +    } +#endif // TQ_WS_X11 +#ifndef TQT_NO_TEXTCODEC +    // map some scripts to something more useful +    if ( script == TQFont::Han ) { +	TQTextCodec *lc = TQTextCodec::codecForLocale(); +	switch( lc->mibEnum() ) { +        case 36: // KS C 5601 +        case 38: // EUC KR +            script = TQFont::Hangul; +            break; + +        case 57: // gb2312.1980-0 +        case 113: // GBK +        case -113: // gbk-0 +        case 114: // GB18030 +        case -114: // gb18030-0 +        case 2025: // GB2312 +        case 2026: // Big5 +        case -2026: // Big5-HKSCS +        case 2101: // big5-0, big5.eten-0 +        case -2101: // big5hkscs-0, hkscs-1 +            break; + +        case 16: // JIS7 +        case 17: // SJIS +        case 18: // EUC JP +        case 63: // JIS X 0208 +        default: +            script = TQFont::Hiragana; +            break; +	} +    } else if ( script == TQFont::Katakana ) +	script = TQFont::Hiragana; +    else if ( script == TQFont::Bopomofo ) +	script = TQFont::Han; +#endif + +    TQString searchname = xfontname; +#if defined(TQ_WS_X11) +    // we need an extension here due to the fact that we use different +    // fonts for different scripts +    if ( xlfd && script >= TQFont::Han && script <= TQFont::Bopomofo ) +	xfontname += "/" + toString( script ); +#endif + +    //qDebug("looking for font %s in dict", xfontname.latin1() ); +    p = priv->fonts.tqfind(xfontname); +    if ( p ) +	return; + +#if defined(TQ_WS_X11) +    if ( xlfd ) { + +	for (TQStringList::Iterator it=priv->fontpath.begin(); it!=priv->fontpath.end() && fontfilename.isEmpty(); ++it) { +	    if ((*it).left(1) != "/") continue; // not a path name, a font server +	    TQString fontmapname; +	    int num = 0; +	    // search font.dir and font.scale for the right file +	    while ( num < 2 ) { +		if ( num == 0 ) +		    fontmapname = (*it) + "/fonts.scale"; +		else +		    fontmapname = (*it) + "/fonts.dir"; +		//qWarning(fontmapname); +		TQFile fontmap(fontmapname); +		if (fontmap.open(IO_ReadOnly)) { +		    while (!fontmap.atEnd()) { +			TQString mapping; +			fontmap.readLine(mapping,512); +			// fold to lower (since X folds to lowercase) +			//qWarning(xfontname); +			//qWarning(mapping); +			if (mapping.lower().tqcontains(searchname.lower())) { +			    int index = mapping.tqfind(' ',0); +			    TQString ffn = mapping.mid(0,index); +                            // remove the most common bitmap formats +			    if( !ffn.tqcontains( ".pcf" ) && !ffn.tqcontains( ".bdf" ) && +				!ffn.tqcontains( ".spd" ) && !ffn.tqcontains( ".phont" ) ) { +				fontfilename = (*it) + TQString("/") + ffn; +				if ( TQFile::exists(fontfilename) ) { +				    //qDebug("found font file %s", fontfilename.latin1()); +				    break; +				} else // unset fontfilename +				    fontfilename = TQString(); +			    } +			} +		    } +		    fontmap.close(); +		} +		num++; +	    } +	} +    } +#endif + +    //qDebug("font=%s, fontname=%s, file=%s, p=%p", f.family().latin1(), xfontname.latin1(), fontfilename.latin1(), p); + +    // memory mapping would be better here +    if (fontfilename.length() > 0) { // maybe there is no file name +	TQFile fontfile(fontfilename); +	if ( fontfile.exists() ) { +	    //printf("font name %s size = %d\n",fontfilename.latin1(),fontfile.size()); +	    data = TQByteArray( fontfile.size() ); + +	    fontfile.open(IO_Raw | IO_ReadOnly); +	    fontfile.readBlock(data.data(), fontfile.size()); +	    fontfile.close(); +	} +    } + +    if (!data.isNull() && data.size() > 0) { +        unsigned char* d = (unsigned char *)data.data(); +        if (d[0] == 0x80 && d[1] == 0x01 && d[6] == '%' && d[7] == '!') +            type = PFB; +        else if (d[0] == '%' && d[1] == '!' && d[2] == 'P' && d[3] == 'S') +            type = PFA; +        else if (d[0]==0x00 && d[1]==0x01 && d[2]==0x00 && d[3]==0x00) +            type = TTF; +        else +            type = NONE; +    } else +        type = NONE; + +    //qDebug("font is of type %d", type ); +    switch (type) { +    case TTF : +        p = new TQPSPrinterFontTTF(engine, data); +        break; +    case PFB: +        p = new TQPSPrinterFontPFB(engine, data); +        break; +    case PFA: +        p = new TQPSPrinterFontPFA(engine, data); +        break; +    case NONE: +    default: + +#ifndef TQT_NO_TEXTCODEC + +        if ( script == TQFont::Hiragana ) +            p = new TQPSPrinterFontJapanese( engine ); +        else if ( script == TQFont::Hangul ) +            p = new TQPSPrinterFontKorean( engine ); +        else if ( script == TQFont::Han ) { +            TQTextCodec *lc = TQTextCodec::codecForLocale(); +            switch( lc->mibEnum() ) { +            case 2025: // GB2312 +            case 57: // gb2312.1980-0 +            case 113: // GBK +            case -113: // gbk-0 +            case 114: // GB18030 +            case -114: // gb18030-0 +                p = new TQPSPrinterFontSimplifiedChinese( engine ); +                break; +            case 2026: // Big5 +            case -2026: // big5-0, big5.eten-0 +            case 2101: // Big5-HKSCS +            case -2101: // big5hkscs-0, hkscs-1 +                p = new TQPSPrinterFontTraditionalChinese( engine ); +                break; +            default: +                p = new TQPSPrinterFontJapanese( engine ); +            } +        } else +#endif +            //qDebug("didnt tqfind font for %s", xfontname.latin1()); +            p = new TQPSPrinterFontNotFound( engine ); +        break; +    } + +    if (p->postScriptFontName() == "Symbol") +	p->setSymbol(); + +    // this is needed to make sure we don't get the same postscriptname twice +    TQDictIterator<TQPSPrinterFontPrivate> it( priv->fonts ); +    for( it.toFirst(); it.current(); ++it ) { +	if ( *(*it) == *p ) { +//	    qWarning("Post script driver: font already in dict"); +	    delete p; +	    p = *it; +	    return; +	} +    } + +    //qDebug("inserting font %s in dict psname=%s", xfontname.latin1(), p->postScriptFontName().latin1() ); +    priv->fonts.insert( xfontname, p ); +} + +// ================= END OF PS FONT METHODS ============ + + +TQPSPrinterPrivate::TQPSPrinterPrivate( TQPrinter *prt, int filedes ) +    : buffer( 0 ), outDevice( 0 ), fd( filedes ), pageBuffer( 0 ), fonts(27, FALSE), fontBuffer(0), savedImage( 0 ), +      dirtypen( FALSE ), dirtybrush( FALSE ), dirtyBkColor( FALSE ), bkMode( TQt::TransparentMode ), dirtyBkMode( FALSE ), +#ifndef TQT_NO_TEXTCODEC +      currentFontCodec( 0 ), +#endif +      fm( TQFont() ), textY( 0 ) +{ +    printer = prt; +    headerFontNames.setAutoDelete( TRUE ); +    pageFontNames.setAutoDelete( TRUE ); +    fonts.setAutoDelete( TRUE ); +    currentFontFile = 0; +    scale = 1.; +    scriptUsed = -1; + +#ifdef TQ_WS_X11 +    // append qsettings fontpath +    TQSettings settings; +    embedFonts = settings.readBoolEntry( "/qt/embedFonts", TRUE ); + +    int npaths; +    char** font_path; +    font_path = XGetFontPath( qt_xdisplay(), &npaths); +    bool xfsconfig_read = FALSE; +    for (int i=0; i<npaths; i++) { +        // If we're using xfs, append font paths from /etc/X11/fs/config +        // can't hurt, and chances are we'll get all fonts that way. +        if (((font_path[i])[0] != '/') && !xfsconfig_read) { +            // We're using xfs -> read its config +            bool finished = FALSE; +            TQFile f("/etc/X11/fs/config"); +            if ( !f.exists() ) +                f.setName("/usr/X11R6/lib/X11/fs/config"); +            if ( !f.exists() ) +                f.setName("/usr/X11/lib/X11/fs/config"); +            if ( f.exists() ) { +                f.open(IO_ReadOnly); +                while(f.status()==IO_Ok && !finished) { +                    TQString fs; +                    f.readLine(fs, 1024); +                    fs=fs.stripWhiteSpace(); +                    if (fs.left(9)=="catalogue" && fs.tqcontains('=')) { +                        fs=fs.mid(fs.tqfind('=')+1).stripWhiteSpace(); +                        bool end = FALSE; +                        while( f.status()==IO_Ok && !end ) { +                            if ( fs[int(fs.length())-1] == ',' ) +                                fs = fs.left(fs.length()-1); +                            else +                                end = TRUE; +                            if (fs[0] != '#' && !fs.tqcontains(":unscaled")) +                                fontpath += fs; +                            f.readLine(fs, 1024); +                            fs=fs.stripWhiteSpace(); +                        } +                        finished = TRUE; +                    } +                } +                f.close(); +            } +            xfsconfig_read = TRUE; +        } else if(!strstr(font_path[i], ":unscaled")) { +            // Fonts paths marked :unscaled are always bitmapped fonts +            // -> we can as well ignore them now and save time +            fontpath += font_path[i]; +        } +    } +    XFreeFontPath(font_path); + +    // append qsettings fontpath +    TQStringList fp = settings.readListEntry( "/qt/fontPath", ':' ); +    if ( !fp.isEmpty() ) +        fontpath += fp; +#else +    embedFonts = FALSE; +#endif +} + +TQPSPrinterPrivate::~TQPSPrinterPrivate() +{ +    delete pageBuffer; +} + +void TQPSPrinterPrivate::setFont( const TQFont & fnt, int script ) +{ +    TQFont f = fnt; +    if ( f.rawMode() ) { +        TQFont fnt( TQString::tqfromLatin1("Helvetica"), 12 ); +        setFont( fnt, TQFont::Unicode ); +        return; +    } +    if ( f.pointSize() == 0 ) { +#if defined(CHECK_RANGE) +        qWarning( "TQPrinter: Cannot set a font with zero point size." ); +#endif +        f.setPointSize(TQApplication::font().pointSize()); +        if ( f.pointSize() == 0 ) +            f.setPointSize( 11 ); +    } + +    TQPSPrinterFont ff( f, script, this ); +    TQString ps = ff.postScriptFontName(); + +    TQString s = ps; +    s.append( ' ' ); +    s.prepend( ' ' ); + +    TQString key = ff.xfontname; + +    if ( f.pointSize() != -1 ) +	key += " " + toString( f.pointSize() ); +    else +	key += " px" + toString( f.pixelSize() ); +    TQString * tmp; +    if ( !buffer ) +        tmp = pageFontNames.tqfind( key ); +    else +        tmp = headerFontNames.tqfind( key ); + +    TQString fontName; +    if ( tmp ) +        fontName = *tmp; + +    if ( fontName.isEmpty() ) { +        fontName = ff.defineFont( pageStream, ps, f, key, this ); +    } +    pageStream << fontName << " F\n"; + +    ps.append( ' ' ); +    ps.prepend( ' ' ); +    if ( !fontsUsed.tqcontains( ps ) ) +        fontsUsed += ps; + +#ifndef TQT_NO_TEXTCODEC +    TQTextCodec * codec = 0; +// ### +// #ifndef TQT_NO_TEXTCODEC +//     i = 0; +//     do { +//      if ( tqunicodevalues[i].cs == f.charSet() ) +//          codec = TQTextCodec::codecForMib( tqunicodevalues[i++].mib ); +//     } while( codec == 0 && tqunicodevalues[i++].cs != tqunicodevalues_LAST ); +// #endif +    currentFontCodec = codec; +#endif +    currentFont = fontName; +    currentFontFile = ff.handle(); +    scriptUsed = script; +} + + +static void ps_r7( TQTextStream& stream, const char * s, int l ) +{ +    int i = 0; +    uchar line[79]; +    int col = 0; + +    while( i < l ) { +        line[col++] = s[i++]; +        if ( col >= 76 ) { +            line[col++] = '\n'; +            line[col++] = '\0'; +            stream << (const char *)line; +            col = 0; +        } +    } +    if ( col > 0 ) { +        while( (col&3) != 0 ) +            line[col++] = '%'; // use a comment as padding +        line[col++] = '\n'; +        line[col++] = '\0'; +        stream << (const char *)line; +    } +} + + +static const int quoteSize = 3; // 1-8 pixels +static const int maxQuoteLength = 4+16+32+64+128+256; // magic extended quote +static const int quoteReach = 10; // ... 1-1024 pixels back +static const int tableSize = 1024; // 2 ** quoteReach; +static const int numAttempts = 128; + +static const int hashSize = 71; + +static const int None = INT_MAX; + +/* puts the lowest numBits of data into the out array starting at postion (byte/bit). +   Adjusts byte and bit to point ot the next position. + +   Need to make sure the out array is long enough before calling the method. +*/ +static void emitBits( char *out, int & byte, int & bit, +                      int numBits, uint data ) +{ +    int b = 0; +    uint d = data; +    while( b < numBits ) { +        if ( bit == 0 ) +            out[byte] = 0; +        if ( d & 1 ) +            out[byte] = (uchar)out[byte] | ( 1 << bit ); +        d = d >> 1; +        b++; +        bit++; +        if ( bit > 6 ) { +            bit = 0; +            byte++; +        } +    } +} + +//#define DEBUG_COMPRESS +#ifdef DEBUG_COMPRESS +#include <tqdatetime.h> +#endif + +static TQByteArray compress( const TQImage & image, bool gray ) { +#ifdef DEBUG_COMPRESS +    TQTime t; +    t.start(); +    int sizeUncompressed[11]; +    for( int i = 0; i < 11; i++ ) +	sizeUncompressed[i] = 0; +    int sizeCompressed[11]; +    for( int i = 0; i < 11; i++ ) +	sizeCompressed[i] = 0; +#endif + +    int width = image.width(); +    int height = image.height(); +    int depth = image.depth(); +    int size = width*height; + +    int pastPixel[tableSize]; +    int mostRecentPixel[hashSize]; +    if ( depth == 1 ) +	size = (width+7)/8*height; +    else if ( !gray ) +	size = size*3; + +    unsigned char *pixel = new unsigned char[size+1]; +    int i = 0; +    if ( depth == 1 ) { +	TQImage::Endian bitOrder = image.bitOrder(); +	memset( pixel, 0xff, size ); +        for( int y=0; y < height; y++ ) { +            uchar * s = image.scanLine( y ); +	    for( int x=0; x < width; x++ ) { +		// need to copy bit for bit... +		bool b = ( bitOrder == TQImage::LittleEndian ) ? +			 (*(s + (x >> 3)) >> (x & 7)) & 1 : +			  (*(s + (x >> 3)) << (x & 7)) & 0x80 ; +		if ( b ) +		    pixel[i >> 3] ^= (0x80 >> ( i & 7 )); +		i++; +	    } +	    // we need to align to 8 bit here +	    i = (i+7) & 0xffffff8; +        } +    } else if ( depth == 8 ) { +        for( int y=0; y < height; y++ ) { +            uchar * s = image.scanLine( y ); +            for( int x=0; x < width; x++ ) { +                TQRgb rgb = image.color( s[x] ); +		if ( gray ) { +		    pixel[i] = (unsigned char) tqGray( rgb ); +		    i++; +		} else { +		    pixel[i] = (unsigned char) tqRed( rgb ); +		    pixel[i+1] = (unsigned char) tqGreen( rgb ); +		    pixel[i+2] = (unsigned char) tqBlue( rgb ); +		    i += 3; +		} +            } +        } +    } else { +        bool alpha = image.hasAlphaBuffer(); +        for( int y=0; y < height; y++ ) { +            TQRgb * s = (TQRgb*)(image.scanLine( y )); +            for( int x=0; x < width; x++ ) { +		TQRgb rgb = (*s++); +		if ( alpha && tqAlpha( rgb ) < 0x40 ) // 25% alpha, convert to white - +		    rgb = tqRgb( 0xff, 0xff, 0xff ); +		if ( gray ) { +		    pixel[i] = (unsigned char) tqGray( rgb ); +		    i++; +		} else { +		    pixel[i] = (unsigned char) tqRed( rgb ); +		    pixel[i+1] = (unsigned char) tqGreen( rgb ); +		    pixel[i+2] = (unsigned char) tqBlue( rgb ); +		    i += 3; +		} +	    } +	} +    } + +    pixel[size] = 0; + +    /* this compression function emits blocks of data, where each +       block is an unquoted series of pixels, or a quote from earlier +       pixels. if the six-letter string "banana" were a six-pixel +       image, it might be unquoted "ban" followed by a 3-pixel quote +       from -2.  note that the final "a" is then copied from the +       second "a", which is copied from the first "a" in the same copy +       operation. + +       the scanning for quotable blocks uses a cobol-like loop and a +       hash table: we know how many pixels we need to quote, hash the +       first and last pixel we need, and then go backwards in time +       looking for some spot where those pixels of those two colours +       occur at the right distance from each other. + +       when we tqfind a spot, we'll try a string-compare of all the +       intervening pixels. we only do a maximum of 128 both-ends +       compares or 64 full-string compares. it's more important to be +       fast than get the ultimate in compression. + +       The format of the compressed stream is as follows: +       // 2 bits step size for search and backreference ( 1 or 3 ) +       1 bit compressed or uncompressed block follows + +       uncompressed block: +       3 bits size of block in bytes +       size*8 bits data + +       compressed block: +       3 bits compression header +           0-2 size of block is 1-3 bytes +           3-7 size of block is bigger, 4-8 additional bits specifying size follow +       0/4-8 additional size fields +       10 location of backreference +    */ + +    for( i=0; i < hashSize; i++ ) +        mostRecentPixel[i] = None; +    int index = 0; +    int emittedUntil = 0; +    char *out = (char *)malloc( 256 * sizeof( char ) ); +    int outLen = 256; +    int outOffset = 0; +    int outBit = 0; + +    /* we process pixels serially, emitting as necessary/possible. */ +    while( index <= size ) { +        int bestCandidate = None; +        int bestLength = 0; +        i = index % tableSize; +        int h = pixel[index] % hashSize; +        int start, end; +        start = end = pastPixel[i] = mostRecentPixel[h]; +        mostRecentPixel[h] = index; +        /* if our first candidate quote is unusable, or we don't need +           to quote because we've already emitted something for this +           pixel, just skip. */ +        if ( start < index - tableSize || index >= size || +             emittedUntil > index) +            start = end = None; +        int attempts = 0; +        /* scan for suitable quote candidates: not too far back, and +           if we've found one that's as big as it can get, don't look +           for more */ +        while( start != None && end != None && +               bestLength < maxQuoteLength && +               start >= index - tableSize && +               end >= index - tableSize + bestLength ) { +            /* scan backwards, looking for something good enough to +               try a (slow) string comparison. we maintain indexes to +               the start and the end of the quote candidate here */ +            while( start != None && end != None && +                   ( pixel[start] != pixel[index] || +                     pixel[end] != pixel[index+bestLength] ) ) { +                if ( attempts++ > numAttempts ) { +                    start = None; +                } else if ( pixel[end] % hashSize == +                            pixel[index+bestLength] % hashSize ) { +                    /* we move the area along the end index' chain */ +                    end = pastPixel[end%tableSize]; +                    start = end - bestLength; +                } else if ( pixel[start] % hashSize == +                            pixel[index] % hashSize ) { +                    /* ... or along the start index' chain */ +                    start = pastPixel[start%tableSize]; +                    end = start + bestLength; +                } else { +#if 0 +                    /* this should never happen: both the start and +                       the end pointers ran off their tracks. */ +                    qDebug( "oops! %06x %06x %06x %06x %5d %5d %5d %d", +                            pixel[start], pixel[end], +                            pixel[index], pixel[index+bestLength], +                            start, end, index, bestLength ); +#endif +                    /* but if it should happen, no problem. we'll just +                       say we found nothing, and the compression will +                       be a bit worse. */ +                    start = None; +                } +                /* if we've moved either index too far to use the +                   quote candidate, let's just give up here. there's +                   also a guard against "start" insanity. */ +                if ( start < index - tableSize || start < 0 || start >= index ) +                    start = None; +                if ( end < index - tableSize + bestLength || end < bestLength ) +                    end = None; +            } +            /* ok, now start and end point to an area of suitable +               length whose first and last points match, or one/both +               is/are set to None. */ +            if ( start != None && end != None ) { +                /* slow string compare... */ +                int length = 0; +                while( length < maxQuoteLength && +                       index+length < size && +                       pixel[start+length] == pixel[index+length] ) +                    length++; +                /* if we've found something that overlaps the index +                   point, maybe we can move the quote point back?  if +                   we're copying 10 pixels from 8 pixels back (an +                   overlap of 2), that'll be faster than copying from +                   4 pixels back (an overlap of 6). */ +                if ( start + length > index && length > 0 ) { +                    int d = index-start; +                    int equal = TRUE; +                    while( equal && start + length > index && +                           start > d && start-d >= index-tableSize ) { +                        int i = 0; +                        while( equal && i < d ) { +                            if( pixel[start+i] != pixel[start+i-d] ) +                                equal = FALSE; +                            i++; +                        } +                        if ( equal ) +                            start -= d; +                    } +                } +                /* if what we have is longer than the best previous +                   candidate, we'll use this one. */ +                if ( length > bestLength ) { +                    attempts = 0; +                    bestCandidate = start; +                    bestLength = length; +                    if ( length < maxQuoteLength && index + length < size ) +                        end = mostRecentPixel[pixel[index+length]%hashSize]; +                } else { +                    /* and if it ins't, we'll try some more. but we'll +                       count each string compare extra, since they're +                       so expensive. */ +                    attempts += 2; +                    if ( attempts > numAttempts ) { +                        start = None; +                    } else if ( pastPixel[start%tableSize] + bestLength < +                                pastPixel[end%tableSize] ) { +                        start = pastPixel[start%tableSize]; +                        end = start + bestLength; +                    } else { +                        end = pastPixel[end%tableSize]; +                        start = end - bestLength; +                    } +                } +                /* again, if we can't make use of the current quote +                   candidate, we don't try any more */ +                if ( start < index - tableSize || start < 0 || start > size+1 ) +                    start = None; +                if ( end < index - tableSize + bestLength || end < 0 || end > size+1 ) +                    end = None; +            } +        } +	/* backreferences to 1 byte of data are actually more costly than +         emitting the data directly, 2 bytes don't save much. */ +	if ( bestCandidate != None && bestLength < 3 ) +	    bestCandidate = None; +        /* at this point, bestCandidate is a candidate of bestLength +         length, or else it's None. if we have such a candidate, or +         we're at the end, we have to emit all unquoted data. */ +        if ( index == size || bestCandidate != None ) { +            /* we need a double loop, because there's a maximum length +               on the "unquoted data" section. */ +            while( emittedUntil < index ) { +#ifdef DEBUG_COMPRESS +		int x = 0; +		int bl = emittedUntil - index; +		while ( (bl /= 2) ) +		    x++; +		if ( x > 10 ) x = 10; +		sizeUncompressed[x]++; +#endif +                int l = TQMIN( 8, index - emittedUntil ); +		if ( outOffset + l + 2 >= outLen ) { +		    outLen *= 2; +		    out = (char *) realloc( out, outLen ); +		} +                emitBits( out, outOffset, outBit, +                          1, 0 ); +                emitBits( out, outOffset, outBit, +                          quoteSize, l-1 ); +                while( l-- ) { +		    emitBits( out, outOffset, outBit, +			      8, pixel[emittedUntil] ); +                    emittedUntil++; +                } +            } +        } +        /* if we have some quoted data to output, do it. */ +        if ( bestCandidate != None ) { +#ifdef DEBUG_COMPRESS +	    int x = 0; +	    int bl = bestLength; +	    while ( (bl /= 2) ) +		x++; +	    if ( x > 10 ) x = 10; +	    sizeCompressed[x]++; +#endif +	    if ( outOffset + 4 >= outLen ) { +		outLen *= 2; +		out = (char *) realloc( out, outLen ); +	    } +            emitBits( out, outOffset, outBit, +                      1, 1 ); +	    int l = bestLength - 3; +	    const struct off_len { +		int off; +		int bits; +	    } ol_table [] = { +		/* Warning: if you change the table here, change /uc in the PS code! */ +		{ 3, 0/*dummy*/ }, +		{ 16, 4 }, +		{ 32, 5 }, +		{ 64, 6 }, +		{ 128, 7 }, +		{ /*256*/ 0xfffffff, 8 }, +	    }; + +            if ( l < ol_table[0].off ) { +                emitBits( out, outOffset, outBit, +                          quoteSize, l ); +	    } else { +		const off_len *ol = ol_table; +		l -= ol->off; +		ol++; +		while ( l >= ol->off ) { +		    l -= ol->off; +		    ol++; +		} +                emitBits( out, outOffset, outBit, +                          quoteSize, ol->bits-1 ); +                emitBits( out, outOffset, outBit, +                          ol->bits, l ); +	    } +	    emitBits( out, outOffset, outBit, +		      quoteReach, index - bestCandidate - 1 ); +	    emittedUntil += bestLength; +	} +	index++; +    } +    /* we've output all the data; time to clean up and finish off the +       last characters. */ +    if ( outBit ) +        outOffset++; +    i = 0; +    /* we have to make sure the data is encoded in a stylish way :) */ +    while( i < outOffset ) { +        uchar c = out[i]; +        c += 42; +        if ( c > 'Z' && ( c != 't' || i == 0 || out[i-1] != 'Q' ) ) +            c += 84; +        out[i] = c; +        i++; +    } +    TQByteArray outarr; +    outarr.duplicate( out, outOffset ); +    free( out ); +    delete [] pixel; + +#ifdef DEBUG_COMPRESS +    qDebug( "------------- image compression statistics ----------------" ); +    qDebug(" compression time %d", t.elapsed() ); +    qDebug( "Size dist of uncompressed blocks:" ); +    qDebug( "\t%d\t%d\t%d\t%d\t%d\t%d\n", sizeUncompressed[0], sizeUncompressed[1], +	    sizeUncompressed[2], sizeUncompressed[3], sizeUncompressed[4], sizeUncompressed[5]); +    qDebug( "\t%d\t%d\t%d\t%d\t%d\n", sizeUncompressed[6], sizeUncompressed[7], +	    sizeUncompressed[8], sizeUncompressed[9], sizeUncompressed[10] ); +    qDebug( "Size dist of compressed blocks:" ); +    qDebug( "\t%d\t%d\t%d\t%d\t%d\t%d\n", sizeCompressed[0], sizeCompressed[1], +	    sizeCompressed[2], sizeCompressed[3], sizeCompressed[4], sizeCompressed[5]); +    qDebug( "\t%d\t%d\t%d\t%d\t%d\n", sizeCompressed[6], sizeCompressed[7], +	    sizeCompressed[8], sizeCompressed[9], sizeCompressed[10] ); +    qDebug( "===> total compression ratio %d/%d = %f", outOffset, size, (float)outOffset/(float)size ); +    qDebug( "-----------------------------------------------------------" ); +#endif + +    return outarr; +} + +#undef XCOORD +#undef YCOORD +#undef WIDTH +#undef HEIGHT +#undef POINT +#undef RECT +#undef INT_ARG + +#define XCOORD(x)       (float)(x) +#define YCOORD(y)       (float)(y) +#define WIDTH(w)        (float)(w) +#define HEIGHT(h)       (float)(h) + +#define POINT(index)    XCOORD(p[index].point->x()) << ' ' <<           \ +                        YCOORD(p[index].point->y()) << ' ' +#define RECT(index)     XCOORD(p[index].rect->normalize().x())  << ' ' <<     \ +                        YCOORD(p[index].rect->normalize().y())  << ' ' <<     \ +                        WIDTH (p[index].rect->normalize().width()) << ' ' <<  \ +                        HEIGHT(p[index].rect->normalize().height()) << ' ' +#define INT_ARG(index)  p[index].ival << ' ' + +static char returnbuffer[13]; +static const char * color( const TQColor &c, TQPrinter * printer ) +{ +    if ( c == TQt::black ) +        qstrcpy( returnbuffer, "B " ); +    else if ( c == TQt::white ) +        qstrcpy( returnbuffer, "W " ); +    else if ( c.red() == c.green() && c.red() == c.blue() ) +        sprintf( returnbuffer, "%d d2 ", c.red() ); +    else if ( printer->colorMode() == TQPrinter::GrayScale ) +        sprintf( returnbuffer, "%d d2 ", +                 tqGray( c.red(), c.green(),c.blue() ) ); +    else +        sprintf( returnbuffer, "%d %d %d ", +                 c.red(), c.green(), c.blue() ); +    return returnbuffer; +} + + +static const char * psCap( TQt::PenCapStyle p ) +{ +    if ( p == TQt::SquareCap ) +        return "2 "; +    else if ( p == TQt::RoundCap ) +        return "1 "; +    return "0 "; +} + + +static const char * psJoin( TQt::PenJoinStyle p ) { +    if ( p == TQt::BevelJoin ) +        return "2 "; +    else if ( p == TQt::RoundJoin ) +        return "1 "; +    return "0 "; +} + + + +void TQPSPrinterPrivate::drawImage( TQPainter *paint, float x, float y, float w, float h, +				   const TQImage &img, const TQImage &tqmask ) +{ +    if ( !w || !h || img.isNull() ) return; + +    int width  = img.width(); +    int height = img.height(); +    float scaleX = (float)width/w; +    float scaleY = (float)height/h; + +    bool gray = (printer->colorMode() == TQPrinter::GrayScale) || +		img.allGray(); +    int splitSize = 21830 * (gray ? 3 : 1 ); +    if ( width * height > splitSize ) { // 65535/3, tolerance for broken printers +        int images, subheight; +        images = ( width * height + splitSize - 1 ) / splitSize; +        subheight = ( height + images-1 ) / images; +        while ( subheight * width > splitSize ) { +            images++; +            subheight = ( height + images-1 ) / images; +        } +        int suby = 0; +        while( suby < height ) { +            drawImage(paint, x, y + suby/scaleY, w, TQMIN( subheight, height-suby )/scaleY, +		      img.copy( 0, suby, width, TQMIN( subheight, height-suby ) ), +		      tqmask.isNull() ? tqmask : tqmask.copy( 0, suby, width, TQMIN( subheight, height-suby ) )); +            suby += subheight; +        } +    } else { +	TQByteArray out; +	int size = 0; +	const char *bits; + +	if ( !tqmask.isNull() ) { +	    out = ::compress( tqmask, TRUE ); +	    size = (width+7)/8*height; +	    pageStream << "/tqmask " << size << " string uc\n"; +	    ps_r7( pageStream, out, out.size() ); +	    pageStream << "d\n"; +	} +	if ( img.depth() == 1 ) { +	    size = (width+7)/8*height; +	    bits = "1 "; +	} else if ( gray ) { +	    size = width*height; +	    bits = "8 "; +        } else { +	    size = width*height*3; +	    bits = "24 "; +        } + +	out = ::compress( img, gray ); +	pageStream << "/sl " << size << " string uc\n"; +	ps_r7( pageStream, out, out.size() ); +	pageStream << "d\n" +		   << width << ' ' << height << "[" << scaleX << " 0 0 " << scaleY << " 0 0]sl " +		   << bits << (!tqmask.isNull() ? "tqmask " : "false ") +		   << x << ' ' << y << " di\n"; +    } +} + + +void TQPSPrinterPrivate::matrixSetup( TQPainter *paint ) +{ +#ifndef TQT_NO_TRANSFORMATIONS +    TQWMatrix tmp; +    if ( paint->hasViewXForm() ) { +        TQRect viewport = paint->viewport(); +        TQRect window   = paint->window(); +        tmp.translate( viewport.x(), viewport.y() ); +        tmp.scale( 1.0 * viewport.width()  / window.width(), +                   1.0 * viewport.height() / window.height() ); +        tmp.translate( -window.x(), -window.y() ); +    } +    if ( paint->hasWorldXForm() ) { +        tmp = paint->tqworldMatrix() * tmp; +    } +    pageStream << "[" +           << tmp.m11() << ' ' << tmp.m12() << ' ' +           << tmp.m21() << ' ' << tmp.m22() << ' ' +           << tmp.dx()  << ' ' << tmp.dy() +           << "]ST\n"; +#else +    TQPoint p(0,0); +    p = paint->xForm(p); +    pageStream << "[" +           << 0 << ' ' << 0 << ' ' +           << 0 << ' ' << 0 << ' ' +           << p.x()    << ' ' << p.y() +           << "]ST\n"; +#endif +    dirtyMatrix = FALSE; +} + +void TQPSPrinterPrivate::orientationSetup() +{ +    if ( printer->orientation() == TQPrinter::Landscape ) +        pageStream << "TQLS\n"; +} + + +void TQPSPrinterPrivate::emitHeader( bool finished ) +{ +    TQString title = printer->docName(); +    TQString creator = printer->creator(); +    if ( !creator )                             // default creator +        creator = TQString::tqfromLatin1("TQt " TQT_VERSION_STR); +    outDevice = new TQFile(); +    (void)((TQFile *)outDevice)->open( IO_WriteOnly, fd ); +    outStream.setDevice( outDevice ); +    outStream << "%!PS-Adobe-1.0"; +    TQPaintDeviceMetrics m( printer ); +    scale = 72. / ((float) m.logicalDpiY()); +    uint mtop, mleft, mbottom, mright; +    printer->margins( &mtop, &mleft, &mbottom, &mright ); +    int width = m.width(); +    int height = m.height(); +    bool fullPage = printer->fullPage(); +    if ( finished && pageCount == 1 && printer->numCopies() == 1 && +         ( ( printer->fullPage() && qt_gen_epsf ) || +	   ( printer->outputToFile() && printer->outputFileName().endsWith( ".eps" ) ) ) +	) { +        if ( !boundingBox.isValid() ) +            boundingBox.setRect( 0, 0, width, height ); +	if ( printer->orientation() == TQPrinter::Landscape ) { +	    if ( !fullPage ) +		boundingBox.moveBy( -mleft, -mtop ); +	    outStream << " EPSF-3.0\n%%BoundingBox: " +		      << (int)(m.height() - boundingBox.bottom())*scale << " " // llx +		      << (int)(m.width() - boundingBox.right())*scale - 1 << " " // lly +		      << (int)(m.height() - boundingBox.top())*scale + 1 << " " // urx +		      << (int)(m.width() - boundingBox.left())*scale; // ury +	} else { +	    if ( !fullPage ) +		boundingBox.moveBy( mleft, -mtop ); +	    outStream << " EPSF-3.0\n%%BoundingBox: " +		      << (int)(boundingBox.left())*scale << " " +		      << (int)(m.height() - boundingBox.bottom())*scale - 1 << " " +		      << (int)(boundingBox.right())*scale + 1 << " " +		      << (int)(m.height() - boundingBox.top())*scale; +	} +    } else { +	int w = width + (fullPage ? 0 : mleft + mright); +        int h = height + (fullPage ? 0 : mtop + mbottom); +	w = (int)(w*scale); +	h = (int)(h*scale); +        // set a bounding box according to the DSC +        if ( printer->orientation() == TQPrinter::Landscape ) +            outStream << "\n%%BoundingBox: 0 0 " << h << " " << w; +        else +            outStream << "\n%%BoundingBox: 0 0 " << w << " " << h; +    } +    outStream << "\n" << wrapDSC( "%%Creator: " + creator ); +    if ( !!title ) +        outStream << wrapDSC( "%%Title: " + title ); +    outStream << "%%CreationDate: " << TQDateTime::tqcurrentDateTime().toString(); +    outStream << "\n%%Orientation: "; +    if ( printer->orientation() == TQPrinter::Landscape ) +        outStream << "Landscape"; +    else +        outStream << "Portrait"; +    if ( finished ) +        outStream << "\n%%Pages: " << pageCount << "\n" +		  << wrapDSC( "%%DocumentFonts: " + fontsUsed ); +    else +        outStream << "%%Pages: (atend)" +               << "\n%%DocumentFonts: (atend)"; +    outStream << "\n%%EndComments\n"; + +    outStream << "%%BeginProlog\n"; +    const char * const prologLicense = "% Prolog copyright 1994-2006 Trolltech. " +                                 "You may copy this prolog in any way\n" +                                 "% that is directly related to this " +                                 "document. For other use of this prolog,\n" +                                 "% see your licensing agreement for TQt.\n"; +    outStream << prologLicense << ps_header << "\n"; + +    // we have to do this here, as scaling can affect this. +    TQString lineStyles = "/LArr["                                       // Pen styles: +			 " [] []"                       //   solid line +			 " [ w s ] [ s w ]"                 //   dash line +			 " [ s s ] [ s s ]"                  //   dot line +			 " [ m s s s ] [ s m s s ]"      //   dash dot line +			 " [ m s s s s ] [ s m s s s s ]"         //   dash dot dot line +			 " ] d\n"; +    lineStyles.tqreplace( TQRegExp( "w" ), toString( 10./scale ) ); +    lineStyles.tqreplace( TQRegExp( "m" ), toString( 5./scale ) ); +    lineStyles.tqreplace( TQRegExp( "s" ), toString( 3./scale ) ); + +    outStream << lineStyles; + +    outStream << "/pageinit {\n"; +    if ( !printer->fullPage() ) { +        if ( printer->orientation() == TQPrinter::Portrait ) +            outStream << mleft*scale << " " +                   << mbottom*scale << " translate\n"; +        else +            outStream << mtop*scale << " " +                   << mleft*scale << " translate\n"; +    } +    if ( printer->orientation() == TQPrinter::Portrait ) { +        outStream << "% " << m.widthMM() << "*" << m.heightMM() +               << "mm (portrait)\n0 " << height*scale +               << " translate " << scale << " -" << scale << " scale/defM matrix CM d } d\n"; +    } else { +        outStream << "% " << m.heightMM() << "*" << m.widthMM() +               << " mm (landscape)\n 90 rotate " << scale << " -" << scale << " scale/defM matrix CM d } d\n"; +    } +    outStream << "%%EndProlog\n"; + + +    outStream << "%%BeginSetup\n"; +    if ( printer->numCopies() > 1 ) { +	outStream << "/#copies " << printer->numCopies() << " def\n"; +	outStream << "/NumCopies " << printer->numCopies() << " SPD\n"; +	outStream << "/Collate " << (printer->collateCopies() ? "true" : "false") << " SPD\n"; +    } +    if ( fontBuffer->buffer().size() ) { +        if ( pageCount == 1 || finished ) +            outStream << "% Fonts and encodings used\n"; +        else +            outStream << "% Fonts and encodings used on pages 1-" +                   << pageCount << "\n"; +        TQDictIterator<TQPSPrinterFontPrivate> it(fonts); +        while (it.current()) { +          it.current()->download(outStream,TRUE); // true means its global +          ++it; +                } +        outStream.writeRawBytes( fontBuffer->buffer().data(), +                              fontBuffer->buffer().size() ); +    } +    outStream << "%%EndSetup\n"; + +    outStream.writeRawBytes( buffer->buffer().data(), +                          buffer->buffer().size() ); + +    delete buffer; +    buffer = 0; +    fontStream.unsetDevice(); +    delete fontBuffer; +    fontBuffer = 0; +} + + +/* Called whenever a restore has been done. Currently done at the top of a +  new page and whenever clipping is turned off. */ +void TQPSPrinterPrivate::resetDrawingTools( TQPainter *paint ) +{ +    TQPen   defaultPen;                  // default drawing tools +    TQBrush defaultBrush; + +    TQColor c = paint->backgroundColor(); +    if ( c != TQt::white ) +        pageStream << color( c, printer ) << "BC\n"; + +    if ( paint->backgroundMode() != TQt::TransparentMode ) +            pageStream << "/OMo true d\n"; + +    //currentUsed = currentSet; +    //setFont( currentSet ); +    currentFontFile = 0; + +    TQBrush b = paint->brush(); +    if ( b != defaultBrush ) { +        if ( b == TQt::CustomPattern ) { +#if defined(CHECK_RANGE) +            qWarning( "TQPrinter: Pixmap brush not supported" ); +#endif +        } else { +            cbrush = b; +        } +    } + +    dirtypen = TRUE; +    dirtybrush = TRUE; + +    if ( paint->hasViewXForm() || paint->hasWorldXForm() ) +        matrixSetup( paint ); +} + + +static void putRect( TQTextStream &stream, const TQRect &r ) +{ +    stream << r.x() << " " +           << r.y() << " " +           << r.width() << " " +           << r.height() << " "; +} + + +void TQPSPrinterPrivate::setClippingOff( TQPainter *paint ) +{ +        pageStream << "CLO\n";              // clipping off, includes a restore +        resetDrawingTools( paint );     // so drawing tools must be reset +} + + +void TQPSPrinterPrivate::clippingSetup( TQPainter *paint ) +{ +    if ( paint->hasClipping() ) { +        if ( !firstClipOnPage ) +            setClippingOff( paint ); +        const TQRegion rgn = paint->clipRegion(); +        TQMemArray<TQRect> rects = rgn.rects(); +        int i; +        pageStream<< "CLSTART\n";           // start clipping +        for( i = 0 ; i < (int)rects.size() ; i++ ) { +            putRect( pageStream, rects[i] ); +            pageStream << "ACR\n";          // add clip rect +            if ( pageCount == 1 ) +                boundingBox = boundingBox.unite( rects[i] ); +        } +        pageStream << "CLEND\n";            // end clipping +        firstClipOnPage = FALSE; +    } else { +        if ( !firstClipOnPage )      // no need to turn off if first on page +            setClippingOff( paint ); +        // if we're painting without clipping, the bounding box must +        // be everything.  NOTE: this assumes that this function is +        // only ever called when something is to be painted. +        TQPaintDeviceMetrics m( printer ); +        if ( !boundingBox.isValid() ) +            boundingBox.setRect( 0, 0, m.width(), m.height() ); +    } +    dirtyClipping = FALSE; +} + +void TQPSPrinterPrivate::initPage(TQPainter *paint) +{ + +    // a restore undefines all the fonts that have been defined +    // inside the scope (normally within pages) and all the glyphs that +    // have been added in the scope. + +    TQDictIterator<TQPSPrinterFontPrivate> it(fonts); +    while (it.current()) { +      it.current()->restore(); +      ++it; +    } +    if ( !buffer ) { +        pageFontNames.clear(); +    } + +    pageStream.unsetDevice(); +    if ( pageBuffer ) +        delete pageBuffer; +    pageBuffer = new TQBuffer(); +    pageBuffer->open( IO_WriteOnly ); +    pageStream.setEncoding( TQTextStream::Latin1 ); +    pageStream.setDevice( pageBuffer ); +    delete savedImage; +    savedImage = 0; +    textY = 0; +    dirtyClipping   = TRUE; +    firstClipOnPage = TRUE; + + +    resetDrawingTools( paint ); +    dirtyNewPage      = FALSE; +    pageFontNumber = headerFontNumber; +} + +void TQPSPrinterPrivate::flushPage( bool last ) +{ +    if ( last && !pageBuffer ) +	return; +    bool pageFonts = ( buffer == 0 ); +    if ( buffer && +//         ( last || pagesInBuffer++ > -1 || +//           ( pagesInBuffer > 4 && buffer->size() > 262144 ) ) ) +#ifdef TQ_WS_TQWS +         (last || buffer->size() > 2000000) // embedded is usually limited in memory +#else +         (last || buffer->size() > 50000000) +#endif +        ) { +//        qDebug("emiting header at page %d", pageCount ); +        emitHeader( last ); +    } +    outStream << "%%Page: " +              << pageCount << ' ' << pageCount << endl +              << "%%BeginPageSetup\n" +              << "QI\n"; +    if (!dirtyNewPage) { +        if ( pageFonts ) { +            //qDebug("page fonts for page %d", pageCount); +            // we have already downloaded the header. Maybe we have page fonts here +            TQDictIterator<TQPSPrinterFontPrivate> it(fonts); +            while (it.current()) { +                it.current()->download( outStream, FALSE ); // FALSE means its for the page only +                ++it; +            } +        } +        outStream  << "%%EndPageSetup\n"; +        if ( pageBuffer )  +            outStream.writeRawBytes( pageBuffer->buffer().data(), +                                     pageBuffer->buffer().size() ); +    } +    outStream << "\nQP\n"; +    pageCount++; +} + +// ================ PSPrinter class ======================== + +TQPSPrinter::TQPSPrinter( TQPrinter *prt, int fd ) +    : TQPaintDevice( TQInternal::Printer | TQInternal::ExternalDevice ) +{ +    d = new TQPSPrinterPrivate( prt, fd ); +} + + +TQPSPrinter::~TQPSPrinter() +{ +    if ( d->fd >= 0 ) +#if defined(_OS_WIN32_) +        ::_close( d->fd ); +#else +        ::close( d->fd ); +#endif +    delete d; +} + + + +static void ignoreSigPipe(bool b) +{ +    static struct sigaction *users_sigpipe_handler = 0; + +    if (b) { +	if (users_sigpipe_handler != 0) +    	    return; // already ignoring sigpipe + +	users_sigpipe_handler = new struct sigaction; +	struct sigaction tmp_sigpipe_handler; +	tmp_sigpipe_handler.sa_handler = SIG_IGN; +	sigemptyset(&tmp_sigpipe_handler.sa_mask); +	tmp_sigpipe_handler.sa_flags = 0; + +	if (sigaction(SIGPIPE, &tmp_sigpipe_handler, users_sigpipe_handler) == -1) { +    	    delete users_sigpipe_handler; +	    users_sigpipe_handler = 0; +	} +    } +    else { +	if (users_sigpipe_handler == 0) +    	    return; // not ignoring sigpipe + +	if (sigaction(SIGPIPE, users_sigpipe_handler, 0) == -1) +	    qWarning("TQPSPrinter: could not restore SIGPIPE handler"); + +	delete users_sigpipe_handler; +	users_sigpipe_handler = 0; +    } +} + +bool TQPSPrinter::cmd( int c , TQPainter *paint, TQPDevCmdParam *p ) +{ +    if ( c == PdcBegin ) {              // start painting +        d->pagesInBuffer = 0; +        d->buffer = new TQBuffer(); +        d->buffer->open( IO_WriteOnly ); +        d->outStream.setEncoding( TQTextStream::Latin1 ); +        d->outStream.setDevice( d->buffer ); +        d->fontBuffer = new TQBuffer(); +        d->fontBuffer->open( IO_WriteOnly ); +        d->fontStream.setEncoding( TQTextStream::Latin1 ); +        d->fontStream.setDevice( d->fontBuffer ); +        d->headerFontNumber = 0; +        d->pageCount           = 1;                // initialize state +        d->dirtyMatrix         = TRUE; +        d->dirtyClipping    = TRUE; +        d->dirtyNewPage        = TRUE; +        d->firstClipOnPage  = TRUE; +        d->boundingBox = TQRect( 0, 0, -1, -1 ); +        d->fontsUsed = TQString::tqfromLatin1(""); + +        TQPaintDeviceMetrics m( d->printer ); +        d->scale = 72. / ((float) m.logicalDpiY()); + +        return TRUE; +    } + +    if ( c == PdcEnd ) {                        // painting done +        bool pageCountAtEnd = (d->buffer != 0); + +    	// we're writing to lp/lpr through a pipe, we don't want to crash with SIGPIPE +	// if lp/lpr dies +	ignoreSigPipe(TRUE); +        d->flushPage( TRUE ); +        d->outStream << "%%Trailer\n"; +        if ( pageCountAtEnd ) +            d->outStream << "%%Pages: " << d->pageCount - 1 << "\n" << +		wrapDSC( "%%DocumentFonts: " + d->fontsUsed ); +        d->outStream << "%%EOF\n"; +	ignoreSigPipe(FALSE); + +        d->outStream.unsetDevice(); +	if ( d->outDevice ) +	    d->outDevice->close(); +        if ( d->fd >= 0 ) +            ::close( d->fd ); +        d->fd = -1; +        delete d->outDevice; +        d->outDevice = 0; +    } + +    if ( c >= PdcDrawFirst && c <= PdcDrawLast ) { +        if ( !paint ) +            return FALSE; // sanity +        if ( d->dirtyNewPage ) +            d->initPage( paint ); +        if ( d->dirtyMatrix ) +            d->matrixSetup( paint ); +        if ( d->dirtyClipping ) // Must be after matrixSetup and initPage +            d->clippingSetup( paint ); +        if ( d->dirtypen ) { +            // we special-case for narrow solid lines with the default +            // cap and join styles +            if ( d->cpen.style() == TQt::SolidLine && d->cpen.width() == 0 && +                 d->cpen.capStyle() == TQt::FlatCap && +                 d->cpen.joinStyle() == TQt::MiterJoin ) +                d->pageStream << color( d->cpen.color(), d->printer ) << "P1\n"; +            else +                d->pageStream << (int)d->cpen.style() << ' ' << d->cpen.width() +                       << ' ' << color( d->cpen.color(), d->printer ) +                       << psCap( d->cpen.capStyle() ) +                       << psJoin( d->cpen.joinStyle() ) << "PE\n"; +            d->dirtypen = FALSE; +        } +        if ( d->dirtybrush ) { +            // we special-case for nobrush and solid white, since +            // those are the two most common brushes +            if ( d->cbrush.style() == TQt::NoBrush ) +                d->pageStream << "NB\n"; +            else if ( d->cbrush.style() == TQt::SolidPattern && +                      d->cbrush.color() == TQt::white ) +                d->pageStream << "WB\n"; +            else +                d->pageStream << (int)d->cbrush.style() << ' ' +                       << color( d->cbrush.color(), d->printer ) << "BR\n"; +            d->dirtybrush = FALSE; +        } +	if ( d->dirtyBkColor ) { +	    d->pageStream << color( d->bkColor, d->printer ) << "BC\n"; +	    d->dirtyBkColor = FALSE; +	} +	if ( d->dirtyBkMode ) { +	    if ( d->bkMode == TQt::TransparentMode ) +		d->pageStream << "/OMo false d\n"; +	    else +		d->pageStream << "/OMo true d\n"; +	    d->dirtyBkMode = FALSE; +	} +    } + +    switch( c ) { +    case PdcDrawPoint: +        d->pageStream << POINT(0) << "P\n"; +        break; +    case PdcMoveTo: +        d->pageStream << POINT(0) << "M\n"; +        break; +    case PdcLineTo: +        d->pageStream << POINT(0) << "L\n"; +        break; +    case PdcDrawLine: +        if ( p[0].point->y() == p[1].point->y() ) +            d->pageStream << POINT(1) << p[0].point->x() << " HL\n"; +        else if ( p[0].point->x() == p[1].point->x() ) +            d->pageStream << POINT(1) << p[0].point->y() << " VL\n"; +        else +            d->pageStream << POINT(1) << POINT(0) << "DL\n"; +        break; +    case PdcDrawRect: +        d->pageStream << RECT(0) << "R\n"; +        break; +    case PdcDrawRoundRect: +        d->pageStream << RECT(0) << INT_ARG(1) << INT_ARG(2) << "RR\n"; +        break; +    case PdcDrawEllipse: +        d->pageStream << RECT(0) << "E\n"; +        break; +    case PdcDrawArc: +        d->pageStream << RECT(0) << INT_ARG(1) << INT_ARG(2) << "A\n"; +        break; +    case PdcDrawPie: +        d->pageStream << RECT(0) << INT_ARG(1) << INT_ARG(2) << "PIE\n"; +        break; +    case PdcDrawChord: +        d->pageStream << RECT(0) << INT_ARG(1) << INT_ARG(2) << "CH\n"; +        break; +    case PdcDrawLineSegments: +        if ( p[0].ptarr->size() > 0 ) { +            TQPointArray a = *p[0].ptarr; +            TQPoint pt; +            d->pageStream << "NP\n"; +            for ( int i=0; i<(int)a.size(); i+=2 ) { +                pt = a.point( i ); +                d->pageStream << XCOORD(pt.x()) << ' ' +                       << YCOORD(pt.y()) << " MT\n"; +                pt = a.point( i+1 ); +                d->pageStream << XCOORD(pt.x()) << ' ' +                       << YCOORD(pt.y()) << " LT\n"; +            } +            d->pageStream << "QS\n"; +        } +        break; +    case PdcDrawPolyline: +        if ( p[0].ptarr->size() > 1 ) { +            TQPointArray a = *p[0].ptarr; +            TQPoint pt = a.point( 0 ); +            d->pageStream << "NP\n" +                   << XCOORD(pt.x()) << ' ' << YCOORD(pt.y()) << " MT\n"; +            for ( int i=1; i<(int)a.size(); i++ ) { +                pt = a.point( i ); +                d->pageStream << XCOORD(pt.x()) << ' ' +                       << YCOORD(pt.y()) << " LT\n"; +            } +            d->pageStream << "QS\n"; +        } +        break; +    case PdcDrawPolygon: +        if ( p[0].ptarr->size() > 2 ) { +            TQPointArray a = *p[0].ptarr; +            if ( p[1].ival ) +                d->pageStream << "/WFi true d\n"; +            TQPoint pt = a.point(0); +            d->pageStream << "NP\n"; +            d->pageStream << XCOORD(pt.x()) << ' ' +                   << YCOORD(pt.y()) << " MT\n"; +            for( int i=1; i<(int)a.size(); i++) { +                pt = a.point( i ); +                d->pageStream << XCOORD(pt.x()) << ' ' +                       << YCOORD(pt.y()) << " LT\n"; +            } +            d->pageStream << "CP BF QS\n"; +            if ( p[1].ival ) +                d->pageStream << "/WFi false d\n"; +        } +        break; +    case PdcDrawCubicBezier: +        if ( p[0].ptarr->size() == 4 ) { +            d->pageStream << "NP\n"; +            TQPointArray a = *p[0].ptarr; +            d->pageStream << XCOORD(a[0].x()) << ' ' +                   << YCOORD(a[0].y()) << " MT "; +            for ( int i=1; i<4; i++ ) { +                d->pageStream << XCOORD(a[i].x()) << ' ' +                       << YCOORD(a[i].y()) << ' '; +            } +            d->pageStream << "BZ\n"; +        } +        break; +    case PdcDrawText2: +	// we use tqdrawTextItem instead +	return TRUE; +    case PdcDrawText2Formatted: +        return TRUE; +    case PdcDrawTextItem: { +	const TQTextItem *ti = p[1].textItem; +	TQScriptItem &si = ti->engine->items[ti->item]; +	int len = ti->engine->length( ti->item ); +	if ( si.isSpace || si.isObject ) +	    return FALSE; + +	if ( d->currentSet != d->currentUsed || d->scriptUsed != si.analysis.script || !d->currentFontFile ) { +	    d->currentUsed = d->currentSet; +	    d->setFont( d->currentSet, si.analysis.script ); +	} +	if( d->currentFontFile ) // better not crash in case somethig goes wrong. +	    d->currentFontFile->drawText( d->pageStream, *p[0].point, ti->engine, ti->item, +					  ti->engine->string.mid( si.position, len ), d, paint); +        return FALSE; +    } +    case PdcDrawPixmap: { +        if ( p[1].pixmap->isNull() ) +            break; +        TQRect r = *p[0].rect; +        TQImage img; +        img = *(p[1].pixmap); +	TQImage tqmask; +	if ( p[1].pixmap->tqmask() ) +	    tqmask = *(p[1].pixmap->tqmask()); +        d->drawImage(paint, r.x(), r.y(), r.width(), r.height(), img, tqmask); +        break; +    } +    case PdcDrawImage: { +        if ( p[1].image->isNull() ) +            break; +        TQRect r = *(p[0].rect); +        TQImage img = *(p[1].image); +	TQImage tqmask; +#ifndef TQT_NO_IMAGE_DITHER_TO_1 +	if ( img.hasAlphaBuffer() ) +	    tqmask = img.createAlphaMask(); +#endif +        d->drawImage(paint, r.x(), r.y(), r.width(), r.height(), img, tqmask); +        break; +    } +    case PdcSetBkColor: +    { +	if ( d->bkColor != *(p[0].color) ) { +	    d->bkColor = *(p[0].color); +	    d->dirtyBkColor = TRUE; +	} +        break; +    } +    case PdcSetBkMode: +    { +	if ( d->bkMode != p[0].ival ) { +	    d->bkMode = (TQt::BGMode) p[0].ival; +	    d->dirtyBkMode = TRUE; +	} +        break; +    } +    case PdcSetROP: +#if defined(CHECK_RANGE) +        if ( p[0].ival != TQt::CopyROP ) +            qWarning( "TQPrinter: Raster operation setting not supported" ); +#endif +        break; +    case PdcSetBrushOrigin: +        break; +    case PdcSetFont: +        d->currentSet = *(p[0].font); +	d->fm = paint->fontMetrics(); +        // turn these off - they confuse the 'avoid font change' logic +        d->currentSet.setUnderline( FALSE ); +        d->currentSet.setStrikeOut( FALSE ); +        break; +    case PdcSetPen: +        if ( d->cpen != *(p[0].pen) ) { +            d->dirtypen = TRUE; +            d->cpen = *(p[0].pen); +        } +        break; +    case PdcSetBrush: +        if ( p[0].brush->style() == TQt::CustomPattern ) { +#if defined(CHECK_RANGE) +            qWarning( "TQPrinter: Pixmap brush not supported" ); +#endif +            return FALSE; +        } +        if ( d->cbrush != *(p[0].brush) ) { +            d->dirtybrush = TRUE; +            d->cbrush = *(p[0].brush); +        } +        break; +    case PdcSetTabStops: +    case PdcSetTabArray: +        return FALSE; +    case PdcSetUnit: +        break; +    case PdcSetVXform: +    case PdcSetWindow: +    case PdcSetViewport: +    case PdcSetWXform: +    case PdcSetWMatrix: +    case PdcRestoreWMatrix: +        d->dirtyMatrix = TRUE; +        break; +    case PdcSetClip: +        d->dirtyClipping = TRUE; +        break; +    case PdcSetClipRegion: +        d->dirtyClipping = TRUE; +        break; +    case NewPage: +    	// we're writing to lp/lpr through a pipe, we don't want to crash with SIGPIPE +	// if lp/lpr dies +    	ignoreSigPipe(TRUE); +        d->flushPage(); +	ignoreSigPipe(FALSE); + +        d->dirtyNewPage = TRUE; +        break; +    case AbortPrinting: +        break; +    default: +        break; +    } +    return TRUE; +} + +#endif // TQT_NO_PRINTER + +#endif // USE_QT4
\ No newline at end of file | 
