You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tqt3/src/kernel/qpsprinter.cpp

6583 lines
224 KiB

/**********************************************************************
**
** Implementation of TQPSPrinter class
**
** Created : 941003
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** 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 "qplatformdefs.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 "qpsprinter_p.h"
#ifndef TQT_NO_PRINTER
#undef Q_PRINTER_USE_TYPE42
#include "ntqpainter.h"
#include "ntqapplication.h"
#include "ntqpaintdevicemetrics.h"
#include "ntqimage.h"
#include "ntqdatetime.h"
#include "ntqstring.h"
#include "ntqdict.h"
#include "ntqmemarray.h"
#include "ntqfile.h"
#include "ntqbuffer.h"
#include "ntqintdict.h"
#include "ntqtextcodec.h"
#include "ntqsettings.h"
#include "ntqmap.h"
#include "ntqfontdatabase.h"
#include "ntqregexp.h"
#include "ntqbitmap.h"
#include <private/qunicodetables_p.h>
#if defined(Q_OS_WIN32)
#include <io.h>
#ifdef Q_PRINTER_USE_TYPE42
#include <stdlib.h>
#endif
#else
#include <unistd.h>
#include <stdlib.h>
#endif
#ifdef TQ_WS_X11
#include "qt_x11_p.h"
#ifdef None
#undef None
#endif
#ifdef GrayScale
#undef GrayScale
#endif
#endif
#if defined( TQ_WS_X11 ) || defined (TQ_WS_QWS)
#include "qfontdata_p.h"
#include "qfontengine_p.h"
#include "qtextlayout_p.h"
#include "qtextengine_p.h"
extern bool tqt_has_xft;
#endif
static bool qt_gen_epsf = FALSE;
static bool embedFonts = TRUE;
TQ_EXPORT void tqt_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 imagemask BkCol SC\n"
"imagemask}{pop false 3 1 roll imagemask}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 findfont 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{findfont dup length\n"
"dict begin{1 i/FID ne{d}{pop pop}ifelse}forall/Encoding ED currentdict end\n"
"definefont pop}D/DF{findfont/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{/setpagedevice where{1 DB 3 1 roll d end setpagedevice}{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/unicodegn.html
//
// IMPORTANT NOTE:
// the list contains glyphs in the private use area of unicode. These should get removed when regenerating the glyphlist.
// also 0 shout be mapped to .notdef
static const struct {
TQ_UINT16 u;
const char * g;
} unicodetoglyph[] = {
// 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" }, // QUOTATION 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" }, // EQUALS SIGN
{ 0x003E, "greater" }, // GREATER-THAN SIGN
{ 0x003F, "question" }, // QUESTION 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 SQUARE BRACKET
{ 0x005C, "backslash" }, // REVERSE SOLIDUS
{ 0x005D, "bracketright" }, // RIGHT SQUARE 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 QUOTATION 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 QUOTATION MARK
{ 0x00BC, "onequarter" }, // VULGAR FRACTION ONE QUARTER
{ 0x00BD, "onehalf" }, // VULGAR FRACTION ONE HALF
{ 0x00BE, "threequarters" }, // VULGAR FRACTION THREE QUARTERS
{ 0x00BF, "questiondown" }, // INVERTED QUESTION 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 QUESTION 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 QUOTATION MARK
{ 0x2019, "quoteright" }, // RIGHT SINGLE QUOTATION MARK
{ 0x201A, "quotesinglbase" }, // SINGLE LOW-9 QUOTATION MARK
{ 0x201B, "quotereversed" }, // SINGLE HIGH-REVERSED-9 QUOTATION MARK
{ 0x201C, "quotedblleft" }, // LEFT DOUBLE QUOTATION MARK
{ 0x201D, "quotedblright" }, // RIGHT DOUBLE QUOTATION MARK
{ 0x201E, "quotedblbase" }, // DOUBLE LOW-9 QUOTATION 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 QUOTATION MARK
{ 0x203A, "guilsinglright" }, // SINGLE RIGHT-POINTING ANGLE QUOTATION 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" }, // SQUARE 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 EQUAL TO
{ 0x2248, "approxequal" }, // ALMOST EQUAL TO
{ 0x2260, "notequal" }, // NOT EQUAL TO
{ 0x2261, "equivalence" }, // IDENTICAL TO
{ 0x2264, "lessequal" }, // LESS-THAN OR EQUAL TO
{ 0x2265, "greaterequal" }, // GREATER-THAN OR EQUAL TO
{ 0x2282, "propersubset" }, // SUBSET OF
{ 0x2283, "propersuperset" }, // SUPERSET OF
{ 0x2284, "notsubset" }, // NOT A SUBSET OF
{ 0x2286, "reflexsubset" }, // SUBSET OF OR EQUAL TO
{ 0x2287, "reflexsuperset" }, // SUPERSET OF OR EQUAL 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 SQUARE
{ 0x25A1, "H22073" }, // WHITE SQUARE
{ 0x25AA, "H18543" }, // BLACK SMALL SQUARE
{ 0x25AB, "H18551" }, // WHITE SMALL SQUARE
{ 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 * replacements;
} postscriptFonts [] = {
{ "arial", Arial, SansSerifReplacements },
{ "arialmt", Arial, SansSerifReplacements },
{ "arialunicodems", 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 &mask );
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 device 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 unicode );
void downloadMapping( TQTextStream &s, bool global );
TQString glyphName( unsigned short glyphindex, bool *glyphSet = 0 );
virtual void restore();
virtual unsigned short unicode_for_glyph(int glyphindex) { return glyphindex; }
virtual unsigned short glyph_for_unicode(unsigned short unicode) { return unicode; }
unsigned short insertIntoSubset( unsigned short unicode );
virtual bool embedded() { return FALSE; }
bool operator == ( const TQPSPrinterFontPrivate &other ) {
return other.psname == psname;
}
inline void setSymbol() { symbol = TRUE; }
protected:
TQString psname;
TQStringList replacementList;
TQMap<unsigned short, unsigned short> subset; // unicode 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::fromLatin1( psf[type].psname );
} else {
switch ( type ) {
case 1:
ps.append( TQString::fromLatin1("-Italic") );
break;
case 2:
ps.append( TQString::fromLatin1("-Bold") );
break;
case 3:
ps.append( TQString::fromLatin1("-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 * replacements, int type, float xscale = 100. )
{
// iterate through the replacement fonts
while ( *replacements ) {
const psfont *psf = *replacements;
TQString ps = "[ /" + TQString::fromLatin1( psf[type].psname ) + " " +
toString( xscale / psf[type].xscale ) + " " +
toString( psf[type].slant ) + " ]";
list.append( ps );
++replacements;
}
}
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 * replacements = postscriptFonts[i].replacements;
float xscale = 100;
if ( psf ) {
// xscale for the "right" font is always 1. We scale the replacements...
xscale = psf->xscale;
ps = "[ /" + TQString::fromLatin1( psf[type].psname ) + " 1.0 " +
toString( psf[type].slant ) + " ]";
} else {
ps = "[ /" + ps + " 1.0 0.0 ]";
// only add default replacement fonts in case this font was unknown.
if ( fe->fontDef.fixedPitch ) {
replacements = FixedReplacements;
} else {
replacements = 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 ( replacements )
appendReplacements( list, replacements, 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.find(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.find(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 {
tqWarning("TQPSPrinterFont::internal error");
}
return retval;
}
void TQPSPrinterFontPrivate::restore()
{
page_subset.clear();
pageSubsetCount = 0;
//tqDebug("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.unicode()[i].unicode()) );
} else {
for ( int i = 0; i < len; i++ )
stream << toHex( mapUnicode(text.unicode()[i].unicode()) );
}
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 unicode )
{
TQMap<unsigned short, unsigned short>::iterator res;
res = subset.find( unicode );
unsigned short offset = 0;
bool found = FALSE;
if ( res != subset.end() ) {
found = TRUE;
} else {
if ( downloaded ) {
res = page_subset.find( unicode );
offset = (subsetCount/256 + 1) * 256;
if ( res != page_subset.end() )
found = TRUE;
}
}
if ( !found ) {
return insertIntoSubset( unicode );
}
//tqDebug("mapping unicode %x to %x", unicode, 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 unicode = unicode_for_glyph( glyphindex );
if (symbol && unicode < 0x100) {
// map from latin1 to symbol
unicode = symbol_map[unicode];
}
if ( !unicode && glyphindex ) {
glyphname = "gl";
glyphname += toHex( glyphindex );
} else {
while( unicodetoglyph[l].u < unicode )
l++;
if ( unicodetoglyph[l].u == unicode ) {
glyphname = unicodetoglyph[l].g;
if ( glyphSet ) {
int other = 0;
switch ( unicode ) {
// 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_unicode( other );
if( oglyph && oglyph != glyphindex && glyphSet[oglyph] ) {
glyphname = "uni";
glyphname += toHex( unicode );
}
}
}
} else {
glyphname = "uni";
glyphname += toHex( unicode );
}
}
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 = &subset;
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 << " findfont\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 unicode_for_glyph(int glyphindex);
unsigned short glyph_for_unicode(unsigned short unicode);
int topost(FWord x) { return (int)( ((int)(x) * 1000 + HUPM) / unitsPerEm ); }
#ifdef Q_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 Q_PRINTER_USE_TYPE42
char* environment_preference = getenv("QT_TTFTOPS");
if (environment_preference) {
if (TQString(environment_preference) == "42")
target_type = 42;
else if (TQString(environment_preference) == "3")
target_type = 3;
else
tqWarning("The value of QT_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) {
tqWarning("TrueType font is unusable because indexToLocFormat != 0");
defective = TRUE;
return;
}
if( getSHORT(ptr+52) != 0 ) {
tqWarning("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;
tqDebug("couldn't find 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.replace(' ', '-');
psname.replace("/", "");
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 ) {
tqWarning("TrueType font does not have a format 2.0 'post' table");
tqWarning("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;
tqDebug("no maxp table in font");
return;
}
numGlyphs = getUSHORT( maxp + 4 );
// tqDebug("number of glyphs is %d", numGlyphs);
replacementList = 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->shape( 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 contains the shaped string.
bool useGlyphAsUnicode = (type == TQFontEngine::XLFD && si.fontEngine->cmap() == 0);
#else // TQ_WS_QWS
const bool glyphIndices = FALSE;
const bool useGlyphAsUnicode = TRUE;
#endif
stream << "<";
if ( si.analysis.bidiLevel % 2 ) {
for ( int i = len-1; i >=0; i-- ) {
// map unicode 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_unicode(useGlyphAsUnicode ? glyphs[i] : text.unicode()[i].unicode());
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 unicode 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_unicode(useGlyphAsUnicode ? glyphs[i] : text.unicode()[i].unicode());
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, replacementList);
if ( !embedFonts ) {
downloadMapping(s, global);
return;
}
//tqDebug("downloading ttf font %s", psname.latin1() );
//tqDebug("target type=%d", target_type);
global_dict = global;
TQMap<unsigned short, unsigned short> *subsetDict = &subset;
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{setcachedevice}{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 Q_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;
//tqDebug("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 find 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 contains */
/* 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, replace 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; // unicode
}
if (platform == 3 && encoding == 0) {
// symbol, continue looking
map = i;
}
}
if (map==nmaps) {
tqWarning("Font does not have unicode encoding\n");
return; // no unicode 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) {
//tqWarning("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::unicode_for_glyph(int glyphindex)
{
return uni2glyph[glyphindex];
}
USHORT TQPSPrinterFontTTF::glyph_for_unicode(unsigned short unicode)
{
return glyph2uni[unicode];
}
#ifdef Q_PRINTER_USE_TYPE42
// ****************** SNFTS ROUTINES *******
/*-------------------------------------------------------------------
** sfnts routines
** These routines generate the PostScript "sfnts" array which
** contains 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 ) {
tqWarning("TrueType font contains 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 ) {
tqWarning("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 find? */
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 {
tqWarning("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 ) {
tqWarning("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 );
}
/*
** find 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 ) {
tqWarning("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 contains: %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 setcachedevice 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
tqWarning("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::fromLatin1(fontnameptr,l);
replacementList = makePSFontNameList( f, psname );
}
void TQPSPrinterFontPFA::download(TQTextStream& s, bool global)
{
emitPSFontNameList( s, psname, replacementList);
if ( !embedFonts ) {
downloadMapping(s, global);
return;
}
//tqDebug("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
tqWarning("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::fromLatin1(fontnameptr,l);
replacementList = makePSFontNameList( f, psname );
}
void TQPSPrinterFontPFB::download(TQTextStream& s, bool global)
{
emitPSFontNameList( s, psname, replacementList);
if ( !embedFonts ) {
downloadMapping(s, global);
return;
}
//tqDebug("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++;
//tqDebug("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;
}
//tqWarning(TQString::fromLatin1((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::fromLatin1((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::fromLatin1(hexchar+((p[pos] >> 4) & 0xf),1)
<< TQString::fromLatin1(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 );
replacementList = makePSFontNameList( f );
}
void TQPSPrinterFontNotFound::download(TQTextStream& s, bool)
{
//tqDebug("downloading not found font %s", psname.latin1() );
emitPSFontNameList( s, psname, replacementList );
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::fromLatin1("-Italic") );
break;
case 2:
ps.append( TQString::fromLatin1("-Bold") );
break;
case 3:
ps.append( TQString::fromLatin1("-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.find( 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)
{
//tqDebug("downloading asian font %s", psname.latin1() );
s << "% Asian postscript font requested. Using "
<< psname << endl;
emitPSFontNameList( s, psname, replacementList );
}
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.unicode()[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.unicode()[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 ]";
replacementList.append( best );
const psfont *const *replacements = ( psname.contains( "Helvetica" ) ? Japanese2Replacements : Japanese1Replacements );
appendReplacements( replacementList, replacements, 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 ]";
replacementList.append( best );
appendReplacements( replacementList, 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 ]";
replacementList.append( best );
appendReplacements( replacementList, 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.contains("kai",FALSE) ) {
psname = KaiGBK2K[type].psname;
appendReplacements( replacementList, KaiGBK2KReplacements, type );
} else if( family.contains("fangsong",FALSE) ) {
psname = FangSongGBK2K[type].psname;
appendReplacements( replacementList, FangSongGBK2KReplacements, type );
} else if( family.contains("hei",FALSE) ) {
psname = HeiGBK2K[type].psname;
appendReplacements( replacementList, HeiGBK2KReplacements, type );
} else {
psname = SongGBK2K[type].psname;
appendReplacements( replacementList, SimplifiedReplacements, type );
}
//tqDebug("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;
//tqDebug("engine = %p name=%s, script=%d", engine, engine ? engine->name() : "(null)", script);
#ifndef TQT_NO_XFTFREETYPE
if ( tqt_has_xft && engine && engine->type() == TQFontEngine::Xft ) {
XftPattern *pattern = static_cast<TQFontEngineXft *>( engine )->pattern();
char *filename = 0;
XftPatternGetString (pattern, XFT_FILE, 0, &filename);
//tqDebug("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.find('-');
if (index == 0) {
// this is an XLFD font name
for (int i=0; i < 6; i++) {
index = rawName.find('-',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
//tqDebug("looking for font %s in dict", xfontname.latin1() );
p = priv->fonts.find(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";
//tqWarning(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)
//tqWarning(xfontname);
//tqWarning(mapping);
if (mapping.lower().contains(searchname.lower())) {
int index = mapping.find(' ',0);
TQString ffn = mapping.mid(0,index);
// remove the most common bitmap formats
if( !ffn.contains( ".pcf" ) && !ffn.contains( ".bdf" ) &&
!ffn.contains( ".spd" ) && !ffn.contains( ".phont" ) ) {
fontfilename = (*it) + TQString("/") + ffn;
if ( TQFile::exists(fontfilename) ) {
//tqDebug("found font file %s", fontfilename.latin1());
break;
} else // unset fontfilename
fontfilename = TQString();
}
}
}
fontmap.close();
}
num++;
}
}
}
#endif
//tqDebug("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;
//tqDebug("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
//tqDebug("didnt find 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 ) {
// tqWarning("Post script driver: font already in dict");
delete p;
p = *it;
return;
}
}
//tqDebug("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( tqt_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.contains('=')) {
fs=fs.mid(fs.find('=')+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.contains(":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::fromLatin1("Helvetica"), 12 );
setFont( fnt, TQFont::Unicode );
return;
}
if ( f.pointSize() == 0 ) {
#if defined(CHECK_RANGE)
tqWarning( "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.find( key );
else
tmp = headerFontNames.find( 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.contains( ps ) )
fontsUsed += ps;
#ifndef TQT_NO_TEXTCODEC
TQTextCodec * codec = 0;
// ###
// #ifndef TQT_NO_TEXTCODEC
// i = 0;
// do {
// if ( unicodevalues[i].cs == f.charSet() )
// codec = TQTextCodec::codecForMib( unicodevalues[i++].mib );
// } while( codec == 0 && unicodevalues[i++].cs != unicodevalues_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 <ntqdatetime.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 find 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. */
tqDebug( "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
tqDebug( "------------- image compression statistics ----------------" );
tqDebug(" compression time %d", t.elapsed() );
tqDebug( "Size dist of uncompressed blocks:" );
tqDebug( "\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]);
tqDebug( "\t%d\t%d\t%d\t%d\t%d\n", sizeUncompressed[6], sizeUncompressed[7],
sizeUncompressed[8], sizeUncompressed[9], sizeUncompressed[10] );
tqDebug( "Size dist of compressed blocks:" );
tqDebug( "\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]);
tqDebug( "\t%d\t%d\t%d\t%d\t%d\n", sizeCompressed[6], sizeCompressed[7],
sizeCompressed[8], sizeCompressed[9], sizeCompressed[10] );
tqDebug( "===> total compression ratio %d/%d = %f", outOffset, size, (float)outOffset/(float)size );
tqDebug( "-----------------------------------------------------------" );
#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 &mask )
{
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 ) ),
mask.isNull() ? mask : mask.copy( 0, suby, width, TQMIN( subheight, height-suby ) ));
suby += subheight;
}
} else {
TQByteArray out;
int size = 0;
const char *bits;
if ( !mask.isNull() ) {
out = ::compress( mask, TRUE );
size = (width+7)/8*height;
pageStream << "/mask " << 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 << (!mask.isNull() ? "mask " : "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->worldMatrix() * 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::fromLatin1("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::currentDateTime().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.replace( TQRegExp( "w" ), toString( 10./scale ) );
lineStyles.replace( TQRegExp( "m" ), toString( 5./scale ) );
lineStyles.replace( 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)
tqWarning( "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_QWS
(last || buffer->size() > 2000000) // embedded is usually limited in memory
#else
(last || buffer->size() > 50000000)
#endif
) {
// tqDebug("emiting header at page %d", pageCount );
emitHeader( last );
}
outStream << "%%Page: "
<< pageCount << ' ' << pageCount << endl
<< "%%BeginPageSetup\n"
<< "QI\n";
if (!dirtyNewPage) {
if ( pageFonts ) {
//tqDebug("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)
tqWarning("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::fromLatin1("");
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 drawTextItem 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 mask;
if ( p[1].pixmap->mask() )
mask = *(p[1].pixmap->mask());
d->drawImage(paint, r.x(), r.y(), r.width(), r.height(), img, mask);
break;
}
case PdcDrawImage: {
if ( p[1].image->isNull() )
break;
TQRect r = *(p[0].rect);
TQImage img = *(p[1].image);
TQImage mask;
#ifndef TQT_NO_IMAGE_DITHER_TO_1
if ( img.hasAlphaBuffer() )
mask = img.createAlphaMask();
#endif
d->drawImage(paint, r.x(), r.y(), r.width(), r.height(), img, mask);
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 )
tqWarning( "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)
tqWarning( "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