r20113 by jghali - fix use of space instead of tabs for indentation

scribus-commit scribus-commit at lists.scribus.net
Thu May 21 23:40:16 UTC 2015


Author: jghali
Date: Thu May 21 23:40:15 2015
New Revision: 20113

URL: http://scribus.net/websvn/listing.php?repname=Scribus&sc=1&rev=20113
Log:
fix use of space instead of tabs for indentation 

Modified:
    trunk/Scribus/scribus/fonts/cff.cpp
    trunk/Scribus/scribus/fonts/cff.h
    trunk/Scribus/scribus/fonts/sfnt.cpp
    trunk/Scribus/scribus/fonts/sfnt.h

Modified: trunk/Scribus/scribus/fonts/cff.cpp
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=20113&path=/trunk/Scribus/scribus/fonts/cff.cpp
==============================================================================
--- trunk/Scribus/scribus/fonts/cff.cpp (original)
+++ trunk/Scribus/scribus/fonts/cff.cpp Thu May 21 23:40:15 2015
@@ -13,1732 +13,1732 @@
 #include <QDebug>
 
 namespace cff {
+	
+	static const char* cffDictKeys[] = {
+		"version",
+		"Notice",
+		"FullName",
+		"FamilyName",
+		"Weight",
+		"FontBBox",
+		"BlueValues",
+		"OtherBlues",
+		"FamilyBlues",
+		"FamilyOtherBlues",
+		"StdHW",
+		"StdVW",
+		"",
+		"UniqueID",
+		"XUID",
+		"charset",
+		"Encoding",
+		"CharStrings",
+		"Private",
+		"Subrs",
+		"defaultWidthX",
+		"nominalWidthX"
+	};
+	
+	static const char* cffDictKeys0c[] = {
+		"Copyright",
+		"IsFixedPitch",
+		"ItalicAngle",
+		"UnderlinePosition",
+		"UnderlineThickness",
+		"PaintType",
+		"CharstringType",
+		"FontMatrix",
+		"StrokeWidth",
+		"BlueScale",
+		"BlueShift",
+		"BlueFuzz",
+		"StemSnapH",
+		"StemSnapV",
+		"ForceBold",
+		"-Reserved-",
+		"-Reserved-",
+		"LanguageGroup",
+		"ExpansionFactor",
+		"InitialRandomSeed",
+		"SyntheticBase",
+		"PostScript",
+		"BaseFontName",
+		"BaseFontBlend",
+		"-Reserved-",
+		"-Reserved-",
+		"-Reserved-",
+		"-Reserved-",
+		"-Reserved-",
+		"-Reserved-",
+		"ROS",
+		"CIDFontVersion",
+		"CIDFontRevision",
+		"CIDFontType",
+		"CIDCount",
+		"UIDBase",
+		"FDArray",
+		"FDSelect",
+		"FontName"
+	};
+	
+	static const char* cff_operator(cff::operator_type id)
+	{
+		if ((id & 0x0c00) == 0x0c00)
+		{
+			int idx = id & 0xff;
+			if (idx >= 0 && idx <= 38)
+				return cffDictKeys0c[idx];
+			else
+				return "";
+		}
+		else
+		{
+			if ( /* id >= 0 && */  id <= 21)
+				return cffDictKeys[id];
+			else
+				return "";
+		}
+	}
+	
+	static const char* stdStrings[] = {
+		/* 0 */
+		".notdef",
+		"space",
+		"exclam",
+		"quotedbl",
+		"numbersign",
+		"dollar",
+		"percent",
+		"ampersand",
+		"quoteright",
+		"parenleft",
+		/* 10 */
+		"parenright",
+		"asterisk",
+		"plus",
+		"comma",
+		"hyphen",
+		"period",
+		"slash",
+		"zero",
+		"one",
+		"two",
+		"three",
+		"four",
+		"five",
+		"six",
+		"seven",
+		"eight",
+		"nine",
+		"colon",
+		"semicolon",
+		"less",
+		/* 30 */
+		"equal",
+		"greater",
+		"question",
+		"at",
+		"A",
+		"B",
+		"C",
+		"D",
+		"E",
+		"F",
+		"G",
+		"H",
+		"I",
+		"J",
+		"K",
+		"L",
+		"M",
+		"N",
+		"O",
+		"P",
+		/* 50 */
+		"Q",
+		"R",
+		"S",
+		"T",
+		"U",
+		"V",
+		"W",
+		"X",
+		"Y",
+		"Z",
+		"bracketleft",
+		"backslash",
+		"bracketrigh",
+		"asciicircum",
+		"underscore",
+		"quoteleft",
+		"a",
+		"b",
+		"c",
+		"d",
+		/* 70 */
+		"e",
+		"f",
+		"g",
+		"h",
+		"i",
+		"j",
+		"k",
+		"l",
+		"m",
+		"n",
+		"o",
+		"p",
+		"q",
+		"r",
+		"s",
+		"t",
+		"u",
+		"v",
+		"w",
+		"x",
+		/* 90 */
+		"y",
+		"z",
+		"braceleft",
+		"bar",
+		"braceright",
+		"asciitilde",
+		"exclamdown",
+		"cent",
+		"sterling",
+		"fraction",
+		/* 100  */
+		"yen",
+		"florin",
+		"section",
+		"currency",
+		"quotesingle",
+		"quotedblleft",
+		"guillemotleft",
+		"guilsinglleft",
+		"guilsinglright",
+		"fi",
+		"fl",
+		"endash",
+		"dagger",
+		"daggerdbl",
+		"periodcentered",
+		"paragraph",
+		"bullet",
+		"quotesinglbase",
+		"quotedblbase",
+		"quotedblright",
+		/* 120 */
+		"guillemotright",
+		"ellipsis",
+		"perthousand",
+		"questiondown",
+		"grave",
+		"acute",
+		"circumflex",
+		"tilde",
+		"macron",
+		"breve",
+		"dotaccent",
+		"dieresis",
+		"ring",
+		"cedilla",
+		"hungarumlaut",
+		"ogonek",
+		"caron",
+		"emdash",
+		"AE",
+		"ordfeminine",
+		/* 140 */
+		"Lslash",
+		"Oslash",
+		"OE",
+		"ordmasculine",
+		"ae",
+		"dotlessi",
+		"lslash",
+		"oslash",
+		"oe",
+		"germandbls",
+		"onesuperior",
+		"logicalnot",
+		"mu",
+		"trademark",
+		"Eth",
+		"onehalf",
+		"plusminus",
+		"Thorn",
+		"onequarter",
+		"divide",
+		/* 160 */
+		"brokenbar",
+		"degree",
+		"thorn",
+		"threequarters",
+		"twosuperior",
+		"registered",
+		"minus",
+		"eth",
+		"multiply",
+		"threesuperior",
+		"copyright",
+		"Aacute",
+		"Acircumflex",
+		"Adieresis",
+		"Agrave",
+		"Aring",
+		"Atilde",
+		"Ccedilla",
+		"Eacute",
+		"Ecircumflex",
+		/* 180 */
+		"Edieresis",
+		"Egrave",
+		"Iacute",
+		"Icircumflex",
+		"Idieresis",
+		"Igrave",
+		"Ntilde",
+		"Oacute",
+		"Ocircumflex",
+		"Odieresis",
+		"Ograve",
+		"Otilde",
+		"Scaron",
+		"Uacute",
+		"Ucircumflex",
+		"Udieresis",
+		"Ugrave",
+		"Yacute",
+		"Ydieresis",
+		"Zcaron",
+		/* 200 */
+		"aacute",
+		"acircumflex",
+		"adieresis",
+		"agrave",
+		"aring",
+		"atilde",
+		"ccedilla",
+		"eacute",
+		"ecircumflex",
+		"edieresis",
+		"egrave",
+		"iacute",
+		"icircumflex",
+		"idieresis",
+		"igrave",
+		"ntilde",
+		"oacute",
+		"ocircumflex",
+		"odieresis",
+		"ograve",
+		/* 220 */
+		"otilde",
+		"scaron",
+		"uacute",
+		"ucircumflex",
+		"udieresis",
+		"ugrave",
+		"yacute",
+		"ydieresis",
+		"zcaron",
+		"exclamsmall",
+		"Hungarumlautsmall",
+		"dollaroldstyle",
+		"dollarsuperior",
+		"ampersandsmall",
+		"Acutesmall",
+		"parenleftsuperior",
+		"parenrightsuperior",
+		"twodotenleader",
+		"onedotenleader",
+		"zerooldstyle",
+		/* 240 */
+		"oneoldstyle",
+		"twooldstyle",
+		"threeoldstyle",
+		"fouroldstyle",
+		"fiveoldstyle",
+		"sixoldstyle",
+		"sevenoldstyle",
+		"2eightoldstyle",
+		"nineoldstyle",
+		"commasuperior",
+		"threequartersemdash",
+		"periodsuperior",
+		"questionsmall",
+		"asuperior",
+		"bsuperior",
+		"centsuperior",
+		"dsuperior",
+		"esuperior",
+		"isuperior",
+		"lsuperior",
+		/* 260 */
+		"msuperior",
+		"nsuperior",
+		"osuperior",
+		"rsuperior",
+		"ssuperior",
+		"tsuperior",
+		"ff",
+		"ffi",
+		"ffl",
+		"parenleftinferior",
+		"parenrightinferior",
+		"Circumflexsmall",
+		"hyphensuperior",
+		"Gravesmall",
+		"Asmall",
+		"Bsmall",
+		"Csmall",
+		"Dsmall",
+		"Esmall",
+		"Fsmall",
+		/* 280 */
+		"Gsmall",
+		"Hsmall",
+		"Ismall",
+		"Jsmall",
+		"Ksmall",
+		"Lsmall",
+		"Msmall",
+		"Nsmall",
+		"Osmall",
+		"Psmall",
+		"Qsmall",
+		"Rsmall",
+		"Ssmall",
+		"Tsmall",
+		"Usmall",
+		"Vsmall",
+		"Wsmall",
+		"Xsmall",
+		"Ysmall",
+		"Zsmall",
+		/* 300 */
+		"colonmonetary",
+		"onefitted",
+		"rupiah",
+		"Tildesmall",
+		"exclamdownsmall",
+		"centoldstyle",
+		"Lslashsmall",
+		"Scaronsmall",
+		"Zcaronsmall",
+		"Dieresissmall",
+		"Brevesmall",
+		"Caronsmall",
+		"Dotaccentsmall",
+		"Macronsmall",
+		"iguredash",
+		"hypheninferior",
+		"goneksmall",
+		"Ringsmall",
+		"Cedillasmall",
+		"questiondownsmall",
+		/* 320 */
+		"oneeighth",
+		"hreeeighths",
+		"fiveeighths",
+		"seveneighths",
+		"onethird",
+		"twothirds",
+		"zerosuperior",
+		"foursuperior",
+		"fivesuperior",
+		"sixsuperior",
+		"sevensuperior",
+		"eightsuperior",
+		"ninesuperior",
+		"zeroinferior",
+		"oneinferior",
+		"twoinferior",
+		"threeinferior",
+		"fourinferior",
+		"fiveinferior",
+		"sixinferior",
+		/* 340 */
+		"seveninferior",
+		"eightinferior",
+		"nineinferior",
+		"centinferior",
+		"dollarinferior",
+		"periodinferior",
+		"commainferior",
+		"Agravesmall",
+		"Aacutesmall",
+		"Acircumflexsmall",
+		"Atildesmall",
+		"Adieresissmall",
+		"Aringsmall",
+		"AEsmall",
+		"Ccedillasmall",
+		"Egravesmall",
+		"Eacutesmall",
+		"Ecircumflexsmall",
+		"Edieresissmall",
+		"Igravesmall",
+		/* 360 */
+		"Iacutesmall",
+		"Icircumflexsmall",
+		"Idieresissmall",
+		"Ethsmall",
+		"Ntildesmall",
+		"Ogravesmall",
+		"Oacutesmall",
+		"Ocircumflexsmall",
+		"Otildesmall",
+		"Odieresissmall",
+		"OEsmall",
+		"Oslashsmall",
+		"Ugravesmall",
+		"Uacutesmall",
+		"Ucircumflexsmall",
+		"Udieresissmall",
+		"Yacutesmall",
+		"Thornsmall",
+		"Ydieresissmall",
+		"001.000",
+		/* 380 */
+		"001.001",
+		"001.002",
+		"001.003",
+		"Black",
+		"Bold",
+		"Book",
+		"Light",
+		"Medium",
+		"Regular",
+		"Roman",
+		/* 390 */
+		"Semibold"
+	};
+	
+	bool CFF_Number::isCardinal() const
+	{
+		switch (type)
+		{
+			case cff_varnt_Error:
+			case cff_varnt_Real:
+				return false;
+			default:
+				return true;
+		}
+	}
+	
+	double CFF_Number::toDouble() const
+	{
+		switch (type)
+		{
+			case cff_varnt_Real:
+				return card * std::pow(10.0, exponent);
+			default:
+				return toCardinal();
+		}
+
+	}
+	
+	int CFF_Number::toCardinal() const
+	{
+		return card;
+	}
+
+	
+	CFF::CFF() : bytes(), offsetSize(4)
+	{
+		for (int i = 0; i <= sid_last_std; ++i)
+		{
+			strings.append(stdStrings[i]);
+			sids[stdStrings[i]] = i;
+		}
+	}
+	
+	
+	CFF::CFF(const QByteArray& cff) : bytes(cff)
+	{
+		// read header
+		offsetSize = cff[cff_offSize];
+		uint pos = cff[cff_hdrSize];
+		qDebug() << "cff header" << offsetSize << "starts" << pos;
+		// read names
+		names = readIndex(pos);
+		// read top dicts
+		QList<QByteArray> topDicts = readIndex(pos);
+		for (int i = 0; i < names.length(); ++i)
+		{
+			QByteArray fontName = names[i];
+			qDebug() << i << fontName;
+			if (fontName.length() > 0 && fontName[0] != char(0))
+			{
+				fontTopDicts[fontName] = getDict(topDicts[i]);
+				uint privLength = fontTopDicts[fontName][18].array[0].toCardinal();
+				uint privOffset = fontTopDicts[fontName][18].array[1].toCardinal();
+				getDict(readSegment(privOffset, privLength));
+			}
+		}
+		// read strings
+		for (int i = 0; i <= sid_last_std; ++i)
+		{
+			strings.append(stdStrings[i]);
+		}
+		strings.append(readIndex(pos));
+		for (int i = 0; i < strings.length(); ++i)
+		{
+//			if ( i > sid_last_std)
+//				qDebug() << i << strings[i];
+			sids[strings[i]] = i;
+		}
+		// read global subroutines
+		globalSubr = readIndex(pos);
+	}
+	
+	
+	QByteArray CFF::readSegment(uint pos, uint size) const
+	{
+		return QByteArray::fromRawData(bytes.data() + pos, size);
+	}
+	
+	
+	uint CFF::readCard(uint pos) const
+	{
+		return static_cast<uchar>(bytes[pos]) << 8 | static_cast<uchar>(bytes[pos+1]);
+	}
+	
+	
+	
+	QMap<operator_type,CFF_Variant> CFF::getDict(const QByteArray& dict) const
+	{
+		QMap<uint,CFF_Variant> result;
+		QList<CFF_Number> stack;
+		
+		uint pos = 0;
+		while (pos < dict.length())
+		{
+			CFF_Number num = parseDictElement(dict, pos);
+			if (num.type == cff_varnt_Operator)
+			{
+				if (stack.length() == 1)
+				{
+					result[num.card] = CFF_Variant(stack[0]);
+				}
+				else if (stack.length() > 0)
+				{
+					result[num.card] = CFF_Variant(stack);
+				}
+				else
+				{
+					/* error */
+				}
+				stack = QList<CFF_Number>();
+			}
+			else
+			{
+				stack.append(num);
+			}
+		}
+		if (stack.length() > 0)
+		{
+			/* error */
+		}
+		// TODO: adapt variant type according to operator
+		return result;
+	}
+	
+	
+	CFF_Number CFF::parseDictElement(const QByteArray& dict, uint& pos) const
+	{
+		uint code = dict[pos];
+		switch (code)
+		{
+			case cff_dict_TwoBytes:
+				code = (code << 8) | dict[++pos];
+				break;
+			case cff_dict_Card16:
+			case cff_dict_Card32:
+				return parseCard(dict, pos);
+			case cff_dict_Real:
+				return parseReal(dict, pos);
+
+			default:
+				if (code >= cff_dict_minOperand)
+				{
+					return parseCard(dict, pos);
+				}
+				break;
+		}
+		++pos;
+		CFF_Number num;
+		num.type = cff_varnt_Operator;
+		num.card = code;
+		qDebug() << "parsed operator" << cff_operator(code) << "(" << code << ")";
+		return num;
+	}
+	
+	
+	CFF_Number CFF::parseCard(const QByteArray& dict, uint& pos) const
+	{
+		CFF_Number result;
+		result.type = cff_varnt_Card;
+		result.exponent = 0;
+		uint start=pos;
+		uchar b0 = dict[pos++];
+		uchar b1,b2,b3,b4;
+		if (b0 == cff_dict_Card16)
+		{
+			b1 = dict[pos++];
+			b2 = dict[pos++];
+			result.card = static_cast<qint16>((b1 << 8) | b2);
+		}
+		else if (b0 == cff_dict_Card32)
+		{
+			b1 = dict[pos++];
+			b2 = dict[pos++];
+			b3 = dict[pos++];
+			b4 = dict[pos++];
+			result.card = static_cast<qint32>((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
+		}
+		else if (b0 < cff_dict_minOperand)
+		{
+			/* error */
+		}
+		else if (b0 <= cff_dict_maxSmallCard)
+		{
+			result.card = b0 + cff_dict_biasSmallCard;
+		}
+		else if (b0 <= cff_dict_maxPosCard)
+		{
+			b1 = dict[pos++];
+			result.card = (b0 - cff_dict_minPosCard) * 256 + b1 + cff_dict_biasPosCard;
+		}
+		else if (b0 <= cff_dict_maxNegCard)
+		{
+			b1 = dict[pos++];
+			result.card = (cff_dict_minNegCard - b0) * 256 - b1 + cff_dict_biasNegCard;
+		}
+		else
+		{
+			/* error */
+		}
+		qDebug() << "parsed" << QByteArray::fromRawData(dict.data()+start, pos-start).toHex() << "to card " << result.card;
+		return result;
+	}
+	
+	
+	CFF_Number CFF::parseReal(const QByteArray& dict, uint& pos) const
+	{
+		assert( dict[pos] == cff_dict_Real );
+		uint start = pos++;
+
+		CFF_Number result;
+		result.type = cff_varnt_Real;
+		result.card = 0;
+		result.exponent = 0;
+		bool upperNibble = false;
+		bool haveSeenMinus = false;
+		bool haveSeenE = false;;
+		bool haveSeenEminus = false;
+		int decimalPointAt = -1;
+		uchar nibble, twoNibbles;
+		do
+		{
+			// get nibble
+			if (upperNibble)
+			{
+				nibble = twoNibbles & 0x0f;
+				upperNibble = false;
+			}
+			else
+			{
+				twoNibbles = dict[pos++];
+				nibble = twoNibbles >> 4;
+				upperNibble = true;
+			}
+			
+			// decode
+			switch (nibble)
+			{
+				case cff_nibble_Minus:
+					haveSeenMinus = !haveSeenMinus;
+					break;
+				case cff_nibble_Point:
+					decimalPointAt = 0;
+					break;
+				case cff_nibble_PosExp:
+					haveSeenE = true;
+					break;
+				case cff_nibble_NegExp:
+					haveSeenEminus = true;
+					break;
+				case cff_nibble_End:
+					break;
+				default:
+					if (nibble > cff_nibble_maxDigit)
+					{
+						/* error */
+					}
+					else if (haveSeenE || haveSeenEminus)
+					{
+						result.exponent *= 10;
+						result.exponent += nibble;
+					}
+					else
+					{
+						result.card *= 10;
+						result.card += nibble;
+						if (decimalPointAt >= 0)
+						{
+							++decimalPointAt;
+						}
+					}
+					break;
+			}
+		} while (nibble != cff_nibble_End);
+			
+		// finish
+		if (haveSeenMinus)
+			result.card = -result.card;
+		if (haveSeenEminus)
+			result.exponent = -result.exponent;
+		if (decimalPointAt > 0)
+			result.exponent -= decimalPointAt;
+		qDebug() << "parsed" << QByteArray::fromRawData(dict.data()+start, pos-start).toHex() << "to real " << result.card << "E" << result.exponent;
+
+		return result;
+	}
+	
+	
+	QList<QByteArray> CFF::readIndex(uint& pos) const
+	{
+		qDebug() << "read INDEX @" << pos;
+		QList<QByteArray> result;
+		uint N = readCard(pos);
+		pos += 2;
+		uint offSize = bytes[pos++];
+		uint dataStart = pos + offSize * (N+1) - 1;
+		qDebug() << "size" << N << "offsetsize" << offSize << "dataStart" << dataStart;
+		uint start = 0;
+		uint end;
+		for (uint c = 0; c < offSize; ++c)
+		{
+			start = start << 8 | (uchar) bytes[pos++];
+		}
+		start += dataStart;
+		for (uint i = 0; i < N; ++i)
+		{
+			end = 0;
+			for (uint c = 0; c < offSize; ++c)
+			{
+				end = end << 8 | (uchar) bytes[pos++];
+			}
+			end += dataStart;
+			result.append(readSegment(start, end-start));
+			start = end;
+		}
+		pos = end;
+		qDebug() << "INDEX ends @" << end;
+		return result;
+	}
+	
+	
+	QList<uint> CFF::readEncoding(uint& pos) const
+	{
+		QList<uint> result;
+		for(int i = 0; i < 256; ++i)
+			result.append(0);
+		
+		uchar format = bytes[pos++];
+		uchar N = bytes[pos++];
+		int gid;
+		uchar code;
+		switch (format)
+		{
+			case 0x0:
+			case 0x80:
+				for (gid = 1; gid <= N; ++gid)
+				{
+					code = bytes[pos++];
+					if (result[code] == 0)
+					{
+						result[code] = gid;
+					}
+				}
+				break;
+			case 0x1:
+			case 0x81:
+				gid = 1;
+				for (int r = 0; r < N; ++r)
+				{
+					uchar first = bytes[pos++];
+					uchar nLeft = bytes[pos++];
+					for (code = first; code <= first + nLeft; ++code)
+					{
+						if (result[code] == 0)
+						{
+							result[code] = gid;
+						}
+						++gid;
+					}
+				}
+				break;
+		}
+		if (format >= 0x80)
+		{
+			uchar nSupplements = bytes[pos++];
+			for (int i = 0; i < nSupplements; ++i)
+			{
+				code = bytes[pos++];
+				gid = readCard(pos);
+				pos += 2;
+				result[code] = gid;
+			}
+		}
+		return result;
+	}
+	
+	
+	QList<sid_type> CFF::readCharset(uint nGlyphs, uint& pos) const
+	{
+		QList<sid_type> result;
+		result.append(0); // sid for .notdef
+		
+		uchar format = bytes[pos++];
+		
+		sid_type first;
+		uchar nLeft1;
+		uint nLeft2;
+		
+		switch (format)
+		{
+			case 0:
+				for (uint gid = 1; gid < nGlyphs; ++gid)
+				{
+					result.append(readCard(pos));
+					pos += 2;
+				}
+				break;
+			case 1:
+				while (result.length() < nGlyphs)
+				{
+					first = readCard(pos);
+					pos += 2;
+					nLeft1 = bytes[pos++];
+					for (sid_type sid = first; sid <= first + nLeft1; ++sid)
+					{
+						result.append(sid);
+					}
+				}
+				break;
+			case 2:
+				while (result.length() < nGlyphs)
+				{
+					first = readCard(pos);
+					pos += 2;
+					nLeft2 = readCard(pos);
+					pos += 2;
+					for (sid_type sid = first; sid <= first + nLeft2; ++sid)
+					{
+						result.append(sid);
+					}
+				}
+				break;
+		}
+		return result;
+	}
+	
+	
+	QByteArray CFF::dump(const CFF_Variant& var) const
+	{
+		QByteArray result;
+		switch(var.type)
+		{
+			case cff_varnt_Error:
+				result += "ERROR";
+				break;
+			case cff_varnt_Card:
+			case cff_varnt_Bool:
+			case cff_varnt_SID:
+				result += QByteArray::number(var.array[0].toCardinal());
+				break;
+			case cff_varnt_Real:
+				result += QByteArray::number(var.array[0].toDouble());
+				break;
+			case cff_varnt_Operator:
+				result += string(var.array[0].toCardinal());
+				result += " (";
+				result += QByteArray::number(var.array[0].toCardinal());
+				result +=")";
+				break;
+			case cff_varnt_Delta:
+				result += "Delta";
+				/* fall thru */
+			case cff_varnt_Array:
+				result += "[";
+				for (int i = 0; i < var.array.length(); ++i)
+				{
+					result += QByteArray::number(var.array[i].toDouble());
+					result += ", ";
+				}
+				result.chop(2);
+				result += "]";
+				break;
+		}
+		return result;
+	}
+	
+	
+	void CFF::dump()
+	{
+		qDebug() << "CFF" << fontTopDicts.count() << "fonts, size =" << bytes.size() << "offset size=" << offsetSize;
+		QMap<QByteArray,QMap<operator_type,CFF_Variant> >::Iterator it;
+		for (it = fontTopDicts.begin(); it != fontTopDicts.end(); ++it)
+		{
+			qDebug() << "Font" << it.key() << ":";
+			QMap<operator_type, CFF_Variant>::Iterator it2;
+			for (it2= it.value().begin(); it2 != it.value().end(); ++it2)
+			{
+				qDebug() << "\t" << cff_operator(it2.key()) << "=" << dump(it2.value());
+			}
+		}
+	}
+	
+	
+	static QByteArray num(uint n)
+	{
+		return QByteArray::number(n);
+	}
+	
+	
+	static void write(QDataStream& out, const QByteArray& data)
+	{
+		out.writeRawData(data.data(), data.length());
+	}
+	
+	static void dumpData(const QList<QByteArray>& index, QDataStream& out, const QByteArray& indent)
+	{
+		for (int i = 0; i < index.length(); ++i)
+		{
+			write(out, indent);
+			write(out, "<data idx='");
+			write(out, num(i));
+			write(out, "' length='");
+			write(out, num(index[i].length()));
+			write(out, "' >");
+			write(out, index[i].toHex());
+			write(out, "</data>\n");
+		}
+	}
+
+	static void dumpStrings(const QList<QByteArray>& index, QDataStream& out, const QByteArray& indent)
+	{
+		for (int i = 0; i < index.length(); ++i)
+		{
+			write(out, indent);
+			write(out, "<string idx='");
+			write(out, num(i));
+			write(out, "' length='");
+			write(out, num(index[i].length()));
+			write(out, "' >");
+			write(out, index[i]);
+			write(out, "</string>\n");
+		}
+	}
+
+	static void dumpDict(const CFF& cff, const QMap<operator_type,CFF_Variant>& dict, QDataStream& out, const QByteArray& indent)
+	{
+		QMap<operator_type,CFF_Variant>::ConstIterator it;
+		for (it = dict.cbegin(); it != dict.cend(); ++it)
+		{
+			write(out, indent);
+			write(out, "<keyvalue key='");
+			write(out, cff_operator(it.key()));
+			write(out, "' value='");
+			write(out, cff.dump(it.value()));
+			write(out, "' />\n");
+		}
+	}
+	
+	void CFF::dump(QDataStream& out) const
+	{
+		write(out, "<CFF version='1.0' offsetSize='" + num(offsetSize) + "' >\n");
+		for (int f = 0; f < names.length(); ++f)
+		{
+			QByteArray font = names[f];
+			QMap<operator_type, CFF_Variant> topDict = fontTopDicts[font];
+			write(out, "  <Font name='" + font + "' >\n");
+			write(out, "    <TopDict>");
+			dumpDict(*this, topDict, out, "      ");
+			write(out, "    </TopDict>\n");
+			uint pos;
+			if (topDict.contains(cff_dict_Encoding))
+			{
+				uint encOffset = topDict[cff_dict_Encoding].array[0].toCardinal();
+				if (encOffset > 4)
+				{
+					write(out, "    <Encoding>\n    ");
+					pos = encOffset;
+					QList<uint> enc = readEncoding(pos);
+					write(out, readSegment(encOffset, pos-encOffset).toHex());
+					write(out, "\n    </Encoding>\n");
+				}
+				else
+					write(out, "    <Encoding predefined='" + num(encOffset) + "' />\n");
+			}
+			pos = topDict[cff_dict_CharStrings].array[0].toCardinal();
+			QList<QByteArray> charStrings = readIndex(pos);
+			uint nglyphs = charStrings.length();
+			if (topDict.contains(cff_dict_charset))
+			{
+				uint charsetOffset = topDict[cff_dict_charset].array[0].toCardinal();
+				if (charsetOffset > 4)
+				{
+					pos = charsetOffset;
+					QList<sid_type> charset = readCharset(nglyphs, pos);
+					write(out, "    <charset>\n");
+					for (int i=0; i < charset.length(); ++i)
+					{
+						write(out, "      <char gid='" + num(i) + "' sid='" + num(charset[i]) + "' >");
+						write(out, string(charset[i]) + "</char>\n");
+					}
+					write(out, "    </charset>\n");
+				}
+			}
+			write(out, "    <CharStrings>\n");
+			dumpData(charStrings, out, "      ");
+			write(out, "    </CharStrings>\n");
+			uint privateLength = topDict[cff_dict_Private].array[0].toCardinal();
+			uint privateOffset = topDict[cff_dict_Private].array[1].toCardinal();
+			write(out, "    <PrivateDict offset='" + num(privateOffset) + "' length='" + num(privateLength) + ">\n");
+			QMap<operator_type,CFF_Variant> privateDict = getDict(readSegment(privateOffset, privateLength));
+			dumpDict(*this, privateDict, out, "      ");
+			write(out, "    </PrivateDict>\n");
+			if (privateDict.contains(cff_dict_Subrs))
+			{
+				uint subrsOffset = privateDict[cff_dict_Subrs].array[0].toCardinal();
+				pos = privateOffset + subrsOffset;
+				QList<QByteArray> localSubrs = readIndex(pos);
+				write(out, "    <LocalSubrs offset='" + num(subrsOffset) + "' length='" + num(pos-subrsOffset) + "' >\n");
+				dumpData(localSubrs, out, "      ");
+				write(out, "    </LocalSubrs>\n");
+			}
+			write(out, "  </Font>\n");
+		}
+		write(out, "  <Strings>\n");
+		dumpStrings(strings, out, "    ");
+		write(out, "  </Strings>\n");
+		write(out, "  <GlobalSubrs>\n");
+		dumpData(globalSubr, out, "    ");
+		write(out, "  </GlobalSubrs>\n");
+		write(out, "</CFF>\n");
+	}
     
-    static const char* cffDictKeys[] = {
-        "version",
-        "Notice",
-        "FullName",
-        "FamilyName",
-        "Weight",
-        "FontBBox",
-        "BlueValues",
-        "OtherBlues",
-        "FamilyBlues",
-        "FamilyOtherBlues",
-        "StdHW",
-        "StdVW",
-        "",
-        "UniqueID",
-        "XUID",
-        "charset",
-        "Encoding",
-        "CharStrings",
-        "Private",
-        "Subrs",
-        "defaultWidthX",
-        "nominalWidthX"
-    };
-    
-    static const char* cffDictKeys0c[] = {
-        "Copyright",
-        "IsFixedPitch",
-        "ItalicAngle",
-        "UnderlinePosition",
-        "UnderlineThickness",
-        "PaintType",
-        "CharstringType",
-        "FontMatrix",
-        "StrokeWidth",
-        "BlueScale",
-        "BlueShift",
-        "BlueFuzz",
-        "StemSnapH",
-        "StemSnapV",
-        "ForceBold",
-        "-Reserved-",
-        "-Reserved-",
-        "LanguageGroup",
-        "ExpansionFactor",
-        "InitialRandomSeed",
-        "SyntheticBase",
-        "PostScript",
-        "BaseFontName",
-        "BaseFontBlend",
-        "-Reserved-",
-        "-Reserved-",
-        "-Reserved-",
-        "-Reserved-",
-        "-Reserved-",
-        "-Reserved-",
-        "ROS",
-        "CIDFontVersion",
-        "CIDFontRevision",
-        "CIDFontType",
-        "CIDCount",
-        "UIDBase",
-        "FDArray",
-        "FDSelect",
-        "FontName"
-    };
-    
-    static const char* cff_operator(cff::operator_type id)
-    {
-        if ((id & 0x0c00) == 0x0c00)
-        {
-            int idx = id & 0xff;
-            if (idx >= 0 && idx <= 38)
-                return cffDictKeys0c[idx];
-            else
-                return "";
-        }
-        else
-        {
-            if ( /* id >= 0 && */  id <= 21)
-                return cffDictKeys[id];
-            else
-                return "";
-        }
-    }
-    
-    static const char* stdStrings[] = {
-        /* 0 */
-        ".notdef",
-        "space",
-        "exclam",
-        "quotedbl",
-        "numbersign",
-        "dollar",
-        "percent",
-        "ampersand",
-        "quoteright",
-        "parenleft",
-        /* 10 */
-        "parenright",
-        "asterisk",
-        "plus",
-        "comma",
-        "hyphen",
-        "period",
-        "slash",
-        "zero",
-        "one",
-        "two",
-        "three",
-        "four",
-        "five",
-        "six",
-        "seven",
-        "eight",
-        "nine",
-        "colon",
-        "semicolon",
-        "less",
-        /* 30 */
-        "equal",
-        "greater",
-        "question",
-        "at",
-        "A",
-        "B",
-        "C",
-        "D",
-        "E",
-        "F",
-        "G",
-        "H",
-        "I",
-        "J",
-        "K",
-        "L",
-        "M",
-        "N",
-        "O",
-        "P",
-        /* 50 */
-        "Q",
-        "R",
-        "S",
-        "T",
-        "U",
-        "V",
-        "W",
-        "X",
-        "Y",
-        "Z",
-        "bracketleft",
-        "backslash",
-        "bracketrigh",
-        "asciicircum",
-        "underscore",
-        "quoteleft",
-        "a",
-        "b",
-        "c",
-        "d",
-        /* 70 */
-        "e",
-        "f",
-        "g",
-        "h",
-        "i",
-        "j",
-        "k",
-        "l",
-        "m",
-        "n",
-        "o",
-        "p",
-        "q",
-        "r",
-        "s",
-        "t",
-        "u",
-        "v",
-        "w",
-        "x",
-        /* 90 */
-        "y",
-        "z",
-        "braceleft",
-        "bar",
-        "braceright",
-        "asciitilde",
-        "exclamdown",
-        "cent",
-        "sterling",
-        "fraction",
-        /* 100  */
-        "yen",
-        "florin",
-        "section",
-        "currency",
-        "quotesingle",
-        "quotedblleft",
-        "guillemotleft",
-        "guilsinglleft",
-        "guilsinglright",
-        "fi",
-        "fl",
-        "endash",
-        "dagger",
-        "daggerdbl",
-        "periodcentered",
-        "paragraph",
-        "bullet",
-        "quotesinglbase",
-        "quotedblbase",
-        "quotedblright",
-        /* 120 */
-        "guillemotright",
-        "ellipsis",
-        "perthousand",
-        "questiondown",
-        "grave",
-        "acute",
-        "circumflex",
-        "tilde",
-        "macron",
-        "breve",
-        "dotaccent",
-        "dieresis",
-        "ring",
-        "cedilla",
-        "hungarumlaut",
-        "ogonek",
-        "caron",
-        "emdash",
-        "AE",
-        "ordfeminine",
-        /* 140 */
-        "Lslash",
-        "Oslash",
-        "OE",
-        "ordmasculine",
-        "ae",
-        "dotlessi",
-        "lslash",
-        "oslash",
-        "oe",
-        "germandbls",
-        "onesuperior",
-        "logicalnot",
-        "mu",
-        "trademark",
-        "Eth",
-        "onehalf",
-        "plusminus",
-        "Thorn",
-        "onequarter",
-        "divide",
-        /* 160 */
-        "brokenbar",
-        "degree",
-        "thorn",
-        "threequarters",
-        "twosuperior",
-        "registered",
-        "minus",
-        "eth",
-        "multiply",
-        "threesuperior",
-        "copyright",
-        "Aacute",
-        "Acircumflex",
-        "Adieresis",
-        "Agrave",
-        "Aring",
-        "Atilde",
-        "Ccedilla",
-        "Eacute",
-        "Ecircumflex",
-        /* 180 */
-        "Edieresis",
-        "Egrave",
-        "Iacute",
-        "Icircumflex",
-        "Idieresis",
-        "Igrave",
-        "Ntilde",
-        "Oacute",
-        "Ocircumflex",
-        "Odieresis",
-        "Ograve",
-        "Otilde",
-        "Scaron",
-        "Uacute",
-        "Ucircumflex",
-        "Udieresis",
-        "Ugrave",
-        "Yacute",
-        "Ydieresis",
-        "Zcaron",
-        /* 200 */
-        "aacute",
-        "acircumflex",
-        "adieresis",
-        "agrave",
-        "aring",
-        "atilde",
-        "ccedilla",
-        "eacute",
-        "ecircumflex",
-        "edieresis",
-        "egrave",
-        "iacute",
-        "icircumflex",
-        "idieresis",
-        "igrave",
-        "ntilde",
-        "oacute",
-        "ocircumflex",
-        "odieresis",
-        "ograve",
-        /* 220 */
-        "otilde",
-        "scaron",
-        "uacute",
-        "ucircumflex",
-        "udieresis",
-        "ugrave",
-        "yacute",
-        "ydieresis",
-        "zcaron",
-        "exclamsmall",
-        "Hungarumlautsmall",
-        "dollaroldstyle",
-        "dollarsuperior",
-        "ampersandsmall",
-        "Acutesmall",
-        "parenleftsuperior",
-        "parenrightsuperior",
-        "twodotenleader",
-        "onedotenleader",
-        "zerooldstyle",
-        /* 240 */
-        "oneoldstyle",
-        "twooldstyle",
-        "threeoldstyle",
-        "fouroldstyle",
-        "fiveoldstyle",
-        "sixoldstyle",
-        "sevenoldstyle",
-        "2eightoldstyle",
-        "nineoldstyle",
-        "commasuperior",
-        "threequartersemdash",
-        "periodsuperior",
-        "questionsmall",
-        "asuperior",
-        "bsuperior",
-        "centsuperior",
-        "dsuperior",
-        "esuperior",
-        "isuperior",
-        "lsuperior",
-        /* 260 */
-        "msuperior",
-        "nsuperior",
-        "osuperior",
-        "rsuperior",
-        "ssuperior",
-        "tsuperior",
-        "ff",
-        "ffi",
-        "ffl",
-        "parenleftinferior",
-        "parenrightinferior",
-        "Circumflexsmall",
-        "hyphensuperior",
-        "Gravesmall",
-        "Asmall",
-        "Bsmall",
-        "Csmall",
-        "Dsmall",
-        "Esmall",
-        "Fsmall",
-        /* 280 */
-        "Gsmall",
-        "Hsmall",
-        "Ismall",
-        "Jsmall",
-        "Ksmall",
-        "Lsmall",
-        "Msmall",
-        "Nsmall",
-        "Osmall",
-        "Psmall",
-        "Qsmall",
-        "Rsmall",
-        "Ssmall",
-        "Tsmall",
-        "Usmall",
-        "Vsmall",
-        "Wsmall",
-        "Xsmall",
-        "Ysmall",
-        "Zsmall",
-        /* 300 */
-        "colonmonetary",
-        "onefitted",
-        "rupiah",
-        "Tildesmall",
-        "exclamdownsmall",
-        "centoldstyle",
-        "Lslashsmall",
-        "Scaronsmall",
-        "Zcaronsmall",
-        "Dieresissmall",
-        "Brevesmall",
-        "Caronsmall",
-        "Dotaccentsmall",
-        "Macronsmall",
-        "iguredash",
-        "hypheninferior",
-        "goneksmall",
-        "Ringsmall",
-        "Cedillasmall",
-        "questiondownsmall",
-        /* 320 */
-        "oneeighth",
-        "hreeeighths",
-        "fiveeighths",
-        "seveneighths",
-        "onethird",
-        "twothirds",
-        "zerosuperior",
-        "foursuperior",
-        "fivesuperior",
-        "sixsuperior",
-        "sevensuperior",
-        "eightsuperior",
-        "ninesuperior",
-        "zeroinferior",
-        "oneinferior",
-        "twoinferior",
-        "threeinferior",
-        "fourinferior",
-        "fiveinferior",
-        "sixinferior",
-        /* 340 */
-        "seveninferior",
-        "eightinferior",
-        "nineinferior",
-        "centinferior",
-        "dollarinferior",
-        "periodinferior",
-        "commainferior",
-        "Agravesmall",
-        "Aacutesmall",
-        "Acircumflexsmall",
-        "Atildesmall",
-        "Adieresissmall",
-        "Aringsmall",
-        "AEsmall",
-        "Ccedillasmall",
-        "Egravesmall",
-        "Eacutesmall",
-        "Ecircumflexsmall",
-        "Edieresissmall",
-        "Igravesmall",
-        /* 360 */
-        "Iacutesmall",
-        "Icircumflexsmall",
-        "Idieresissmall",
-        "Ethsmall",
-        "Ntildesmall",
-        "Ogravesmall",
-        "Oacutesmall",
-        "Ocircumflexsmall",
-        "Otildesmall",
-        "Odieresissmall",
-        "OEsmall",
-        "Oslashsmall",
-        "Ugravesmall",
-        "Uacutesmall",
-        "Ucircumflexsmall",
-        "Udieresissmall",
-        "Yacutesmall",
-        "Thornsmall",
-        "Ydieresissmall",
-        "001.000",
-        /* 380 */
-        "001.001",
-        "001.002",
-        "001.003",
-        "Black",
-        "Bold",
-        "Book",
-        "Light",
-        "Medium",
-        "Regular",
-        "Roman",
-        /* 390 */
-        "Semibold"
-    };
-    
-    bool CFF_Number::isCardinal() const
-    {
-        switch (type)
-        {
-            case cff_varnt_Error:
-            case cff_varnt_Real:
-                return false;
-            default:
-                return true;
-        }
-    }
-    
-    double CFF_Number::toDouble() const
-    {
-        switch (type)
-        {
-            case cff_varnt_Real:
-                return card * std::pow(10.0, exponent);
-            default:
-                return toCardinal();
-        }
+	/// encodes 'value' as exactly 'nBytes' bytes in Big Endian
+	static QByteArray encodeBE(int nbytes, uint value)
+	{
+		QByteArray result;
+		while (nbytes-- > 0)
+		{
+			result.prepend(static_cast<uchar>(value & 0xFF));
+			value >>= 8;
+		}
+		return result;
+	}
+	
+	
+	/// calculates the required offset size to represent 'dataLength'
+	static int requiredOffsetSize(int dataLength)
+	{
+		if (dataLength < 255)
+			return 1;
+		else if (dataLength < 65535)
+			return 2;
+		else if (dataLength < 0xFFFFFF)
+			return 3;
+		else
+			return 4;
+	}
+	
+	
+	static void writeCard(QByteArray& bytes, int val)
+	{
+		int biasedVal = val - cff_dict_biasSmallCard;
+		if (biasedVal >= cff_dict_minOperand && biasedVal <= cff_dict_maxSmallCard)
+		{
+			bytes.append((char) biasedVal);
+			return;
+		}
+		if (val > 0)
+		{
+			biasedVal = val - cff_dict_biasPosCard;
+			if (biasedVal >= 0 &&  biasedVal <= 1023)
+			{
+				biasedVal += (cff_dict_minPosCard << 8);
+				bytes.append(encodeBE(2, biasedVal));
+				qDebug() << "writeCard" << val << "as" << encodeBE(2, biasedVal).toHex();
+				return;
+			};
+		}
+		else
+		{
+			biasedVal = -val + cff_dict_biasNegCard;
+			if (biasedVal >= 0 &&  biasedVal <= 1023)
+			{
+				biasedVal += (cff_dict_minNegCard << 8);
+				bytes.append(encodeBE(2, biasedVal));
+				qDebug() << "writeCard" << val << "as" << encodeBE(2, biasedVal).toHex();
+				return;
+			};
+		}
+		if (val >= -32768 && val <= 32767)
+		{
+			bytes.append((char) cff_dict_Card16);
+			bytes.append(encodeBE(2, val));
+		}
+		else
+		{
+			bytes.append((char) cff_dict_Card32);
+			bytes.append(encodeBE(4, val));
+		}
+	}
+	
+	
+	/// creates one byte per digit (not ASCII!)
+	static QByteArray bsdNibbles(long long val)
+	{
+		QByteArray result;
+		if (val < 0)
+			val = -val;
+		
+		do {
+			result.prepend((char) (val % 10));
+			val /= 10;
+		}
+		while (val != 0);
+		
+		return result;
+	}
+	
+	
+	static void writeReal(QByteArray& bytes, CFF_Number num)
+	{
+		QByteArray bsd;
+		if (num.card < 0)
+		{
+			bsd.append((char) cff_nibble_Minus);
+			bsd.append(bsdNibbles(-num.card));
+		}
+		else
+		{
+			bsd.append(bsdNibbles(num.card));
+		}
+		if (num.exponent < 0)
+		{
+			bsd.append((char) cff_nibble_NegExp);
+			bsd.append(bsdNibbles(-num.exponent));
+		}
+		else if (num.exponent > 0)
+		{
+			bsd.append((char) cff_nibble_PosExp);
+			bsd.append(bsdNibbles(num.exponent));
+		}
+		bsd.append((char) cff_nibble_End);
+		if (bsd.length() % 2 == 1)
+			bsd.append((char) cff_nibble_End);
+		
+		uint start = bytes.length();
+		bytes.append((char) cff_dict_Real);
+		for (int i= 0; i < bsd.length(); i += 2)
+		{
+			bytes.append((char) ((bsd[i] << 4) | bsd[i+1]));
+		}
+		qDebug() << "writeReal" << num.card << "E" << num.exponent << "as" << bytes.mid(start).toHex();
+	}
+	
+	
+	uint CFF::writeSegment(const QByteArray& data)
+	{
+		uint result = bytes.length();
+		bytes.append(data);
+		return result;
+	}
+	
+	
+	sid_type CFF::createSid(const QByteArray& str)
+	{
+		sid_type result;
+		if (!sids.contains(str))
+		{
+			result = strings.length();
+			strings.append(str);
+			sids[str] = result;
+			qDebug() << "new SID" << result << "for" << str;
+		}
+		else
+		{
+			result = sids[str];
+		}
+		return result;
+	}
+	
+	
+	uint CFF::writeTopDict(QByteArray name,
+	                       QMap<operator_type, CFF_Variant> dict,
+	                       QList<QByteArray> oldStrings,
+	                       QHash<operator_type, uint>& patchAddresses)
+	{
+		offsetSize = 4;
+		names.append(name);
+		fontTopDicts[name] = dict;
+		bytes.append((char) 1);
+		bytes.append((char) 0);                     // format 1.0
+		bytes.append((char) 4);                     // header length 4
+		bytes.append((char) 4);                     // offsetSize 4
+		
+		// write Name index
+		bytes.append(encodeBE(2,1));                  // count
+		assert (name.length() < 255);
+		bytes.append(encodeBE(1, 1));                 // offSize
+		bytes.append(encodeBE(1, 1));                 // offset 1
+		bytes.append(encodeBE(1, 1 + name.length())); // offset 2
+		bytes.append(name);
+		
+		
+		// write TopDict index
+		QByteArray topDict = makeDict(dict, oldStrings, patchAddresses);
+		int offSize = requiredOffsetSize(topDict.length());
+		bytes.append(encodeBE(2, 1));                          // count
+		bytes.append(encodeBE(1, offSize));                    // offSize
+		bytes.append(encodeBE(offSize, 1));                    // offset 1
+		bytes.append(encodeBE(offSize, 1 + topDict.length())); // offset 2
+		uint start = bytes.size();
+		bytes.append(topDict);
+		return start;
+	}
+	
+	
+	QByteArray CFF::makeDict(QMap<operator_type, CFF_Variant> dict,
+	                         QList<QByteArray> oldStrings,
+	                         QHash<operator_type, uint>& patchAddresses)
+	{
+		QByteArray result;
+		if (dict.contains(cff_dict_ROS))
+		{
+			// pull to front
+			QList<CFF_Number> ros = dict[cff_dict_ROS].array;
+			sid_type sid = ros[0].toCardinal();
+			sid = createSid(oldStrings[sid]);
+			writeCard(result, sid);
+			sid = ros[1].toCardinal();
+			sid = createSid(oldStrings[sid]);
+			writeCard(result, sid);
+			writeCard(result, ros[2].toCardinal());
+			result.append(encodeBE(2, cff_dict_ROS));
 
-    }
-    
-    int CFF_Number::toCardinal() const
-    {
-        return card;
-    }
+		}
+		if (dict.contains(cff_dict_SyntheticBase))
+		{
+			// pull to front
+			writeCard(result, dict[cff_dict_ROS].array[0].toCardinal());
+			result.append(encodeBE(2, cff_dict_SyntheticBase));
+		}
+		QMap<operator_type, CFF_Variant>::Iterator it;
+		for (it = dict.begin(); it != dict.end(); ++it)
+		{
+			QList<CFF_Number> arr = it.value().array;
+			switch (it.key())
+			{
+				case cff_dict_ROS:
+				case cff_dict_SyntheticBase:
+					/* already done */
+					break;
+				case cff_dict_charset:
+				case cff_dict_Encoding:
+				case cff_dict_CharStrings:
+				case cff_dict_FDArray:
+				case cff_dict_FDSelect:
+				case cff_dict_Subrs:
+					/* remember offset */
+					patchAddresses[it.key()] = result.length();
+					/* write 32 bit offset */
+					result.append((char) cff_dict_Card32);
+					result.append(encodeBE(4, arr[0].toCardinal()));
+					break;
+				case cff_dict_Private:
+					/* remember offset */
+					patchAddresses[it.key()] = result.length();
+					/* write 32 bit length */
+					result.append((char) cff_dict_Card32);
+					result.append(encodeBE(4, arr[0].toCardinal()));
+					/* write 32 bit offset */
+					result.append((char) cff_dict_Card32);
+					result.append(encodeBE(4, arr[1].toCardinal()));
+					break;
+				case cff_dict_version:
+				case cff_dict_Notice:
+				case cff_dict_Copyright:
+				case cff_dict_FullName:
+				case cff_dict_FamilyName:
+				case cff_dict_Weight:
+				case cff_dict_PostScript:
+				case cff_dict_BaseFontName:
+				case cff_dict_FontName:
+				{
+					/* write SID */
+					sid_type sid = arr[0].toCardinal();
+					sid = createSid(oldStrings[sid]);
+					qDebug() << "writeDict SID" << arr[0].toCardinal() << "-->" << sid;
+					writeCard(result, sid);
+				}
+					break;
+				default:
+					/* write numbers */
+					for (int i = 0; i < arr.length(); ++i)
+					{
+						if (arr[i].type == cff_varnt_Real)
+							writeReal(result, arr[i]);
+						else
+							writeCard(result, arr[i].toCardinal());
+					}
+					break;
+			}
+			// write operator
+			if (it.key() >= 0x0c00)
+			{
+				result.append(encodeBE(2, it.key()));
+			}
+			else
+			{
+				result.append((char) it.key());
+			}
+		}
+		return result;
+	}
+	
+	
+	void CFF::patch(QHash<operator_type, uint> patchPositions,
+	                uint patchOffset,
+	                operator_type op,
+	                uint offset,
+	                uint length)
+	{
+		if (patchPositions.contains(op))
+		{
+			uint pos = patchOffset + patchPositions[op];
+			uchar c;
+			switch (op)
+			{
+				case cff_dict_charset:
+				case cff_dict_Encoding:
+				case cff_dict_CharStrings:
+				case cff_dict_Subrs:
+				case cff_dict_FDArray:
+				case cff_dict_FDSelect:
+					assert (bytes[pos] == (char) cff_dict_Card32);
+					++pos;
+					bytes.replace(pos, 4, encodeBE(4, offset));
+					qDebug() << "patch" << cff_operator(op) << "offset @" << pos << offset;
+					break;
+				case cff_dict_Private:
+					c = bytes[pos];
+					if (c == cff_dict_Card16)
+					{
+						if (length > 0)
+						{
+							bytes.replace(pos+1, 2, encodeBE(2, length));
+							qDebug() << "patch priv short length @" << (pos+1) << length;
+						}
+						pos += 3;
+					}
+					else if (c == cff_dict_Card32)
+					{
+						if (length > 0)
+						{
+							bytes.replace(pos+1, 4, encodeBE(4, length));
+							qDebug() << "patch priv length @" << (pos+1) << length;
+						}
+						pos += 5;
+					}
+					else if (c >= cff_dict_minOperand && c <= cff_dict_maxSmallCard)
+					{
+						pos += 1;
+					}
+					else if (c >= cff_dict_minPosCard && c <= cff_dict_maxNegCard)
+					{
+						pos += 2;
+					}
+					else
+					{
+						/* error */
+					}
+					assert (bytes[pos] == (char) cff_dict_Card32);
+					++pos;
+					bytes.replace(pos, 4, encodeBE(4, offset));
+					qDebug() << "patch priv offset @" << pos << offset;
+					break;
+				default:
+					/* error */
+					break;
+			}
+		}
+	}
+	
+	
+	QByteArray CFF::makeIndex(QList<QByteArray> data) const
+	{
+		QByteArray result;
+		uint size = 0;
+		for (int i = 0; i < data.length(); ++i)
+		{
+			size += data[i].size();
+		}
+		int offSize = requiredOffsetSize(size);
+		result.append(encodeBE(2, data.length())); // count
+		if (data.length() == 0)
+			return result;
+		
+		result.append(encodeBE(1, offSize));	   // offSize
+		uint offset = 1;
+		result.append(encodeBE(offSize, offset));  // offset 1
+		for (int i=0; i < data.length(); ++i)
+		{
+			offset += data[i].length();
+			result.append(encodeBE(offSize, offset));
+		}
+		for (int i=0; i < data.length(); ++i)
+		{
+			result.append(data[i]);
+		}
+		return result;
+	}
 
-    
-    CFF::CFF() : bytes(), offsetSize(4)
-    {
-        for (int i = 0; i <= sid_last_std; ++i)
-        {
-            strings.append(stdStrings[i]);
-            sids[stdStrings[i]] = i;
-        }
-    }
-    
-    
-    CFF::CFF(const QByteArray& cff) : bytes(cff)
-    {
-        // read header
-        offsetSize = cff[cff_offSize];
-        uint pos = cff[cff_hdrSize];
-        qDebug() << "cff header" << offsetSize << "starts" << pos;
-        // read names
-        names = readIndex(pos);
-        // read top dicts
-        QList<QByteArray> topDicts = readIndex(pos);
-        for (int i = 0; i < names.length(); ++i)
-        {
-            QByteArray fontName = names[i];
-            qDebug() << i << fontName;
-            if (fontName.length() > 0 && fontName[0] != char(0))
-            {
-                fontTopDicts[fontName] = getDict(topDicts[i]);
-                uint privLength = fontTopDicts[fontName][18].array[0].toCardinal();
-                uint privOffset = fontTopDicts[fontName][18].array[1].toCardinal();
-                getDict(readSegment(privOffset, privLength));
-            }
-        }
-        // read strings
-        for (int i = 0; i <= sid_last_std; ++i)
-        {
-            strings.append(stdStrings[i]);
-        }
-        strings.append(readIndex(pos));
-        for (int i = 0; i < strings.length(); ++i)
-        {
-//            if ( i > sid_last_std)
-//                qDebug() << i << strings[i];
-            sids[strings[i]] = i;
-        }
-        // read global subroutines
-        globalSubr = readIndex(pos);
-    }
-    
-    
-    QByteArray CFF::readSegment(uint pos, uint size) const
-    {
-        return QByteArray::fromRawData(bytes.data() + pos, size);
-    }
-    
-    
-    uint CFF::readCard(uint pos) const
-    {
-        return static_cast<uchar>(bytes[pos]) << 8 | static_cast<uchar>(bytes[pos+1]);
-    }
-    
-    
-    
-    QMap<operator_type,CFF_Variant> CFF::getDict(const QByteArray& dict) const
-    {
-        QMap<uint,CFF_Variant> result;
-        QList<CFF_Number> stack;
-        
-        uint pos = 0;
-        while (pos < dict.length())
-        {
-            CFF_Number num = parseDictElement(dict, pos);
-            if (num.type == cff_varnt_Operator)
-            {
-                if (stack.length() == 1)
-                {
-                    result[num.card] = CFF_Variant(stack[0]);
-                }
-                else if (stack.length() > 0)
-                {
-                    result[num.card] = CFF_Variant(stack);
-                }
-                else
-                {
-                    /* error */
-                }
-                stack = QList<CFF_Number>();
-            }
-            else
-            {
-                stack.append(num);
-            }
-        }
-        if (stack.length() > 0)
-        {
-            /* error */
-        }
-        // TODO: adapt variant type according to operator
-        return result;
-    }
-    
-    
-    CFF_Number CFF::parseDictElement(const QByteArray& dict, uint& pos) const
-    {
-        uint code = dict[pos];
-        switch (code)
-        {
-            case cff_dict_TwoBytes:
-                code = (code << 8) | dict[++pos];
-                break;
-            case cff_dict_Card16:
-            case cff_dict_Card32:
-                return parseCard(dict, pos);
-            case cff_dict_Real:
-                return parseReal(dict, pos);
+	
+	QByteArray CFF::makeCharset(QList<sid_type> sids) const
+	{
+		QByteArray result;
+		// we won't bother with ranges for now
+		result.append('\0'); // format 0
+		for (int i = 1; i < sids.length(); ++i)
+		{
+			result.append(encodeBE(2, sids[i]));
+		}
+		return result;
+	}
+	
+	
+	QByteArray CFF::makeEncoding(QList<uint> encoding) const
+	{
+		QByteArray result;
+#ifdef UNTESTET_CFF_MAKEENCODING
+		QMap<uint, uchar> codes;
+		QMap<uchar, uint> supplements;
+		uint maxGid = 0;
+		for (uchar c = 0; c < encoding.length(); ++c)
+		{
+			uint gid = encoding[c];
+			if (gid > maxGid && gid < 256)
+				maxGid = gid;
+			
+			if (gid != 0)
+			{
+				if (gid >= 256 || codes.contains(gid))
+					supplements[c] = gid;
+				else
+					codes[gid] = c;
+			}
+		}
+		result.append('\0');
+		result.append((uchar) (maxGid+1));
+		for (uint gid = 0; gid <= maxGid; ++gid);
+		{
+			if (codes.contains(gid))
+				result.append(codes[gid]);
+			else
+				result.append('\0'); // this is probably not correct
+		}
+		QMap<uchar, uint>::Iterator it;
+		result.append(supplements.count());
+		for (it = supplements.begin(); it != supplements.end(); ++it)
+		{
+			result.append(it.key());
+			result.append(encodeBE(2, it.value()));
+		}
+#else
+		result.append((char) 0x80);			   // format 0 with supplements
+		result.append((char) 0);				  // no encoded glyphs except supplements
+		result.append((char) encoding.length());  // all supplements
+		for (int c = 0; c < encoding.length(); ++c)
+		{
+			result.append((uchar)c);
+			result.append(encodeBE(2, encoding[c]));
+		}
+#endif
+		return result;
+	}
+	
+	
+	CFF CFF::extractSubset(uint faceIndex,
+	                       QList<uint> cids) const
+	{
+		uint pos;
+		
+		// get top dict
+		QByteArray fontName = names[faceIndex];
+		QMap<operator_type, CFF_Variant> topDict = fontTopDicts[fontName];
+		
+		// get charstrings
+		QList<QByteArray> charStrings;
+		pos = topDict[cff_dict_CharStrings].array[0].toCardinal();
+		charStrings = readIndex(pos);
+		
+		// get encoding (optional, maybe predefined 0-1)
+		QList<uint> encoding;
+		if (topDict.contains(cff_dict_Encoding))
+		{
+			uint offset = topDict[cff_dict_Encoding].array[0].toCardinal();
+			if (offset > 1)
+			{
+				pos = offset;
+				encoding = readEncoding(pos);
+//				encodingBytes = readSegment(offset, pos-offset);
+			}
+			else
+				encoding.append(offset);
+		}
+		
+		// get charmap (optional, maybe predefined 0-2)
+		QList<sid_type> charset;
+		if (topDict.contains(cff_dict_charset))
+		{
+			uint offset = topDict[cff_dict_charset].array[0].toCardinal();
+			if (offset > 2)
+			{
+				pos = offset;
+				charset = readCharset(charStrings.count(), pos);
+//				charsetBytes = readSegment(offset, pos-offset);
+			}
+			else
+				charset.append(offset);
+		}
+		
+		// get private dict
+		QList<CFF_Number> lengthOffset = topDict[cff_dict_Private].array;
+		QMap<operator_type, CFF_Variant> privateDict = getDict(readSegment(lengthOffset[1].toCardinal(), lengthOffset[0].toCardinal()));
+		
+		// get local subr (optional)
+		QList<QByteArray> localSubrs;
+		if (privateDict.contains(cff_dict_Subrs))
+		{
+			pos = lengthOffset[1].toCardinal() + privateDict[cff_dict_Subrs].array[0].toCardinal();
+			localSubrs = readIndex(pos);
+		}
+		
+		// now create new font
+		CFF result;
+		result.globalSubr = globalSubr;  // no changes
+		
+		// subset
+		if (cids.length() > 0)
+		{
+			// normalize .notdef
+			cids.removeAll(0);
+			cids.prepend(0);
+			
+			// forget encoding
+			topDict.remove(cff_dict_Encoding);
+			encoding = QList<uint>();
+		
+			// new charset
+			QList<sid_type> newCharset;
+			// new charStrings
+			QList<QByteArray> newCharStrings;
 
-            default:
-                if (code >= cff_dict_minOperand)
-                {
-                    return parseCard(dict, pos);
-                }
-                break;
-        }
-        ++pos;
-        CFF_Number num;
-        num.type = cff_varnt_Operator;
-        num.card = code;
-        qDebug() << "parsed operator" << cff_operator(code) << "(" << code << ")";
-        return num;
-    }
-    
-    
-    CFF_Number CFF::parseCard(const QByteArray& dict, uint& pos) const
-    {
-        CFF_Number result;
-        result.type = cff_varnt_Card;
-        result.exponent = 0;
-        uint start=pos;
-        uchar b0 = dict[pos++];
-        uchar b1,b2,b3,b4;
-        if (b0 == cff_dict_Card16)
-        {
-            b1 = dict[pos++];
-            b2 = dict[pos++];
-            result.card = static_cast<qint16>((b1 << 8) | b2);
-        }
-        else if (b0 == cff_dict_Card32)
-        {
-            b1 = dict[pos++];
-            b2 = dict[pos++];
-            b3 = dict[pos++];
-            b4 = dict[pos++];
-            result.card = static_cast<qint32>((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
-        }
-        else if (b0 < cff_dict_minOperand)
-        {
-            /* error */
-        }
-        else if (b0 <= cff_dict_maxSmallCard)
-        {
-            result.card = b0 + cff_dict_biasSmallCard;
-        }
-        else if (b0 <= cff_dict_maxPosCard)
-        {
-            b1 = dict[pos++];
-            result.card = (b0 - cff_dict_minPosCard) * 256 + b1 + cff_dict_biasPosCard;
-        }
-        else if (b0 <= cff_dict_maxNegCard)
-        {
-            b1 = dict[pos++];
-            result.card = (cff_dict_minNegCard - b0) * 256 - b1 + cff_dict_biasNegCard;
-        }
-        else
-        {
-            /* error */
-        }
-        qDebug() << "parsed" << QByteArray::fromRawData(dict.data()+start, pos-start).toHex() << "to card " << result.card;
-        return result;
-    }
-    
-    
-    CFF_Number CFF::parseReal(const QByteArray& dict, uint& pos) const
-    {
-        assert( dict[pos] == cff_dict_Real );
-        uint start = pos++;
+			for (int i = 0; i < cids.length(); ++i)
+			{
+				sid_type gid = cids[i];
+				sid_type sid = charset[gid];
+				if (sid < strings.length())
+				{
+					sid = result.createSid(strings[sid]);
+				}
+				newCharset.append(sid);
+				newCharStrings.append(charStrings[gid]);
+			}
+			
+			charset = newCharset;
+			charStrings = newCharStrings;
+		}
+		else if (charset.length() > 1)
+		{
+			// copy over needed strings
+			for (int i = 0; i < charset.length(); ++i)
+			{
+				sid_type cid = charset[i];
+				if (cid < strings.length())
+				{
+					cid = result.createSid(strings[cid]);
+				}
+				charset[i] = cid;
+			}
+		}
+		
+		// create new private dict
+		QHash<operator_type, uint> privatePatches;
+		QByteArray privateBytes = result.makeDict(privateDict, strings, privatePatches);
 
-        CFF_Number result;
-        result.type = cff_varnt_Real;
-        result.card = 0;
-        result.exponent = 0;
-        bool upperNibble = false;
-        bool haveSeenMinus = false;
-        bool haveSeenE = false;;
-        bool haveSeenEminus = false;
-        int decimalPointAt = -1;
-        uchar nibble, twoNibbles;
-        do
-        {
-            // get nibble
-            if (upperNibble)
-            {
-                nibble = twoNibbles & 0x0f;
-                upperNibble = false;
-            }
-            else
-            {
-                twoNibbles = dict[pos++];
-                nibble = twoNibbles >> 4;
-                upperNibble = true;
-            }
-            
-            // decode
-            switch (nibble)
-            {
-                case cff_nibble_Minus:
-                    haveSeenMinus = !haveSeenMinus;
-                    break;
-                case cff_nibble_Point:
-                    decimalPointAt = 0;
-                    break;
-                case cff_nibble_PosExp:
-                    haveSeenE = true;
-                    break;
-                case cff_nibble_NegExp:
-                    haveSeenEminus = true;
-                    break;
-                case cff_nibble_End:
-                    break;
-                default:
-                    if (nibble > cff_nibble_maxDigit)
-                    {
-                        /* error */
-                    }
-                    else if (haveSeenE || haveSeenEminus)
-                    {
-                        result.exponent *= 10;
-                        result.exponent += nibble;
-                    }
-                    else
-                    {
-                        result.card *= 10;
-                        result.card += nibble;
-                        if (decimalPointAt >= 0)
-                        {
-                            ++decimalPointAt;
-                        }
-                    }
-                    break;
-            }
-        } while (nibble != cff_nibble_End);
-            
-        // finish
-        if (haveSeenMinus)
-            result.card = -result.card;
-        if (haveSeenEminus)
-            result.exponent = -result.exponent;
-        if (decimalPointAt > 0)
-            result.exponent -= decimalPointAt;
-        qDebug() << "parsed" << QByteArray::fromRawData(dict.data()+start, pos-start).toHex() << "to real " << result.card << "E" << result.exponent;
+		
+		// write new header, name and topdict, remember offset positions for patching
+		QHash<operator_type, uint> patchPositions;
+		uint topDictOffset = result.writeTopDict(fontName, topDict, strings, patchPositions);
+		
+		// write strings
+		// makeDict() needs to be called before this in order to create SIDs for used strings
+		result.writeSegment(makeIndex(result.strings.mid(sid_last_std + 1)));
+		
+		// write global subr (required but maybe empty)
+		result.writeSegment(makeIndex(globalSubr));
 
-        return result;
-    }
-    
-    
-    QList<QByteArray> CFF::readIndex(uint& pos) const
-    {
-        qDebug() << "read INDEX @" << pos;
-        QList<QByteArray> result;
-        uint N = readCard(pos);
-        pos += 2;
-        uint offSize = bytes[pos++];
-        uint dataStart = pos + offSize * (N+1) - 1;
-        qDebug() << "size" << N << "offsetsize" << offSize << "dataStart" << dataStart;
-        uint start = 0;
-        uint end;
-        for (int c = 0; c < offSize; ++c)
-        {
-            start = start << 8 | (uchar) bytes[pos++];
-        }
-        start += dataStart;
-        for (int i = 0; i < N; ++i)
-        {
-            end = 0;
-            for (int c = 0; c < offSize; ++c)
-            {
-                end = end << 8 | (uchar) bytes[pos++];
-            }
-            end += dataStart;
-            result.append(readSegment(start, end-start));
-            start = end;
-        }
-        pos = end;
-        qDebug() << "INDEX ends @" << end;
-        return result;
-    }
-    
-    
-    QList<uint> CFF::readEncoding(uint& pos) const
-    {
-        QList<uint> result;
-        for(int i = 0; i < 256; ++i)
-            result.append(0);
-        
-        uchar format = bytes[pos++];
-        uchar N = bytes[pos++];
-        int gid;
-        uchar code;
-        switch (format)
-        {
-            case 0x0:
-            case 0x80:
-                for (gid = 1; gid <= N; ++gid)
-                {
-                    code = bytes[pos++];
-                    if (result[code] == 0)
-                    {
-                        result[code] = gid;
-                    }
-                }
-                break;
-            case 0x1:
-            case 0x81:
-                gid = 1;
-                for (int r = 0; r < N; ++r)
-                {
-                    uchar first = bytes[pos++];
-                    uchar nLeft = bytes[pos++];
-                    for (code = first; code <= first + nLeft; ++code)
-                    {
-                        if (result[code] == 0)
-                        {
-                            result[code] = gid;
-                        }
-                        ++gid;
-                    }
-                }
-                break;
-        }
-        if (format >= 0x80)
-        {
-            uchar nSupplements = bytes[pos++];
-            for (int i = 0; i < nSupplements; ++i)
-            {
-                code = bytes[pos++];
-                gid = readCard(pos);
-                pos += 2;
-                result[code] = gid;
-            }
-        }
-        return result;
-    }
-    
-    
-    QList<sid_type> CFF::readCharset(uint nGlyphs, uint& pos) const
-    {
-        QList<sid_type> result;
-        result.append(0); // sid for .notdef
-        
-        uchar format = bytes[pos++];
-        
-        sid_type first;
-        uchar nLeft1;
-        uint nLeft2;
-        
-        switch (format)
-        {
-            case 0:
-                for (int gid = 1; gid < nGlyphs; ++gid)
-                {
-                    result.append(readCard(pos));
-                    pos += 2;
-                }
-                break;
-            case 1:
-                while (result.length() < nGlyphs)
-                {
-                    first = readCard(pos);
-                    pos += 2;
-                    nLeft1 = bytes[pos++];
-                    for (sid_type sid = first; sid <= first + nLeft1; ++sid)
-                    {
-                        result.append(sid);
-                    }
-                }
-                break;
-            case 2:
-                while (result.length() < nGlyphs)
-                {
-                    first = readCard(pos);
-                    pos += 2;
-                    nLeft2 = readCard(pos);
-                    pos += 2;
-                    for (sid_type sid = first; sid <= first + nLeft2; ++sid)
-                    {
-                        result.append(sid);
-                    }
-                }
-                break;
-        }
-        return result;
-    }
-    
-    
-    QByteArray CFF::dump(const CFF_Variant& var) const
-    {
-        QByteArray result;
-        switch(var.type)
-        {
-            case cff_varnt_Error:
-                result += "ERROR";
-                break;
-            case cff_varnt_Card:
-            case cff_varnt_Bool:
-            case cff_varnt_SID:
-                result += QByteArray::number(var.array[0].toCardinal());
-                break;
-            case cff_varnt_Real:
-                result += QByteArray::number(var.array[0].toDouble());
-                break;
-            case cff_varnt_Operator:
-                result += string(var.array[0].toCardinal());
-                result += " (";
-                result += QByteArray::number(var.array[0].toCardinal());
-                result +=")";
-                break;
-            case cff_varnt_Delta:
-                result += "Delta";
-                /* fall thru */
-            case cff_varnt_Array:
-                result += "[";
-                for (int i = 0; i < var.array.length(); ++i)
-                {
-                    result += QByteArray::number(var.array[i].toDouble());
-                    result += ", ";
-                }
-                result.chop(2);
-                result += "]";
-                break;
-        }
-        return result;
-    }
-    
-    
-    void CFF::dump()
-    {
-        qDebug() << "CFF" << fontTopDicts.count() << "fonts, size =" << bytes.size() << "offset size=" << offsetSize;
-        QMap<QByteArray,QMap<operator_type,CFF_Variant> >::Iterator it;
-        for (it = fontTopDicts.begin(); it != fontTopDicts.end(); ++it)
-        {
-            qDebug() << "Font" << it.key() << ":";
-            QMap<operator_type, CFF_Variant>::Iterator it2;
-            for (it2= it.value().begin(); it2 != it.value().end(); ++it2)
-            {
-                qDebug() << "\t" << cff_operator(it2.key()) << "=" << dump(it2.value());
-            }
-        }
-    }
-    
-    
-    static QByteArray num(uint n)
-    {
-        return QByteArray::number(n);
-    }
-    
-    
-    static void write(QDataStream& out, const QByteArray& data)
-    {
-        out.writeRawData(data.data(), data.length());
-    }
-    
-    static void dumpData(const QList<QByteArray>& index, QDataStream& out, const QByteArray& indent)
-    {
-        for (int i = 0; i < index.length(); ++i)
-        {
-            write(out, indent);
-            write(out, "<data idx='");
-            write(out, num(i));
-            write(out, "' length='");
-            write(out, num(index[i].length()));
-            write(out, "' >");
-            write(out, index[i].toHex());
-            write(out, "</data>\n");
-        }
-    }
+		// write encoding
+		uint encodingOffset = encoding.size() > 1? result.writeSegment(makeEncoding(encoding)) : encoding.size() == 1? encoding[0] : 0;
+		
+		// write charset
+		uint charsetOffset = charset.size() > 1? result.writeSegment(makeCharset(charset)) : charset.size() == 1? charset[0] : 0;
+		
+		// write charstrings
+		uint charStringsOffset = result.writeSegment(makeIndex(charStrings));
+		
+		// write private dict
+		uint privateOffset = result.writeSegment(privateBytes);
+		
+		// write local subr
+		if (localSubrs.size() > 0)
+		{
+			uint localSubrOffset = result.writeSegment(makeIndex(localSubrs));
 
-    static void dumpStrings(const QList<QByteArray>& index, QDataStream& out, const QByteArray& indent)
-    {
-        for (int i = 0; i < index.length(); ++i)
-        {
-            write(out, indent);
-            write(out, "<string idx='");
-            write(out, num(i));
-            write(out, "' length='");
-            write(out, num(index[i].length()));
-            write(out, "' >");
-            write(out, index[i]);
-            write(out, "</string>\n");
-        }
-    }
-
-    static void dumpDict(const CFF& cff, const QMap<operator_type,CFF_Variant>& dict, QDataStream& out, const QByteArray& indent)
-    {
-        QMap<operator_type,CFF_Variant>::ConstIterator it;
-        for (it = dict.cbegin(); it != dict.cend(); ++it)
-        {
-            write(out, indent);
-            write(out, "<keyvalue key='");
-            write(out, cff_operator(it.key()));
-            write(out, "' value='");
-            write(out, cff.dump(it.value()));
-            write(out, "' />\n");
-        }
-    }
-    
-    void CFF::dump(QDataStream& out) const
-    {
-        write(out, "<CFF version='1.0' offsetSize='" + num(offsetSize) + "' >\n");
-        for (int f = 0; f < names.length(); ++f)
-        {
-            QByteArray font = names[f];
-            QMap<operator_type, CFF_Variant> topDict = fontTopDicts[font];
-            write(out, "  <Font name='" + font + "' >\n");
-            write(out, "    <TopDict>");
-            dumpDict(*this, topDict, out, "      ");
-            write(out, "    </TopDict>\n");
-            uint pos;
-            if (topDict.contains(cff_dict_Encoding))
-            {
-                uint encOffset = topDict[cff_dict_Encoding].array[0].toCardinal();
-                if (encOffset > 4)
-                {
-                    write(out, "    <Encoding>\n    ");
-                    pos = encOffset;
-                    QList<uint> enc = readEncoding(pos);
-                    write(out, readSegment(encOffset, pos-encOffset).toHex());
-                    write(out, "\n    </Encoding>\n");
-                }
-                else
-                    write(out, "    <Encoding predefined='" + num(encOffset) + "' />\n");
-            }
-            pos = topDict[cff_dict_CharStrings].array[0].toCardinal();
-            QList<QByteArray> charStrings = readIndex(pos);
-            uint nglyphs = charStrings.length();
-            if (topDict.contains(cff_dict_charset))
-            {
-                uint charsetOffset = topDict[cff_dict_charset].array[0].toCardinal();
-                if (charsetOffset > 4)
-                {
-                    pos = charsetOffset;
-                    QList<sid_type> charset = readCharset(nglyphs, pos);
-                    write(out, "    <charset>\n");
-                    for (int i=0; i < charset.length(); ++i)
-                    {
-                        write(out, "      <char gid='" + num(i) + "' sid='" + num(charset[i]) + "' >");
-                        write(out, string(charset[i]) + "</char>\n");
-                    }
-                    write(out, "    </charset>\n");
-                }
-            }
-            write(out, "    <CharStrings>\n");
-            dumpData(charStrings, out, "      ");
-            write(out, "    </CharStrings>\n");
-            uint privateLength = topDict[cff_dict_Private].array[0].toCardinal();
-            uint privateOffset = topDict[cff_dict_Private].array[1].toCardinal();
-            write(out, "    <PrivateDict offset='" + num(privateOffset) + "' length='" + num(privateLength) + ">\n");
-            QMap<operator_type,CFF_Variant> privateDict = getDict(readSegment(privateOffset, privateLength));
-            dumpDict(*this, privateDict, out, "      ");
-            write(out, "    </PrivateDict>\n");
-            if (privateDict.contains(cff_dict_Subrs))
-            {
-                uint subrsOffset = privateDict[cff_dict_Subrs].array[0].toCardinal();
-                pos = privateOffset + subrsOffset;
-                QList<QByteArray> localSubrs = readIndex(pos);
-                write(out, "    <LocalSubrs offset='" + num(subrsOffset) + "' length='" + num(pos-subrsOffset) + "' >\n");
-                dumpData(localSubrs, out, "      ");
-                write(out, "    </LocalSubrs>\n");
-            }
-            write(out, "  </Font>\n");
-        }
-        write(out, "  <Strings>\n");
-        dumpStrings(strings, out, "    ");
-        write(out, "  </Strings>\n");
-        write(out, "  <GlobalSubrs>\n");
-        dumpData(globalSubr, out, "    ");
-        write(out, "  </GlobalSubrs>\n");
-        write(out, "</CFF>\n");
-    }
-    
-    /// encodes 'value' as exactly 'nBytes' bytes in Big Endian
-    static QByteArray encodeBE(int nbytes, uint value)
-    {
-        QByteArray result;
-        while (nbytes-- > 0)
-        {
-            result.prepend(static_cast<uchar>(value & 0xFF));
-            value >>= 8;
-        }
-        return result;
-    }
-    
-    
-    /// calculates the required offset size to represent 'dataLength'
-    static int requiredOffsetSize(int dataLength)
-    {
-        if (dataLength < 255)
-            return 1;
-        else if (dataLength < 65535)
-            return 2;
-        else if (dataLength < 0xFFFFFF)
-            return 3;
-        else
-            return 4;
-    }
-    
-    
-    static void writeCard(QByteArray& bytes, int val)
-    {
-        int biasedVal = val - cff_dict_biasSmallCard;
-        if (biasedVal >= cff_dict_minOperand && biasedVal <= cff_dict_maxSmallCard)
-        {
-            bytes.append((char) biasedVal);
-            return;
-        }
-        if (val > 0)
-        {
-            biasedVal = val - cff_dict_biasPosCard;
-            if (biasedVal >= 0 &&  biasedVal <= 1023)
-            {
-                biasedVal += (cff_dict_minPosCard << 8);
-                bytes.append(encodeBE(2, biasedVal));
-                qDebug() << "writeCard" << val << "as" << encodeBE(2, biasedVal).toHex();
-                return;
-            };
-        }
-        else
-        {
-            biasedVal = -val + cff_dict_biasNegCard;
-            if (biasedVal >= 0 &&  biasedVal <= 1023)
-            {
-                biasedVal += (cff_dict_minNegCard << 8);
-                bytes.append(encodeBE(2, biasedVal));
-                qDebug() << "writeCard" << val << "as" << encodeBE(2, biasedVal).toHex();
-                return;
-            };
-        }
-        if (val >= -32768 && val <= 32767)
-        {
-            bytes.append((char) cff_dict_Card16);
-            bytes.append(encodeBE(2, val));
-        }
-        else
-        {
-            bytes.append((char) cff_dict_Card32);
-            bytes.append(encodeBE(4, val));
-        }
-    }
-    
-    
-    /// creates one byte per digit (not ASCII!)
-    static QByteArray bsdNibbles(long long val)
-    {
-        QByteArray result;
-        if (val < 0)
-            val = -val;
-        
-        do {
-            result.prepend((char) (val % 10));
-            val /= 10;
-        }
-        while (val != 0);
-        
-        return result;
-    }
-    
-    
-    static void writeReal(QByteArray& bytes, CFF_Number num)
-    {
-        QByteArray bsd;
-        if (num.card < 0)
-        {
-            bsd.append((char) cff_nibble_Minus);
-            bsd.append(bsdNibbles(-num.card));
-        }
-        else
-        {
-            bsd.append(bsdNibbles(num.card));
-        }
-        if (num.exponent < 0)
-        {
-            bsd.append((char) cff_nibble_NegExp);
-            bsd.append(bsdNibbles(-num.exponent));
-        }
-        else if (num.exponent > 0)
-        {
-            bsd.append((char) cff_nibble_PosExp);
-            bsd.append(bsdNibbles(num.exponent));
-        }
-        bsd.append((char) cff_nibble_End);
-        if (bsd.length() % 2 == 1)
-            bsd.append((char) cff_nibble_End);
-        
-        uint start = bytes.length();
-        bytes.append((char) cff_dict_Real);
-        for (int i= 0; i < bsd.length(); i += 2)
-        {
-            bytes.append((char) ((bsd[i] << 4) | bsd[i+1]));
-        }
-        qDebug() << "writeReal" << num.card << "E" << num.exponent << "as" << bytes.mid(start).toHex();
-    }
-    
-    
-    uint CFF::writeSegment(const QByteArray& data)
-    {
-        uint result = bytes.length();
-        bytes.append(data);
-        return result;
-    }
-    
-    
-    sid_type CFF::createSid(const QByteArray& str)
-    {
-        sid_type result;
-        if (!sids.contains(str))
-        {
-            result = strings.length();
-            strings.append(str);
-            sids[str] = result;
-            qDebug() << "new SID" << result << "for" << str;
-        }
-        else
-        {
-            result = sids[str];
-        }
-        return result;
-    }
-    
-    
-    uint CFF::writeTopDict(QByteArray name,
-                           QMap<operator_type, CFF_Variant> dict,
-                           QList<QByteArray> oldStrings,
-                           QHash<operator_type, uint>& patchAddresses)
-    {
-        offsetSize = 4;
-        names.append(name);
-        fontTopDicts[name] = dict;
-        bytes.append((char) 1);
-        bytes.append((char) 0);                     // format 1.0
-        bytes.append((char) 4);                     // header length 4
-        bytes.append((char) 4);                     // offsetSize 4
-        
-        // write Name index
-        bytes.append(encodeBE(2,1));                  // count
-        assert (name.length() < 255);
-        bytes.append(encodeBE(1, 1));                 // offSize
-        bytes.append(encodeBE(1, 1));                 // offset 1
-        bytes.append(encodeBE(1, 1 + name.length())); // offset 2
-        bytes.append(name);
-        
-        
-        // write TopDict index
-        QByteArray topDict = makeDict(dict, oldStrings, patchAddresses);
-        int offSize = requiredOffsetSize(topDict.length());
-        bytes.append(encodeBE(2, 1));                          // count
-        bytes.append(encodeBE(1, offSize));                    // offSize
-        bytes.append(encodeBE(offSize, 1));                    // offset 1
-        bytes.append(encodeBE(offSize, 1 + topDict.length())); // offset 2
-        uint start = bytes.size();
-        bytes.append(topDict);
-        return start;
-    }
-    
-    
-    QByteArray CFF::makeDict(QMap<operator_type, CFF_Variant> dict,
-                             QList<QByteArray> oldStrings,
-                             QHash<operator_type, uint>& patchAddresses)
-    {
-        QByteArray result;
-        if (dict.contains(cff_dict_ROS))
-        {
-            // pull to front
-            QList<CFF_Number> ros = dict[cff_dict_ROS].array;
-            sid_type sid = ros[0].toCardinal();
-            sid = createSid(oldStrings[sid]);
-            writeCard(result, sid);
-            sid = ros[1].toCardinal();
-            sid = createSid(oldStrings[sid]);
-            writeCard(result, sid);
-            writeCard(result, ros[2].toCardinal());
-            result.append(encodeBE(2, cff_dict_ROS));
-
-        }
-        if (dict.contains(cff_dict_SyntheticBase))
-        {
-            // pull to front
-            writeCard(result, dict[cff_dict_ROS].array[0].toCardinal());
-            result.append(encodeBE(2, cff_dict_SyntheticBase));
-        }
-        QMap<operator_type, CFF_Variant>::Iterator it;
-        for (it = dict.begin(); it != dict.end(); ++it)
-        {
-            QList<CFF_Number> arr = it.value().array;
-            switch (it.key())
-            {
-                case cff_dict_ROS:
-                case cff_dict_SyntheticBase:
-                    /* already done */
-                    break;
-                case cff_dict_charset:
-                case cff_dict_Encoding:
-                case cff_dict_CharStrings:
-                case cff_dict_FDArray:
-                case cff_dict_FDSelect:
-                case cff_dict_Subrs:
-                    /* remember offset */
-                    patchAddresses[it.key()] = result.length();
-                    /* write 32 bit offset */
-                    result.append((char) cff_dict_Card32);
-                    result.append(encodeBE(4, arr[0].toCardinal()));
-                    break;
-                case cff_dict_Private:
-                    /* remember offset */
-                    patchAddresses[it.key()] = result.length();
-                    /* write 32 bit length */
-                    result.append((char) cff_dict_Card32);
-                    result.append(encodeBE(4, arr[0].toCardinal()));
-                    /* write 32 bit offset */
-                    result.append((char) cff_dict_Card32);
-                    result.append(encodeBE(4, arr[1].toCardinal()));
-                    break;
-                case cff_dict_version:
-                case cff_dict_Notice:
-                case cff_dict_Copyright:
-                case cff_dict_FullName:
-                case cff_dict_FamilyName:
-                case cff_dict_Weight:
-                case cff_dict_PostScript:
-                case cff_dict_BaseFontName:
-                case cff_dict_FontName:
-                {
-                    /* write SID */
-                    sid_type sid = arr[0].toCardinal();
-                    sid = createSid(oldStrings[sid]);
-                    qDebug() << "writeDict SID" << arr[0].toCardinal() << "-->" << sid;
-                    writeCard(result, sid);
-                }
-                    break;
-                default:
-                    /* write numbers */
-                    for (int i = 0; i < arr.length(); ++i)
-                    {
-                        if (arr[i].type == cff_varnt_Real)
-                            writeReal(result, arr[i]);
-                        else
-                            writeCard(result, arr[i].toCardinal());
-                    }
-                    break;
-            }
-            // write operator
-            if (it.key() >= 0x0c00)
-            {
-                result.append(encodeBE(2, it.key()));
-            }
-            else
-            {
-                result.append((char) it.key());
-            }
-        }
-        return result;
-    }
-    
-    
-    void CFF::patch(QHash<operator_type, uint> patchPositions,
-                    uint patchOffset,
-                    operator_type op,
-                    uint offset,
-                    uint length)
-    {
-        if (patchPositions.contains(op))
-        {
-            uint pos = patchOffset + patchPositions[op];
-            uchar c;
-            switch (op)
-            {
-                case cff_dict_charset:
-                case cff_dict_Encoding:
-                case cff_dict_CharStrings:
-                case cff_dict_Subrs:
-                case cff_dict_FDArray:
-                case cff_dict_FDSelect:
-                    assert (bytes[pos] == (char) cff_dict_Card32);
-                    ++pos;
-                    bytes.replace(pos, 4, encodeBE(4, offset));
-                    qDebug() << "patch" << cff_operator(op) << "offset @" << pos << offset;
-                    break;
-                case cff_dict_Private:
-                    c = bytes[pos];
-                    if (c == cff_dict_Card16)
-                    {
-                        if (length > 0)
-                        {
-                            bytes.replace(pos+1, 2, encodeBE(2, length));
-                            qDebug() << "patch priv short length @" << (pos+1) << length;
-                        }
-                        pos += 3;
-                    }
-                    else if (c == cff_dict_Card32)
-                    {
-                        if (length > 0)
-                        {
-                            bytes.replace(pos+1, 4, encodeBE(4, length));
-                            qDebug() << "patch priv length @" << (pos+1) << length;
-                        }
-                        pos += 5;
-                    }
-                    else if (c >= cff_dict_minOperand && c <= cff_dict_maxSmallCard)
-                    {
-                        pos += 1;
-                    }
-                    else if (c >= cff_dict_minPosCard && c <= cff_dict_maxNegCard)
-                    {
-                        pos += 2;
-                    }
-                    else
-                    {
-                        /* error */
-                    }
-                    assert (bytes[pos] == (char) cff_dict_Card32);
-                    ++pos;
-                    bytes.replace(pos, 4, encodeBE(4, offset));
-                    qDebug() << "patch priv offset @" << pos << offset;
-                    break;
-                default:
-                    /* error */
-                    break;
-            }
-        }
-    }
-    
-    
-    QByteArray CFF::makeIndex(QList<QByteArray> data) const
-    {
-        QByteArray result;
-        uint size = 0;
-        for (int i = 0; i < data.length(); ++i)
-        {
-            size += data[i].size();
-        }
-        int offSize = requiredOffsetSize(size);
-        result.append(encodeBE(2, data.length())); // count
-        if (data.length() == 0)
-            return result;
-        
-        result.append(encodeBE(1, offSize));       // offSize
-        uint offset = 1;
-        result.append(encodeBE(offSize, offset));  // offset 1
-        for (int i=0; i < data.length(); ++i)
-        {
-            offset += data[i].length();
-            result.append(encodeBE(offSize, offset));
-        }
-        for (int i=0; i < data.length(); ++i)
-        {
-            result.append(data[i]);
-        }
-        return result;
-    }
-
-    
-    QByteArray CFF::makeCharset(QList<sid_type> sids) const
-    {
-        QByteArray result;
-        // we won't bother with ranges for now
-        result.append('\0'); // format 0
-        for (int i = 1; i < sids.length(); ++i)
-        {
-            result.append(encodeBE(2, sids[i]));
-        }
-        return result;
-    }
-    
-    
-    QByteArray CFF::makeEncoding(QList<uint> encoding) const
-    {
-        QByteArray result;
-#ifdef UNTESTET_CFF_MAKEENCODING
-        QMap<uint, uchar> codes;
-        QMap<uchar, uint> supplements;
-        uint maxGid = 0;
-        for (uchar c = 0; c < encoding.length(); ++c)
-        {
-            uint gid = encoding[c];
-            if (gid > maxGid && gid < 256)
-                maxGid = gid;
-            
-            if (gid != 0)
-            {
-                if (gid >= 256 || codes.contains(gid))
-                    supplements[c] = gid;
-                else
-                    codes[gid] = c;
-            }
-        }
-        result.append('\0');
-        result.append((uchar) (maxGid+1));
-        for (uint gid = 0; gid <= maxGid; ++gid);
-        {
-            if (codes.contains(gid))
-                result.append(codes[gid]);
-            else
-                result.append('\0'); // this is probably not correct
-        }
-        QMap<uchar, uint>::Iterator it;
-        result.append(supplements.count());
-        for (it = supplements.begin(); it != supplements.end(); ++it)
-        {
-            result.append(it.key());
-            result.append(encodeBE(2, it.value()));
-        }
-#else
-        result.append((char) 0x80);               // format 0 with supplements
-        result.append((char) 0);                  // no encoded glyphs except supplements
-        result.append((char) encoding.length());  // all supplements
-        for (uint c = 0; c < encoding.length(); ++c)
-        {
-            result.append((uchar)c);
-            result.append(encodeBE(2, encoding[c]));
-        }
-#endif
-        return result;
-    }
-    
-    
-    CFF CFF::extractSubset(uint faceIndex,
-                           QList<uint> cids) const
-    {
-        uint pos;
-        
-        // get top dict
-        QByteArray fontName = names[faceIndex];
-        QMap<operator_type, CFF_Variant> topDict = fontTopDicts[fontName];
-        
-        // get charstrings
-        QList<QByteArray> charStrings;
-        pos = topDict[cff_dict_CharStrings].array[0].toCardinal();
-        charStrings = readIndex(pos);
-        
-        // get encoding (optional, maybe predefined 0-1)
-        QList<uint> encoding;
-        if (topDict.contains(cff_dict_Encoding))
-        {
-            uint offset = topDict[cff_dict_Encoding].array[0].toCardinal();
-            if (offset > 1)
-            {
-                pos = offset;
-                encoding = readEncoding(pos);
-//                encodingBytes = readSegment(offset, pos-offset);
-            }
-            else
-                encoding.append(offset);
-        }
-        
-        // get charmap (optional, maybe predefined 0-2)
-        QList<sid_type> charset;
-        if (topDict.contains(cff_dict_charset))
-        {
-            uint offset = topDict[cff_dict_charset].array[0].toCardinal();
-            if (offset > 2)
-            {
-                pos = offset;
-                charset = readCharset(charStrings.count(), pos);
-//                charsetBytes = readSegment(offset, pos-offset);
-            }
-            else
-                charset.append(offset);
-        }
-        
-        // get private dict
-        QList<CFF_Number> lengthOffset = topDict[cff_dict_Private].array;
-        QMap<operator_type, CFF_Variant> privateDict = getDict(readSegment(lengthOffset[1].toCardinal(), lengthOffset[0].toCardinal()));
-        
-        // get local subr (optional)
-        QList<QByteArray> localSubrs;
-        if (privateDict.contains(cff_dict_Subrs))
-        {
-            pos = lengthOffset[1].toCardinal() + privateDict[cff_dict_Subrs].array[0].toCardinal();
-            localSubrs = readIndex(pos);
-        }
-        
-        // now create new font
-        CFF result;
-        result.globalSubr = globalSubr;  // no changes
-        
-        // subset
-        if (cids.length() > 0)
-        {
-            // normalize .notdef
-            cids.removeAll(0);
-            cids.prepend(0);
-            
-            // forget encoding
-            topDict.remove(cff_dict_Encoding);
-            encoding = QList<uint>();
-        
-            // new charset
-            QList<sid_type> newCharset;
-            // new charStrings
-            QList<QByteArray> newCharStrings;
-
-            for (int i = 0; i < cids.length(); ++i)
-            {
-                sid_type gid = cids[i];
-                sid_type sid = charset[gid];
-                if (sid < strings.length())
-                {
-                    sid = result.createSid(strings[sid]);
-                }
-                newCharset.append(sid);
-                newCharStrings.append(charStrings[gid]);
-            }
-            
-            charset = newCharset;
-            charStrings = newCharStrings;
-        }
-        else if (charset.length() > 1)
-        {
-            // copy over needed strings
-            for (int i = 0; i < charset.length(); ++i)
-            {
-                sid_type cid = charset[i];
-                if (cid < strings.length())
-                {
-                    cid = result.createSid(strings[cid]);
-                }
-                charset[i] = cid;
-            }
-        }
-        
-        // create new private dict
-        QHash<operator_type, uint> privatePatches;
-        QByteArray privateBytes = result.makeDict(privateDict, strings, privatePatches);
-
-        
-        // write new header, name and topdict, remember offset positions for patching
-        QHash<operator_type, uint> patchPositions;
-        uint topDictOffset = result.writeTopDict(fontName, topDict, strings, patchPositions);
-        
-        // write strings
-        // makeDict() needs to be called before this in order to create SIDs for used strings
-        result.writeSegment(makeIndex(result.strings.mid(sid_last_std + 1)));
-        
-        // write global subr (required but maybe empty)
-        result.writeSegment(makeIndex(globalSubr));
-
-        // write encoding
-        uint encodingOffset = encoding.size() > 1? result.writeSegment(makeEncoding(encoding)) : encoding.size() == 1? encoding[0] : 0;
-        
-        // write charset
-        uint charsetOffset = charset.size() > 1? result.writeSegment(makeCharset(charset)) : charset.size() == 1? charset[0] : 0;
-        
-        // write charstrings
-        uint charStringsOffset = result.writeSegment(makeIndex(charStrings));
-        
-        // write private dict
-        uint privateOffset = result.writeSegment(privateBytes);
-        
-        // write local subr
-        if (localSubrs.size() > 0)
-        {
-            uint localSubrOffset = result.writeSegment(makeIndex(localSubrs));
-
-            result.patch(privatePatches, privateOffset, cff_dict_Subrs, localSubrOffset - privateOffset);
-        }
-        
-        // patch topdict offset positions for charset, encoding, charstrings, private
-        result.patch(patchPositions, topDictOffset, cff_dict_charset, charsetOffset);
-        result.patch(patchPositions, topDictOffset, cff_dict_Encoding, encodingOffset);
-        result.patch(patchPositions, topDictOffset, cff_dict_CharStrings, charStringsOffset);
-        result.patch(patchPositions, topDictOffset, cff_dict_Private, privateOffset, privateBytes.length());
-        
-        // no FDArray and FDSelect yet
-        
-        return result;
-    }
-    
-    
-    
-    QByteArray extractFace(const QByteArray& cff, int faceIndex)
-    {
-        return CFF(cff).extractSubset(faceIndex, QList<uint>()).data();
-    }
-    
-    QByteArray subsetFace(const QByteArray& cff, QList<uint> cids)
-    {
-        return CFF(cff).extractSubset(0, cids).data();
-    }
-    
+			result.patch(privatePatches, privateOffset, cff_dict_Subrs, localSubrOffset - privateOffset);
+		}
+		
+		// patch topdict offset positions for charset, encoding, charstrings, private
+		result.patch(patchPositions, topDictOffset, cff_dict_charset, charsetOffset);
+		result.patch(patchPositions, topDictOffset, cff_dict_Encoding, encodingOffset);
+		result.patch(patchPositions, topDictOffset, cff_dict_CharStrings, charStringsOffset);
+		result.patch(patchPositions, topDictOffset, cff_dict_Private, privateOffset, privateBytes.length());
+		
+		// no FDArray and FDSelect yet
+		
+		return result;
+	}
+	
+	
+	
+	QByteArray extractFace(const QByteArray& cff, int faceIndex)
+	{
+		return CFF(cff).extractSubset(faceIndex, QList<uint>()).data();
+	}
+	
+	QByteArray subsetFace(const QByteArray& cff, QList<uint> cids)
+	{
+		return CFF(cff).extractSubset(0, cids).data();
+	}
+	
 } // namespace

Modified: trunk/Scribus/scribus/fonts/cff.h
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=20113&path=/trunk/Scribus/scribus/fonts/cff.h
==============================================================================
--- trunk/Scribus/scribus/fonts/cff.h (original)
+++ trunk/Scribus/scribus/fonts/cff.h Thu May 21 23:40:15 2015
@@ -23,222 +23,222 @@
 #include FT_FREETYPE_H
 
 namespace cff {
-    
-    typedef quint16 sid_type;
-    typedef uint operator_type;
-    
-    enum sid_range {
-        sid_min = 0,
-        sid_last_std = 390,
-        sid_max = 64999,
-        sid_max1 = 65000
-    };
-    
-    enum CFF_Header_Format {
-        cff_major   = 0,
-        cff_minor   = 1,
-        cff_hdrSize = 2,
-        cff_offSize = 3
-    };
-    
-    
-    enum CFF_INDEX_Format {
-        cff_idx_count   = 0,
-        cff_idx_offsize = 2,
-        cff_idx_offsets = 3
-    };
-    
-    
-    enum cff_Real_Format {
-        cff_nibble_maxDigit = 9,
-        cff_nibble_Point    = 10,
-        cff_nibble_PosExp   = 11,
-        cff_nibble_NegExp   = 12,
-        cff_nibble_Reserved = 13,
-        cff_nibble_Minus    = 14,
-        cff_nibble_End      = 15
-    };
-    
-    
-    enum CFF_DICT_Format {
-        cff_dict_version            = 0x00,
-        cff_dict_Notice             = 0x01,
-        cff_dict_FullName           = 0x02,
-        cff_dict_FamilyName         = 0x03,
-        cff_dict_Weight             = 0x04,
-        cff_dict_FontBBox           = 0x05,
-        cff_dict_BlueValues         = 0x06,
-        cff_dict_OtherBlues         = 0x07,
-        cff_dict_FamilyBlues        = 0x08,
-        cff_dict_FamilyOtherBlues   = 0x09,
-        cff_dict_StdHW              = 0x0a,
-        cff_dict_StdVW              = 0x0b,
-        cff_dict_TwoBytes           = 12,
-        cff_dict_UniqueID           = 0x0d,
-        cff_dict_XUID               = 0x0e,
-        cff_dict_charset            = 0x0f,
-        cff_dict_Encoding           = 0x10,
-        cff_dict_CharStrings        = 0x11,
-        cff_dict_Private            = 0x12,
-        cff_dict_Subrs              = 0x13,
-        cff_dict_defaultWidthX      = 0x14,
-        cff_dict_nominalWidthX      = 0x15,
-        // 0x16+ reserved
-        cff_dict_Card16             = 28,
-        cff_dict_Card32             = 29,
-        cff_dict_Real               = 30,
-        cff_dict_minOperand         = 32,
-        cff_dict_maxSmallCard       = 246,
-        cff_dict_biasSmallCard      = -139,
-        cff_dict_minPosCard         = 247,
-        cff_dict_maxPosCard         = 250,
-        cff_dict_biasPosCard        = 108,
-        cff_dict_minNegCard         = 251,
-        cff_dict_maxNegCard         = 254,
-        cff_dict_biasNegCard        = -108,
-        cff_dict_Copyright          = 0x0c00,
-        cff_dict_isFixedPitch       = 0x0c01,
-        cff_dict_ItalicAngle        = 0x0c02,
-        cff_dict_UnderlinePosition  = 0x0c03,
-        cff_dict_UnderlineThickness = 0x0c04,
-        cff_dict_CharstringType     = 0x0c06,
-        cff_dict_FontMatrix         = 0x0c07,
-        cff_dict_StrokeWidth        = 0x0c08,
-        cff_dict_BlueScale          = 0x0c09,
-        cff_dict_BlueShift          = 0x0c0a,
-        cff_dict_BlueFuzz           = 0x0c0b,
-        cff_dict_StemSnapH          = 0x0c0c,
-        cff_dict_StemSnapV          = 0x0c0d,
-        cff_dict_ForceBold          = 0x0c0e,
-        // 0c 0f -Reserved-
-        // 0c 10 -Reserved-
-        cff_dict_LanguageGroup      = 0x0c11,
-        cff_dict_ExpansionFactor    = 0x0c12,
-        cff_dict_initialRandomSeed  = 0x0c13,
-        cff_dict_SyntheticBase      = 0x0c14,
-        cff_dict_PostScript         = 0x0c15,
-        cff_dict_BaseFontName       = 0x0c16,
-        cff_dict_BaseFontBlend      = 0x0c17,
-        // 0c 18 -Reserved-
-        // 0c 19 -Reserved-
-        // 0c 1a -Reserved-
-        // 0c 1b -Reserved-
-        // 0c 1c -Reserved-
-        // 0c 1d -Reserved-
-        cff_dict_ROS                = 0x0c1e,
-        cff_dict_CIDFontVersion     = 0x0c1f,
-        cff_dict_CIDFontRevision    = 0x0c20,
-        cff_dict_CIDFontType        = 0x0c21,
-        cff_dict_CIDCount           = 0x0c22,
-        cff_dict_UIDBase            = 0x0c23,
-        cff_dict_FDArray            = 0x0c24,
-        cff_dict_FDSelect           = 0x0c25,
-        cff_dict_FontName           = 0x0c26
-    };
-    
-    
-    enum CFF_Variant_Type {
-        cff_varnt_Error    = 0,
-        cff_varnt_Bool     = 1,
-        cff_varnt_Card     = 2,
-        cff_varnt_SID      = 3,
-        cff_varnt_Real     = 4,
-        cff_varnt_Array    = 5,
-        cff_varnt_Delta    = 6,
-        cff_varnt_Operator = 7
-    };
-
-    
-    struct CFF_Number {
-        long long   card;
-        int         exponent;
-        uchar       type;
-        bool        isCardinal() const;
-        double      toDouble() const;
-        int         toCardinal() const;
-    };
-    
-
-    struct CFF_Variant {
-        uchar type;
-        QList<CFF_Number> array;
-        CFF_Variant()                      : type(cff_varnt_Error) {}
-        CFF_Variant(CFF_Number val)        : type(val.type), array() { array.append(val); }
-        CFF_Variant(QList<CFF_Number> arr) : type(cff_varnt_Array), array(arr) {}
-    };
-    
-    
-    class CFF {
-    public:
-        /// For creating new CFF fonts
-        CFF();
-        CFF(const QByteArray& cff);
-
-        uint readCard(uint pos) const;
-        QByteArray readSegment(uint pos, uint size) const;
-        QMap<operator_type,CFF_Variant> getDict(const QByteArray& dict) const;
-        QList<QByteArray> readIndex(uint& pos) const;
-        CFF extractSubset(uint faceIndex, QList<uint> cids) const;
-        
-        void dump();
-        QByteArray dump(const CFF_Variant& var) const;
-        
-        const QByteArray& data() const {
-            return bytes;
-        }
-        
-        QList<QByteArray> fontNames() const {
-            return fontTopDicts.keys();
-        }
-        
-        uint offset(uint unscaled)
-        {
-            return unscaled * offsetSize;
-        }
-        
-        QByteArray string(sid_type sid) const {
-            return sid < strings.length()? strings[sid] : "";
-        }
-        
-        sid_type sid(const QByteArray str) const {
-            return sids.contains(str)? sids[str] : sid_max1;
-        }
-        
-        void dump(QDataStream& out) const;
-        
-    private:
-        QByteArray bytes;
-        uint offsetSize;
-        
-        QList<QByteArray> names;
-        QMap<QByteArray, QMap<uint,CFF_Variant> > fontTopDicts;
-        QList<QByteArray> strings;
-        QHash<QByteArray,uint> sids;
-        QList<QByteArray> globalSubr;
-        
-        sid_type createSid(const QByteArray& str);
-        
-        CFF_Number parseDictElement(const QByteArray& dict, uint& pos) const;
-        CFF_Number parseReal(const QByteArray& dict, uint& pos) const;
-        CFF_Number parseCard(const QByteArray& dict, uint& pos) const;
-        QList<sid_type> readCharset(uint nGlyphs, uint& pos) const;
-        QList<uint> readEncoding(uint& pos) const;
-        
-        /// This write the header, name index and TopDict index for exactly one font.
-        /// All unknown offset are preset as 4 byte cardinal and corresponding operator positions returned
-        uint writeTopDict(QByteArray name, QMap<operator_type, CFF_Variant> dict, QList<QByteArray> oldStrings, QHash<operator_type, uint>& patches);
-        /// this will write another segment and return the start offset
-        uint writeSegment(const QByteArray& data);
-        void patch(QHash<operator_type, uint> patchPositions, uint patchOffset, operator_type op, uint offset, uint length = 0);
-        
-        QByteArray makeCharset(QList<sid_type>) const;
-        QByteArray makeEncoding(QList<uint>) const;
-        QByteArray makeIndex(QList<QByteArray> data) const;
-        QByteArray makeDict(QMap<operator_type, CFF_Variant> dict, QList<QByteArray> oldStrings, QHash<operator_type, uint>& patchAddresses);
-    };
-    
-    QByteArray extractFace(const QByteArray& cff, int faceIndex);
-    QByteArray subsetFace(const QByteArray& cff, QList<uint> cids);
+	
+	typedef quint16 sid_type;
+	typedef uint operator_type;
+	
+	enum sid_range {
+		sid_min = 0,
+		sid_last_std = 390,
+		sid_max = 64999,
+		sid_max1 = 65000
+	};
+	
+	enum CFF_Header_Format {
+		cff_major   = 0,
+		cff_minor   = 1,
+		cff_hdrSize = 2,
+		cff_offSize = 3
+	};
+	
+	
+	enum CFF_INDEX_Format {
+		cff_idx_count   = 0,
+		cff_idx_offsize = 2,
+		cff_idx_offsets = 3
+	};
+	
+	
+	enum cff_Real_Format {
+		cff_nibble_maxDigit = 9,
+		cff_nibble_Point    = 10,
+		cff_nibble_PosExp   = 11,
+		cff_nibble_NegExp   = 12,
+		cff_nibble_Reserved = 13,
+		cff_nibble_Minus    = 14,
+		cff_nibble_End      = 15
+	};
+	
+	
+	enum CFF_DICT_Format {
+		cff_dict_version            = 0x00,
+		cff_dict_Notice             = 0x01,
+		cff_dict_FullName           = 0x02,
+		cff_dict_FamilyName         = 0x03,
+		cff_dict_Weight             = 0x04,
+		cff_dict_FontBBox           = 0x05,
+		cff_dict_BlueValues         = 0x06,
+		cff_dict_OtherBlues         = 0x07,
+		cff_dict_FamilyBlues        = 0x08,
+		cff_dict_FamilyOtherBlues   = 0x09,
+		cff_dict_StdHW              = 0x0a,
+		cff_dict_StdVW              = 0x0b,
+		cff_dict_TwoBytes           = 12,
+		cff_dict_UniqueID           = 0x0d,
+		cff_dict_XUID               = 0x0e,
+		cff_dict_charset            = 0x0f,
+		cff_dict_Encoding           = 0x10,
+		cff_dict_CharStrings        = 0x11,
+		cff_dict_Private            = 0x12,
+		cff_dict_Subrs              = 0x13,
+		cff_dict_defaultWidthX      = 0x14,
+		cff_dict_nominalWidthX      = 0x15,
+		// 0x16+ reserved
+		cff_dict_Card16             = 28,
+		cff_dict_Card32             = 29,
+		cff_dict_Real               = 30,
+		cff_dict_minOperand         = 32,
+		cff_dict_maxSmallCard       = 246,
+		cff_dict_biasSmallCard      = -139,
+		cff_dict_minPosCard         = 247,
+		cff_dict_maxPosCard         = 250,
+		cff_dict_biasPosCard        = 108,
+		cff_dict_minNegCard         = 251,
+		cff_dict_maxNegCard         = 254,
+		cff_dict_biasNegCard        = -108,
+		cff_dict_Copyright          = 0x0c00,
+		cff_dict_isFixedPitch       = 0x0c01,
+		cff_dict_ItalicAngle        = 0x0c02,
+		cff_dict_UnderlinePosition  = 0x0c03,
+		cff_dict_UnderlineThickness = 0x0c04,
+		cff_dict_CharstringType     = 0x0c06,
+		cff_dict_FontMatrix         = 0x0c07,
+		cff_dict_StrokeWidth        = 0x0c08,
+		cff_dict_BlueScale          = 0x0c09,
+		cff_dict_BlueShift          = 0x0c0a,
+		cff_dict_BlueFuzz           = 0x0c0b,
+		cff_dict_StemSnapH          = 0x0c0c,
+		cff_dict_StemSnapV          = 0x0c0d,
+		cff_dict_ForceBold          = 0x0c0e,
+		// 0c 0f -Reserved-
+		// 0c 10 -Reserved-
+		cff_dict_LanguageGroup      = 0x0c11,
+		cff_dict_ExpansionFactor    = 0x0c12,
+		cff_dict_initialRandomSeed  = 0x0c13,
+		cff_dict_SyntheticBase      = 0x0c14,
+		cff_dict_PostScript         = 0x0c15,
+		cff_dict_BaseFontName       = 0x0c16,
+		cff_dict_BaseFontBlend      = 0x0c17,
+		// 0c 18 -Reserved-
+		// 0c 19 -Reserved-
+		// 0c 1a -Reserved-
+		// 0c 1b -Reserved-
+		// 0c 1c -Reserved-
+		// 0c 1d -Reserved-
+		cff_dict_ROS                = 0x0c1e,
+		cff_dict_CIDFontVersion     = 0x0c1f,
+		cff_dict_CIDFontRevision    = 0x0c20,
+		cff_dict_CIDFontType        = 0x0c21,
+		cff_dict_CIDCount           = 0x0c22,
+		cff_dict_UIDBase            = 0x0c23,
+		cff_dict_FDArray            = 0x0c24,
+		cff_dict_FDSelect           = 0x0c25,
+		cff_dict_FontName           = 0x0c26
+	};
+	
+	
+	enum CFF_Variant_Type {
+		cff_varnt_Error    = 0,
+		cff_varnt_Bool     = 1,
+		cff_varnt_Card     = 2,
+		cff_varnt_SID      = 3,
+		cff_varnt_Real     = 4,
+		cff_varnt_Array    = 5,
+		cff_varnt_Delta    = 6,
+		cff_varnt_Operator = 7
+	};
+
+	
+	struct CFF_Number {
+		long long   card;
+		int         exponent;
+		uchar       type;
+		bool        isCardinal() const;
+		double      toDouble() const;
+		int         toCardinal() const;
+	};
+	
+
+	struct CFF_Variant {
+		uchar type;
+		QList<CFF_Number> array;
+		CFF_Variant()                      : type(cff_varnt_Error) {}
+		CFF_Variant(CFF_Number val)        : type(val.type), array() { array.append(val); }
+		CFF_Variant(QList<CFF_Number> arr) : type(cff_varnt_Array), array(arr) {}
+	};
+	
+	
+	class CFF {
+	public:
+		/// For creating new CFF fonts
+		CFF();
+		CFF(const QByteArray& cff);
+
+		uint readCard(uint pos) const;
+		QByteArray readSegment(uint pos, uint size) const;
+		QMap<operator_type,CFF_Variant> getDict(const QByteArray& dict) const;
+		QList<QByteArray> readIndex(uint& pos) const;
+		CFF extractSubset(uint faceIndex, QList<uint> cids) const;
+		
+		void dump();
+		QByteArray dump(const CFF_Variant& var) const;
+		
+		const QByteArray& data() const {
+			return bytes;
+		}
+		
+		QList<QByteArray> fontNames() const {
+			return fontTopDicts.keys();
+		}
+		
+		uint offset(uint unscaled)
+		{
+			return unscaled * offsetSize;
+		}
+		
+		QByteArray string(sid_type sid) const {
+			return sid < strings.length()? strings[sid] : "";
+		}
+		
+		sid_type sid(const QByteArray str) const {
+			return sids.contains(str)? sids[str] : sid_max1;
+		}
+		
+		void dump(QDataStream& out) const;
+		
+	private:
+		QByteArray bytes;
+		uint offsetSize;
+		
+		QList<QByteArray> names;
+		QMap<QByteArray, QMap<uint,CFF_Variant> > fontTopDicts;
+		QList<QByteArray> strings;
+		QHash<QByteArray,uint> sids;
+		QList<QByteArray> globalSubr;
+		
+		sid_type createSid(const QByteArray& str);
+		
+		CFF_Number parseDictElement(const QByteArray& dict, uint& pos) const;
+		CFF_Number parseReal(const QByteArray& dict, uint& pos) const;
+		CFF_Number parseCard(const QByteArray& dict, uint& pos) const;
+		QList<sid_type> readCharset(uint nGlyphs, uint& pos) const;
+		QList<uint> readEncoding(uint& pos) const;
+		
+		/// This write the header, name index and TopDict index for exactly one font.
+		/// All unknown offset are preset as 4 byte cardinal and corresponding operator positions returned
+		uint writeTopDict(QByteArray name, QMap<operator_type, CFF_Variant> dict, QList<QByteArray> oldStrings, QHash<operator_type, uint>& patches);
+		/// this will write another segment and return the start offset
+		uint writeSegment(const QByteArray& data);
+		void patch(QHash<operator_type, uint> patchPositions, uint patchOffset, operator_type op, uint offset, uint length = 0);
+		
+		QByteArray makeCharset(QList<sid_type>) const;
+		QByteArray makeEncoding(QList<uint>) const;
+		QByteArray makeIndex(QList<QByteArray> data) const;
+		QByteArray makeDict(QMap<operator_type, CFF_Variant> dict, QList<QByteArray> oldStrings, QHash<operator_type, uint>& patchAddresses);
+	};
+	
+	QByteArray extractFace(const QByteArray& cff, int faceIndex);
+	QByteArray subsetFace(const QByteArray& cff, QList<uint> cids);
 }
 
 

Modified: trunk/Scribus/scribus/fonts/sfnt.cpp
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=20113&path=/trunk/Scribus/scribus/fonts/sfnt.cpp
==============================================================================
--- trunk/Scribus/scribus/fonts/sfnt.cpp (original)
+++ trunk/Scribus/scribus/fonts/sfnt.cpp Thu May 21 23:40:15 2015
@@ -16,1236 +16,1237 @@
 #include <QDebug>
 
 namespace sfnt {
-    
-    uchar byte(const QByteArray & bb, uint pos)
-    {
-        const unsigned char * pp = reinterpret_cast<const unsigned char*>(bb.data()) + pos;
-        return pp[0];
-    }
-    quint32 word(const QByteArray & bb, uint pos)
-    {
-        const unsigned char * pp = reinterpret_cast<const unsigned char*>(bb.data()) + pos;
-        return pp[0] << 24 | pp[1] << 16 | pp[2] << 8 | pp[3];
-    }
-    
-    void putWord(QByteArray & bb, uint pos, quint32 val)
-    {
-        unsigned char * pp = reinterpret_cast<unsigned char*>(bb.data()) + pos;
-        *pp++ = (val >> 24) & 0xFF;
-        *pp++ = (val >> 16) & 0xFF;
-        *pp++ = (val >> 8) & 0xFF;
-        *pp++ = (val) & 0xFF;
-    }
-    
-    void appendWord(QByteArray & bb, quint32 val)
-    {
-        uint pos = bb.size();
-        bb.resize(pos + 4);
-        putWord(bb, pos, val);
-    }
-    
-    quint16 word16(const QByteArray & bb, uint pos)
-    {
-        const unsigned char * pp = reinterpret_cast<const unsigned char*>(bb.data()) + pos;
-        return pp[0] << 8 | pp[1];
-    }
-    
-    void putWord16(QByteArray & bb, uint pos, quint16 val)
-    {
-        unsigned char * pp = reinterpret_cast<unsigned char*>(bb.data()) + pos;
-        *pp++ = (val >> 8) & 0xFF;
-        *pp++ = (val) & 0xFF;
-    }
-    
-    void appendWord16(QByteArray & bb, quint16 val)
-    {
-        uint pos = bb.size();
-        bb.resize(pos + 2);
-        putWord16(bb, pos, val);
-    }
-    
-    const QByteArray tag(const QByteArray& bb, uint pos)
-    {
-        return QByteArray::fromRawData(bb.constData() + pos, 4);
-    }
-    
-    const QByteArray tag(uint word)
-    {
-        QByteArray result;
-        result.resize(4);
-        result[0] = (word >> 24) & 0xFF;
-        result[1] = (word >> 16) & 0xFF;
-        result[2] = (word >> 8) & 0xFF;
-        result[3] = (word) & 0xFF;
-        return result;
-    }
-    
-    bool copy(QByteArray & dst, uint to, const QByteArray & src, uint from, uint len)
-    {
-        if (!dst.data())
-            return false;
-        if (!src.data())
-            return false;
-        if (to + len > static_cast<uint>(dst.size()))
-            return false;
-        if (from + len > static_cast<uint>(src.size()))
-            return false;
-        
-        memcpy(dst.data() + to, src.data() + from, len);
-        return true;
-    }
-    
-
-
-
-
-    
+	
+	uchar byte(const QByteArray & bb, uint pos)
+	{
+		const unsigned char * pp = reinterpret_cast<const unsigned char*>(bb.data()) + pos;
+		return pp[0];
+	}
+	quint32 word(const QByteArray & bb, uint pos)
+	{
+		const unsigned char * pp = reinterpret_cast<const unsigned char*>(bb.data()) + pos;
+		return pp[0] << 24 | pp[1] << 16 | pp[2] << 8 | pp[3];
+	}
+	
+	void putWord(QByteArray & bb, uint pos, quint32 val)
+	{
+		unsigned char * pp = reinterpret_cast<unsigned char*>(bb.data()) + pos;
+		*pp++ = (val >> 24) & 0xFF;
+		*pp++ = (val >> 16) & 0xFF;
+		*pp++ = (val >> 8) & 0xFF;
+		*pp++ = (val) & 0xFF;
+	}
+	
+	void appendWord(QByteArray & bb, quint32 val)
+	{
+		uint pos = bb.size();
+		bb.resize(pos + 4);
+		putWord(bb, pos, val);
+	}
+	
+	quint16 word16(const QByteArray & bb, uint pos)
+	{
+		const unsigned char * pp = reinterpret_cast<const unsigned char*>(bb.data()) + pos;
+		return pp[0] << 8 | pp[1];
+	}
+	
+	void putWord16(QByteArray & bb, uint pos, quint16 val)
+	{
+		unsigned char * pp = reinterpret_cast<unsigned char*>(bb.data()) + pos;
+		*pp++ = (val >> 8) & 0xFF;
+		*pp++ = (val) & 0xFF;
+	}
+	
+	void appendWord16(QByteArray & bb, quint16 val)
+	{
+		uint pos = bb.size();
+		bb.resize(pos + 2);
+		putWord16(bb, pos, val);
+	}
+	
+	const QByteArray tag(const QByteArray& bb, uint pos)
+	{
+		return QByteArray::fromRawData(bb.constData() + pos, 4);
+	}
+	
+	const QByteArray tag(uint word)
+	{
+		QByteArray result;
+		result.resize(4);
+		result[0] = (word >> 24) & 0xFF;
+		result[1] = (word >> 16) & 0xFF;
+		result[2] = (word >> 8) & 0xFF;
+		result[3] = (word) & 0xFF;
+		return result;
+	}
+	
+	bool copy(QByteArray & dst, uint to, const QByteArray & src, uint from, uint len)
+	{
+		if (!dst.data())
+			return false;
+		if (!src.data())
+			return false;
+		if (to + len > static_cast<uint>(dst.size()))
+			return false;
+		if (from + len > static_cast<uint>(src.size()))
+			return false;
+		
+		memcpy(dst.data() + to, src.data() + from, len);
+		return true;
+	}
+
+
+
+
+
+
 const uint post_format10_names_count = 258;
 
-    
+
 static const char* post_format10_names[] = {
-    ".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",
-    "nonbreakingspace",
-    "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",
-    "Idotaccent",
-    "Scedilla",
-    "scedilla",
-    "Cacute",
-    "cacute",
-    "Ccaron",
-    "ccaron",
-    "dcroat"
+	".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",
+	"nonbreakingspace",
+	"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",
+	"Idotaccent",
+	"Scedilla",
+	"scedilla",
+	"Cacute",
+	"cacute",
+	"Ccaron",
+	"ccaron",
+	"dcroat"
 };
 
 
 
 uint PostTable::numberOfGlyphs() const
 {
-    if (names.length() > 0)
-        return names.length();
-    else
-        return post_format10_names_count;
+	if (names.length() > 0)
+		return names.length();
+	else
+		return post_format10_names_count;
 }
 
 QString PostTable::nameFor(uint glyph) const
 {
-    if (glyph < names.length())
-    {
-        return names[glyph];
-    }
-    else if (glyph < sfnt::post_format10_names_count)
-    {
-        return post_format10_names[glyph];
-    }
-    else
-    {
-        return ".notdef";
-    }
+	if (glyph < names.length())
+	{
+		return names[glyph];
+	}
+	else if (glyph < sfnt::post_format10_names_count)
+	{
+		return post_format10_names[glyph];
+	}
+	else
+	{
+		return ".notdef";
+	}
 }
 
 
 void PostTable::readFrom(FT_Face face)
 {
-    QByteArray postData;
-    FT_ULong size = 0;
-    int error = FT_Load_Sfnt_Table ( face, TTAG_post , 0, NULL, &size );
-    qDebug() << "load post" << error << size;
-    if (error || size == 0)
-    {
-        errorMsg = "no post table";
-        usable = false;
-        return;
-    }
-    postData.resize(size);
-    error = FT_Load_Sfnt_Table ( face, TTAG_post , 0, reinterpret_cast<FT_Byte*>(postData.data()), &size );
-    if (error)
-    {
-        errorMsg = "can't load post table";
-        usable = false;
-        return;
-    }
-    
-    switch (sfnt::word(postData, ttf_post_format))
-    {
-        case sfnt::post_format10:
-            usable = true;
-            names.clear();
-            return;
-        case sfnt::post_format20:
-            break;
-        case sfnt::post_format30:
-            errorMsg = QString("post table has no glyph names");
-            usable = false;
-            return;
-        case sfnt::post_format25:
-        case sfnt::post_format40:
-        default:
-            errorMsg = QString("unsupported post format %1").arg(sfnt::word(postData,0));
-            usable = false;
-            return;
-            
-    }
-    QMap<QString,uint> usedNames;
-    QList<QByteArray> pascalStrings;
-    
-    uint nrOfGlyphs = sfnt::word16(postData, ttf_post_header_length);
-    uint stringPos = ttf_post_header_length + 2 + 2 * nrOfGlyphs;
-    while (stringPos < postData.length())
-    {
-        int strLen = byte(postData, stringPos);
-        ++stringPos;
-        pascalStrings.append(postData.mid(stringPos, strLen));
-        stringPos += strLen;
-    }
-    uint pos = ttf_post_header_length + 2;
-    for (int gid = 0; gid < nrOfGlyphs; ++gid)
-    {
-        uint nameIndex = sfnt::word16(postData, pos);
-        pos += 2;
-        QString name;
-        if (nameIndex < sfnt::post_format10_names_count)
-            name = sfnt::post_format10_names[nameIndex];
-        else if (nameIndex < pascalStrings.length() + sfnt::post_format10_names_count)
-            name = pascalStrings[nameIndex - sfnt::post_format10_names_count];
-        else {
-            usable = false;
-            errorMsg = QString("missing name %1 for glyph %2").arg(nameIndex).arg(gid);
-            return;
-        }
-        if (name != ".notdef" && name[0] != QChar(0) && usedNames.contains(name))
-        {
-            usable = false;
-            errorMsg = QString("duplicate name %1 used for glyphs %2 and %3").arg(name).arg(gid).arg(usedNames[name]);
-            return;
-        }
-        usedNames[name] = gid;
-        names.append(name);
-    }
-    errorMsg = "";
-    usable = true;
+	QByteArray postData;
+	FT_ULong size = 0;
+	int error = FT_Load_Sfnt_Table ( face, TTAG_post , 0, NULL, &size );
+	qDebug() << "load post" << error << size;
+	if (error || size == 0)
+	{
+		errorMsg = "no post table";
+		usable = false;
+		return;
+	}
+	postData.resize(size);
+	error = FT_Load_Sfnt_Table ( face, TTAG_post , 0, reinterpret_cast<FT_Byte*>(postData.data()), &size );
+	if (error)
+	{
+		errorMsg = "can't load post table";
+		usable = false;
+		return;
+	}
+	
+	switch (sfnt::word(postData, ttf_post_format))
+	{
+		case sfnt::post_format10:
+			usable = true;
+			names.clear();
+			return;
+		case sfnt::post_format20:
+			break;
+		case sfnt::post_format30:
+			errorMsg = QString("post table has no glyph names");
+			usable = false;
+			return;
+		case sfnt::post_format25:
+		case sfnt::post_format40:
+		default:
+			errorMsg = QString("unsupported post format %1").arg(sfnt::word(postData,0));
+			usable = false;
+			return;
+			
+	}
+	QMap<QString,uint> usedNames;
+	QList<QByteArray> pascalStrings;
+	
+	uint nrOfGlyphs = sfnt::word16(postData, ttf_post_header_length);
+	uint stringPos = ttf_post_header_length + 2 + 2 * nrOfGlyphs;
+	while (stringPos < postData.length())
+	{
+		int strLen = byte(postData, stringPos);
+		++stringPos;
+		pascalStrings.append(postData.mid(stringPos, strLen));
+		stringPos += strLen;
+	}
+	uint pos = ttf_post_header_length + 2;
+	for (int gid = 0; gid < nrOfGlyphs; ++gid)
+	{
+		uint nameIndex = sfnt::word16(postData, pos);
+		pos += 2;
+		QString name;
+		if (nameIndex < sfnt::post_format10_names_count)
+			name = sfnt::post_format10_names[nameIndex];
+		else if (nameIndex < pascalStrings.length() + sfnt::post_format10_names_count)
+			name = pascalStrings[nameIndex - sfnt::post_format10_names_count];
+		else {
+			usable = false;
+			errorMsg = QString("missing name %1 for glyph %2").arg(nameIndex).arg(gid);
+			return;
+		}
+		if (name != ".notdef" && name[0] != QChar(0) && usedNames.contains(name))
+		{
+			usable = false;
+			errorMsg = QString("duplicate name %1 used for glyphs %2 and %3").arg(name).arg(gid).arg(usedNames[name]);
+			return;
+		}
+		usedNames[name] = gid;
+		names.append(name);
+	}
+	errorMsg = "";
+	usable = true;
 }
 
-    
-    
-    int copyTable(QByteArray& ttf, uint destDirEntry, uint pos, const QByteArray& source, uint dirEntry)
-    {
-        FT_ULong tag = word(source, dirEntry + ttf_TableRecord_tag);
-        uint checksum = word(source, dirEntry + ttf_TableRecord_checkSum);
-        uint tableStart = word(source, dirEntry + ttf_TableRecord_offset);
-        uint tableSize  = word(source, dirEntry + ttf_TableRecord_length);
-        
-        if (!copy(ttf, pos, source, tableStart, tableSize))
-            return -1;
-        
-        putWord(ttf, destDirEntry + ttf_TableRecord_tag, tag);
-        putWord(ttf, destDirEntry + ttf_TableRecord_checkSum, checksum);
-        putWord(ttf, destDirEntry + ttf_TableRecord_offset, pos);
-        putWord(ttf, destDirEntry + ttf_TableRecord_length, tableSize);
-        
-        return tableSize;
-    }
-    
+
+
+	int copyTable(QByteArray& ttf, uint destDirEntry, uint pos, const QByteArray& source, uint dirEntry)
+	{
+		FT_ULong tag = word(source, dirEntry + ttf_TableRecord_tag);
+		uint checksum = word(source, dirEntry + ttf_TableRecord_checkSum);
+		uint tableStart = word(source, dirEntry + ttf_TableRecord_offset);
+		uint tableSize  = word(source, dirEntry + ttf_TableRecord_length);
+		
+		if (!copy(ttf, pos, source, tableStart, tableSize))
+			return -1;
+		
+		putWord(ttf, destDirEntry + ttf_TableRecord_tag, tag);
+		putWord(ttf, destDirEntry + ttf_TableRecord_checkSum, checksum);
+		putWord(ttf, destDirEntry + ttf_TableRecord_offset, pos);
+		putWord(ttf, destDirEntry + ttf_TableRecord_length, tableSize);
+		
+		return tableSize;
+	}
+
 
 QByteArray extractFace(const QByteArray& coll, int faceIndex)
 {
-    QByteArray result;
-    
-    const int numFonts = word(coll, ttc_numFonts);
-    if (faceIndex >= static_cast<int>(numFonts))
-    {
-        return result;
-    }
-
-    uint faceOffset = sfnt::word(coll, ttc_OffsetTables + 4 * faceIndex);
-    uint nTables    = sfnt::word16(coll, faceOffset + ttf_numtables);
-    
-    qDebug() << QObject::tr("extracting face %1 from font %2 (offset=%3, nTables=%4)").arg(faceIndex).arg("collection").arg(faceOffset).arg(nTables);
-    
-    uint headerLength = ttf_TableRecords + ttf_TableRecord_Size * nTables;
-    
-    uint tableLengths = 0;
-    // sum table lengths incl padding
-    for (uint i=0; i < nTables; ++i)
-    {
-        tableLengths += sfnt::word(coll, faceOffset + ttf_TableRecords + ttf_TableRecord_Size * i + ttf_TableRecord_length);
-        tableLengths = (tableLengths+3) & ~3;
-    }
-    result.resize(headerLength + tableLengths);
-    if (!result.data())
-    {
-        result.resize(0);
-        return result;
-    }
-    
-    // write header
-    //		sDebug(QObject::tr("memcpy header: %1 %2 %3").arg(0).arg(faceOffset).arg(headerLength));
-    if (!copy(result, 0, coll, faceOffset, headerLength))
-    {
-        result.resize(0);
-        return result;
-    }
-    uint pos = headerLength;
-    for (uint i=0; i < nTables; ++i)
-    {
-        uint sourceDirEntry = faceOffset + ttf_TableRecords + ttf_TableRecord_Size * i;
-        uint destDirEntry = ttf_TableRecords + ttf_TableRecord_Size * i;
-        
-        int tableSize = copyTable(result, destDirEntry, pos, coll, sourceDirEntry);
-        if (tableSize < 0)
-        {
-            result.resize(0);
-            return result;
-        }
-        pos += tableSize;
-
-        // pad
-        while ((pos & 3) != 0)
-            result.data()[pos++] = '\0';
-    }
-    return result;
+	QByteArray result;
+	
+	const int numFonts = word(coll, ttc_numFonts);
+	if (faceIndex >= static_cast<int>(numFonts))
+	{
+		return result;
+	}
+
+	uint faceOffset = sfnt::word(coll, ttc_OffsetTables + 4 * faceIndex);
+	uint nTables	= sfnt::word16(coll, faceOffset + ttf_numtables);
+	
+	qDebug() << QObject::tr("extracting face %1 from font %2 (offset=%3, nTables=%4)").arg(faceIndex).arg("collection").arg(faceOffset).arg(nTables);
+	
+	uint headerLength = ttf_TableRecords + ttf_TableRecord_Size * nTables;
+	
+	uint tableLengths = 0;
+	// sum table lengths incl padding
+	for (uint i=0; i < nTables; ++i)
+	{
+		tableLengths += sfnt::word(coll, faceOffset + ttf_TableRecords + ttf_TableRecord_Size * i + ttf_TableRecord_length);
+		tableLengths = (tableLengths+3) & ~3;
+	}
+	result.resize(headerLength + tableLengths);
+	if (!result.data())
+	{
+		result.resize(0);
+		return result;
+	}
+	
+	// write header
+	//		sDebug(QObject::tr("memcpy header: %1 %2 %3").arg(0).arg(faceOffset).arg(headerLength));
+	if (!copy(result, 0, coll, faceOffset, headerLength))
+	{
+		result.resize(0);
+		return result;
+	}
+	uint pos = headerLength;
+	for (uint i=0; i < nTables; ++i)
+	{
+		uint sourceDirEntry = faceOffset + ttf_TableRecords + ttf_TableRecord_Size * i;
+		uint destDirEntry = ttf_TableRecords + ttf_TableRecord_Size * i;
+		
+		int tableSize = copyTable(result, destDirEntry, pos, coll, sourceDirEntry);
+		if (tableSize < 0)
+		{
+			result.resize(0);
+			return result;
+		}
+		pos += tableSize;
+
+		// pad
+		while ((pos & 3) != 0)
+			result.data()[pos++] = '\0';
+	}
+	return result;
 }
-    
-    
-    uint getTableDirEntry(const QByteArray& ttf, const QByteArray& ttfTag)
-    {
-        uint nTables = word16(ttf, ttf_numtables);
-        uint pos = ttf_TableRecords;
-        for (uint i=0; i < nTables; ++i)
-        {
-            if (ttfTag == tag(word(ttf, pos + ttf_TableRecord_tag)))
-            {
-                return pos;
-            }
-            pos += ttf_TableRecord_Size;
-        }
-        return 0;
-    }
-    
-    
-    const QByteArray getTable(const QByteArray& ttf, const QByteArray& ttfTag)
-    {
-        uint pos = getTableDirEntry(ttf, ttfTag);
-        if (pos > 0)
-        {
-            uint offset = word(ttf, pos + ttf_TableRecord_offset);
-            uint length = word(ttf, pos + ttf_TableRecord_length);
-            return QByteArray::fromRawData(ttf.constData() + offset, length);
-        }
-        else
-        {
-            return QByteArray();
-        }
-    }
-    
-    QByteArray createTableDir(const QList<QByteArray>& tags)
-    {
-        QByteArray result;
-        uint numTables = tags.length();
-        uint tableRecordsSize = numTables * ttf_TableRecord_Size;
-        result.resize(ttf_TableRecords +  tableRecordsSize);
-        uint entrySelector = 0;
-        uint searchRange = ttf_TableRecord_Size;
-        while (2*searchRange < tableRecordsSize)
-        {
-            searchRange *= 2;
-            ++entrySelector;
-        }
-        uint rangeShift = tableRecordsSize - searchRange;
-        
-        putWord(result, ttf_sfnt_version, 0x00010000);
-        putWord16(result, ttf_numtables, numTables);
-        putWord16(result, ttf_searchRange, searchRange);
-        putWord16(result, ttf_entrySelector, entrySelector);
-        putWord16(result, ttf_rangeShift, rangeShift);
-        for (int i = 0; i < numTables; ++i)
-        {
-            copy(result, ttf_TableRecords + i*ttf_TableRecord_Size + ttf_TableRecord_tag, tags[i], 0, 4);
-            putWord(result, ttf_TableRecords + i*ttf_TableRecord_Size + ttf_TableRecord_checkSum, 0);
-            putWord(result, ttf_TableRecords + i*ttf_TableRecord_Size + ttf_TableRecord_offset, 0);
-            putWord(result, ttf_TableRecords + i*ttf_TableRecord_Size +ttf_TableRecord_length, 0);
-        }
-        return result;
-    }
-    
-    
-    quint32 calcTableChecksum(QByteArray& table)
-    {
-        quint32 Sum = 0L;
-        for (int pos = 0; pos < table.length(); pos += 4)
-            Sum += word(table, pos);
-        return Sum;
-    }
-    
-
-    void writeTable(QByteArray& ttf, const QByteArray& tag, QByteArray& table)
-    {
-        qDebug() << "writing table" << tag << table.size() << "@" << ttf.size();
-        uint length = table.size();
-        while (table.size() & 0x3)
-            table.append('\0');
-        uint offset = ttf.size();
-        uint checksum = calcTableChecksum(table);
-        uint pos = getTableDirEntry(ttf, tag);
-        putWord(ttf, pos + ttf_TableRecord_checkSum, checksum);
-        putWord(ttf, pos + ttf_TableRecord_offset, offset);
-        putWord(ttf, pos + ttf_TableRecord_length, length);
-        ttf.append(table);
-    }
-    
-    
-    bool hasLongLocaFormat(const QByteArray& ttf)
-    {
-        const QByteArray head = getTable(ttf, "head");
-        uint idxToLocFormat = word16(head, ttf_head_indexToLocFormat);
-        qDebug() << "loca format:" << (void*)idxToLocFormat;
-        return idxToLocFormat == 1;
-    }
-    
-    
-    QList<quint32> readLoca(const QByteArray& ttf)
-    {
-        QList<quint32> result;
-        const QByteArray loca = getTable(ttf, "loca");
-        if (hasLongLocaFormat(ttf))
-        {
-            for (int i = 0; i < loca.length(); i+=4)
-            {
-                result.append(word(loca, i));
-            }
-        }
-        else
-        {
-            for (int i = 0; i < loca.length(); i+=2)
-            {
-                result.append(word16(loca, i) * 2);
-            }
-        }
-        return result;
-    }
-    
-    const QByteArray writeLoca(const QList<uint>& loca, bool longFormat)
-    {
-        QByteArray result;
-        if (longFormat)
-        {
-            for(int i=0; i < loca.length(); ++i)
-                appendWord(result, loca[i]);
-        }
-        else
-        {
-            for(int i=0; i < loca.length(); ++i)
-                appendWord16(result, loca[i] / 2);
-        }
-        return result;
-    }
-    
-    
-    QList<std::pair<qint16,quint16> > readHmtx(const QByteArray& ttf)
-    {
-        QList<std::pair<qint16,quint16> > result;
-        const QByteArray hhea = getTable(ttf, "hhea");
-        const QByteArray hmtx = getTable(ttf, "hmtx");
-        uint endOfLongHorMetrics = 4 * word16(hhea, ttf_hhea_numOfLongHorMetrics);
-        qint16 advance;
-        quint16 leftSideBearing;
-        uint pos = 0;
-        while (pos < endOfLongHorMetrics)
-        {
-            advance = word16(hmtx, pos);
-            leftSideBearing = word16(hmtx, pos+2);
-            qDebug() << pos << "hmtx" << advance << leftSideBearing;
-            result.append(std::pair<qint16,quint16>(advance, leftSideBearing));
-            pos += 4;
-        }
-        while (pos < hmtx.length())
-        {
-            leftSideBearing = word16(hmtx, pos);
-            qDebug() << pos << "hmtx =" << advance << leftSideBearing;
-            result.append(std::pair<qint16,quint16>(advance, leftSideBearing));
-            pos += 2;
-        }
-        return result;
-    }
-    
-    
-    QByteArray writeHmtx(const QList<std::pair<qint16,quint16> >& longHorMetrics)
-    {
-        QByteArray result;
-        QList<std::pair<qint16,quint16> >::const_iterator it;
-        int i = 0;
-        for (it = longHorMetrics.cbegin(); it < longHorMetrics.cend(); ++it)
-        {
-            qDebug() << "hmtx" << i++ << it->first << it->second;
-            appendWord16(result, it->first);
-            appendWord16(result, it->second);
-        }
-        return result;
-    }
-    
-    
-    QMap<uint, uint> readCMap(const QByteArray& ttf)
-    {
-        QMap<uint,uint> result;
-        const QByteArray cmaps = getTable(ttf, "cmap");
-        
-        uint numSubtables = word16(cmaps, ttf_cmap_numberSubtables);
-        uint startOfUnicodeTable = 0;
-        uint format = 0;
-        uint pos = ttf_cmap_encodings;
-        for (int i = 0; i < numSubtables; ++i)
-        {
-            uint platform = word16(cmaps, pos + ttf_cmap_encoding_platformID);
-            uint encoding = word16(cmaps, pos + ttf_cmap_encoding_platformSpecificID);
-            uint offset = word(cmaps, pos + ttf_cmap_encoding_offset);
-            format = word16(cmaps, offset + ttf_cmapx_format);
-            pos += ttf_cmap_encoding_Size;
-            
-            if (format < 4 || format > 12)
-                continue;
-            if (platform == 0 || (platform == 3 && encoding == 1))
-            {
-                startOfUnicodeTable = offset;
-                break;
-            }
-            format = 1; // no such format
-        }
-        qDebug() << "reading cmap format" << format;
-        switch(format)
-        {
-            case 4:
-            {
-                uint segCount2 = word16(cmaps, startOfUnicodeTable + ttf_cmap4_segCountX2);
-                uint endCodes = startOfUnicodeTable + ttf_cmap4_EndCodes;
-                uint startCodes = endCodes + segCount2 + ttf_cmap4_StartCodes_EndCodes;
-                uint idDeltas = startCodes + segCount2 + ttf_cmap4_IdDeltas_StartCodes;
-                uint idRangeOffsets = idDeltas + segCount2 + ttf_cmap4_IdRangeOffsets_IdDeltas;
-                //uint glyphIndexArray = idRangeOffsets + segCount2 + ttf_cmap4_GlyphIds_IdRangeOffsets;
-                
-                for (int seg = 0; seg < segCount2; seg+=2)
-                {
-                    uint start = word16(cmaps, startCodes + seg);
-                    uint end = word16(cmaps, endCodes + seg);
-                    uint idDelta = word16(cmaps, idDeltas + seg);
-                    uint idRangeOffset = word16(cmaps, idRangeOffsets + seg);
-                    for (uint c = start; c <= end; ++c)
-                    {
-                        quint16 glyph;
-                        if (idRangeOffset > 0)
-                        {
-                            uint glyphIndexAdress = idRangeOffset + 2*(c-start) + (idRangeOffsets + seg);
-                            glyph = word16(cmaps, glyphIndexAdress);
-                            if (glyph != 0)
-                                glyph += idDelta;
-                        }
-                        else
-                        {
-                            glyph = c + idDelta;
-                        }
-                        if (!result.contains(c))
-                        {
-                            // search would always find the one in the segment with the lower endcode, i.e. earlier segment
-                            if (c < 256 || glyph == 0) qDebug() << "(" << QChar(c) << "," << glyph << ")";
-                            result[c] = glyph;
-                        }
-                        else
-                        {
-                            // nothing to do. No idea if fonts with overlapping cmap4 segments exist, though.
-                        }
-                    }
-                }
-                break;
-            }
-            case 6:
-            {
-                uint firstCode = word16(cmaps, startOfUnicodeTable + ttf_cmap6_firstCode);
-                uint count = word16(cmaps, startOfUnicodeTable + ttf_cmap6_entryCount);
-                pos = word16(cmaps, startOfUnicodeTable + ttf_cmap6_glyphIndexArray);
-                for (int i = 0; i < count; ++i)
-                {
-                    result[firstCode + i] = word16(cmaps, pos);
-                    pos += 2;
-                }
-                break;
-            }
-            case 12:
-            {
-                uint nGroups = word(cmaps, startOfUnicodeTable + ttf_cmap12_nGroups);
-                pos = startOfUnicodeTable + ttf_cmap12_Groups;
-                for (int grp = 0; grp < nGroups; ++grp)
-                {
-                    uint start = word(cmaps, pos + ttf_cmap12_Group_startCharCode);
-                    uint end = word(cmaps, pos + ttf_cmap12_Group_endCharCode);
-                    uint gid = word(cmaps, pos + ttf_cmap12_Group_startGlyphCode);
-                    for (uint c = start; c <= end; ++c)
-                    {
-                        result[c] = gid;
-                        ++gid;
-                    }
-                    pos += ttf_cmap12_Group_Size;
-                }
-                break;
-            }
-            default:
-            {
-                qDebug() << "unsupported cmap format" << format;
-                break;
-            }
-        }
-        return result;
-    }
-    
-    
-    
-    const QByteArray writeCMap(const QMap<uint, uint>& cmap)
-    {
-        // we always write only one table: platform=3(MS), encoding=1(Unicode 16bit)
-        QByteArray result;
-        appendWord16(result, 0); // version
-        appendWord16(result, 1); // number of subtables
-        appendWord16(result, 3); // platformID Microsoft
-        appendWord16(result, 1); // encodingID UnicodeBMP
-        appendWord(result, result.size() + 4); // offset
-        
-        // find the segments
-        
-        QList<uint> chars;
-        QMap<uint, uint>::ConstIterator cit;
-        qDebug() << "writing cmap";
-        for(cit = cmap.cbegin(); cit != cmap.cend(); ++cit)
-        {
-            uint ch = cit.key();
-            if (!QChar::requiresSurrogates(ch) && cit.value() != 0)
-            {
-                qDebug() << "(" << QChar(cit.key()) << "," << cit.value() << ")";
-                chars.append(ch);
-            }
-//            qDebug() << QChar(ch) << QChar::requiresSurrogates(ch) << cit.value();
-        }
-        std::sort(chars.begin(), chars.end());
-        
-        QList<quint16> startCodes;
-        QList<quint16> endCodes;
-        QList<quint16> idDeltas;
-        QList<quint16> rangeOffsets;
-        
-        uint pos = 0;
-        do {
-            quint16 start = chars[pos];
-            quint16 delta = cmap[start] - start;
-            quint16 rangeOffset = 0;
-            quint16 end = start;
-            quint16 next;
-            ++pos;
-            while (pos < chars.length() && (next = chars[pos]) == end+1)
-            {
-                end = next;
-                if (delta != (quint16)(cmap[chars[pos]] - next))
-                {
-                    rangeOffset = 1; // will be changed later
-                }
-                ++pos;
-            }
-            startCodes.append(start);
-            endCodes.append(end);
-            idDeltas.append(delta);
-            rangeOffsets.append(rangeOffset);
-        } while(pos < chars.length());
-        
-        startCodes.append(0xFFFF);
-        endCodes.append(0xFFFF);
-        idDeltas.append(1); // makes gid 0
-        rangeOffsets.append(0);
-        
-        // write the tables
-        
-        uint startOfTable = result.size();
-        result.resize(startOfTable + ttf_cmap4_EndCodes);
-
-        uint segCount = endCodes.length();
-        uint segCountX2 = 2 * segCount;
-        uint entrySelector = 0;
-        uint searchRange = 2;
-        while (searchRange <= segCount)
-        {
-            ++entrySelector;
-            searchRange *= 2;
-        }
-        putWord16(result, startOfTable + ttf_cmapx_format, 4);
-        /* ttf_cmap4_length is set later */
-        putWord16(result, startOfTable + ttf_cmap4_language, 0);
-        putWord16(result, startOfTable + ttf_cmap4_segCountX2, segCountX2);
-        putWord16(result, startOfTable + ttf_cmap4_searchRange, searchRange);
-        putWord16(result, startOfTable + ttf_cmap4_entrySelector, entrySelector);
-        putWord16(result, startOfTable + ttf_cmap4_rangeShift, segCountX2 - searchRange);
-        
-        for (int i = 0; i < segCount; ++i)
-        {
-            appendWord16(result, endCodes[i]);
-        };
-        appendWord16(result, 0); // reservedPad
-        
-        for (int i = 0; i < segCount; ++i)
-        {
-            appendWord16(result, startCodes[i]);
-        };
-        for (int i = 0; i < segCount; ++i)
-        {
-            appendWord16(result, idDeltas[i]);
-        };
-        
-        
-        uint startOfIdRangeOffsetTable = result.size();
-        uint startOfGlyphIndexArray = startOfIdRangeOffsetTable + segCountX2;
-        result.resize(startOfGlyphIndexArray);
-        
-        for (int i = 0; i < segCount; ++i)
-        {
-            uint idRangeOffsetAddress = startOfIdRangeOffsetTable + 2*i;
-            if (rangeOffsets[i] == 0)
-            {
-                quint16 dbg = startCodes[i] + idDeltas[i];
-                qDebug() << QChar(startCodes[i]) << "-" << QChar(endCodes[i]) << "/" << (endCodes[i]-startCodes[i]+1) << "+" << idDeltas[i] << "-->" << dbg;
-                putWord16(result, idRangeOffsetAddress, 0);
-            }
-            else
-            {
-                quint16 idRangeOffset = result.size() - idRangeOffsetAddress;
-                putWord16(result, idRangeOffsetAddress, idRangeOffset);
-
-                qDebug() << QChar(startCodes[i]) << "-" << QChar(endCodes[i]) << "/" << (endCodes[i]-startCodes[i]+1) << "@" << idRangeOffset << "+" << idDeltas[i];
-
-                uint startCode = startCodes[i];
-                uint segLength = (endCodes[i]-startCode+1);
-                for (uint offset = 0; offset < segLength; ++offset)
-                {
-                    quint16 glyph = cmap[startCode + offset];
-                    if (glyph != 0)
-                    {
-                        glyph -= idDeltas[i];
-                    }
-                    appendWord16(result, glyph);
-                }
-            }
-        };
-        
-        putWord16(result, startOfTable + ttf_cmap4_length, result.size() - startOfTable);
-        return result;
-     }
-    
-    
-    QList<uint> copyGlyphComponents(QByteArray& destGlyf, const QByteArray& srcGlyf, uint srcOffset,
-                                    QMap<uint,uint> newForOldGid, uint& nextFreeGid)
-    {
-        QList<uint> result;
-        
-        uint destStart = destGlyf.size();
-        destGlyf.resize(destStart + ttf_glyf_headerSize);
-        copy(destGlyf, destStart, srcGlyf, srcOffset, ttf_glyf_headerSize);
-        
-        uint pos = srcOffset + ttf_glyf_headerSize;
-        bool haveInstructions = false;
-        uint flags = 0;
-        do {
-            /* flags */
-            flags = word16(srcGlyf, pos);
-            pos += 2;
-            haveInstructions |= (flags & ttf_glyf_ComponentFlag_WE_HAVE_INSTRUCTIONS);
-            appendWord16(destGlyf, flags);
-            
-            /* glyphindex */
-            uint glyphIndex = word16(srcGlyf, pos);
-            pos += 2;
-            if (newForOldGid.contains(glyphIndex))
-            {
-                glyphIndex = newForOldGid[glyphIndex];
-            }
-            else
-            {
-                glyphIndex = nextFreeGid++;
-                result.append(glyphIndex);
-                newForOldGid[glyphIndex] = glyphIndex;
-            }
-            appendWord16(destGlyf, glyphIndex);
-            
-            /* args */
-            if ( flags & ttf_glyf_ComponentFlag_ARG_1_AND_2_ARE_WORDS) {
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // arg1
-                pos += 2;
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // arg2
-                pos += 2;
-            }
-            else {
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // arg1and2
-                pos += 2;
-            }
-            if ( flags & ttf_glyf_ComponentFlag_WE_HAVE_A_SCALE ) {
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // scale
-                pos += 2;
-            } else if ( flags & ttf_glyf_ComponentFlag_WE_HAVE_AN_X_AND_Y_SCALE ) {
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // xscale
-                pos += 2;
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // yscale
-                pos += 2;
-            } else if ( flags & ttf_glyf_ComponentFlag_WE_HAVE_A_TWO_BY_TWO ) {
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // xscale
-                pos += 2;
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // scale01
-                pos += 2;
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // scale10
-                pos += 2;
-                appendWord16(destGlyf, word16(srcGlyf, pos)); // yscale
-                pos += 2;
-            }
-        } while ( flags & ttf_glyf_ComponentFlag_MORE_COMPONENTS );
-            
-            
-
-        if (haveInstructions)
-        {
-            uint numInstr = word16(srcGlyf, pos);
-            appendWord16(destGlyf, numInstr);
-            pos += 2;
-            uint destPos = destGlyf.size();
-            destGlyf.resize(destPos + numInstr);
-            copy(destGlyf, destPos, srcGlyf, pos, numInstr);
-        }
-        
-        return result;
-    }
-    
-    
-    QList<uint> copyGlyph(QList<uint>& destLoca, QByteArray& destGlyf, uint destGid,
-                          const QList<uint>& srcLoca, const QByteArray& srcGlyf, uint srcGid,
-                          QMap<uint,uint>& newForOldGid, uint& nextFreeGid)
-    {
-        QList<uint> compositeElements;
-        uint glyphStart = srcLoca[srcGid];
-        uint glyphLength = srcLoca[srcGid+1] - glyphStart;
-        destLoca.append(destGlyf.size());
-        int i = 0;
-        if (glyphLength > 0)
-        {
-            uint nrOfContours = word16(srcGlyf, glyphStart);
-            if (nrOfContours > 0)
-            {
-                // simple glyph
-                uint destStart = destGlyf.size();
-                qDebug() << i++ << ":" << nrOfContours << "contours" << glyphStart << "-->" << destStart << "/" << glyphLength;
-                destGlyf.resize(destStart + glyphLength);
-                copy(destGlyf, destStart, srcGlyf, glyphStart, glyphLength);
-            }
-            else
-            {
-                compositeElements.append(copyGlyphComponents(destGlyf, srcGlyf, glyphStart, newForOldGid, nextFreeGid));
-                     qDebug() << i++ << ":" << srcGid << "composite glyph brought" << compositeElements.size() << "more glyphs";
-            }
-        }
-
-        return compositeElements;
-    }
-    
-    
-    QByteArray subsetFace(const QByteArray& ttf, QList<uint>& glyphs)
-    {
-        QMap<QByteArray,QByteArray> tables;
-        
-        
-//        qDebug() << "loca table:" << (void*) oldLoca[0] << (void*) oldLoca[1] << (void*) oldLoca[2] << (void*) oldLoca[3] << (void*) oldLoca[4] << (void*) oldLoca[5] << (void*) oldLoca[6] << (void*) oldLoca[7];
-        
-
-        QMap<uint,uint> newForOldGid;
-        if (glyphs.length() == 0)
-        {
-            tables["loca"] = getTable(ttf, "loca");
-            tables["glyf"] = getTable(ttf, "glyf");
-        }
-        else
-        {
-            QList<uint> oldLoca = readLoca(ttf);
-            const QByteArray oldGlyf = getTable(ttf, "glyf");
-
-            QList<quint32> newLoca;
-            QByteArray newGlyf;
-            glyphs.removeAll(0);
-            glyphs.prepend(0);
-            
-            uint nextFreeGid = glyphs.length();
-            for (int i = 0; i < glyphs.length(); ++i)
-            {
-                uint oldGid = glyphs[i];
-                newForOldGid[oldGid] = i;
-                glyphs.append(copyGlyph(newLoca, newGlyf, i,
-                                        oldLoca, oldGlyf, oldGid,
-                                        newForOldGid, nextFreeGid));
-            }
-            newLoca.append(newGlyf.length());
-            
-            tables["loca"] = writeLoca(newLoca, hasLongLocaFormat(ttf));
-            tables["glyf"] = newGlyf;
-        }
-        
-        
-        QMap<uint,uint> cmap = readCMap(ttf);
-        QMap<uint,uint>::iterator it;
-        uint firstChar = 0xFFFFFFFF;
-        uint lastChar = 0;
-        for (it = cmap.begin(); it != cmap.end(); ++it)
-        {
-            if (glyphs.length() > 0 && !glyphs.contains(it.value()))
-            {
-                it.value() = 0;
-            }
-            else if (it.value() != 0)
-            {
-                if (glyphs.length() > 0)
-                {
-                    qDebug() << "MAP" << QChar(it.key()) << it.value() << "-->" << newForOldGid[it.value()];
-                    it.value() = newForOldGid[it.value()];
-                }
-                if (it.key() < firstChar)
-                    firstChar = it.key();
-                else if (it.key() > lastChar)
-                    lastChar = it.key();
-            }
-        }
-        tables["cmap"] = writeCMap(cmap);
-
-        
-        QByteArray os2 = getTable(ttf, "OS/2");
-        if (os2.length() > ttf_os2_usLastCharIndex)
-        {
-            // TODO: adapt unicode ranges
-            putWord16(os2, ttf_os2_usFirstCharIndex, firstChar < 0xFFFF ? firstChar : 0xFFFF);
-            putWord16(os2, ttf_os2_usLastCharIndex, lastChar < 0xFFFF ? lastChar : 0xFFFF);
-            tables["OS/2"] = os2;
-        }
-        
-        if (glyphs.length() > 0)
-        {
-            QList<std::pair<qint16, quint16> > oldHmtx = readHmtx(ttf);
-            QList<std::pair<qint16, quint16> > newHmtx;
-            newHmtx.append(std::pair<qint16, quint16>(1234, 123));
-            for (int i = 1; i < glyphs.length(); ++i)
-                newHmtx.append(newHmtx[0]);
-            QMap<uint,uint>::const_iterator iter;
-            for (iter = newForOldGid.cbegin(); iter != newForOldGid.cend(); ++iter)
-            {
-                qDebug() << "hmtx" << iter.key() << " -> " << iter.value() << "=" << oldHmtx[iter.key()].first;
-                newHmtx[iter.value()] = oldHmtx[iter.key()];
-            }
-            tables["hmtx"] = writeHmtx(newHmtx);
-        }
-        else
-        {
-            tables["hmtx"] = getTable(ttf, "hmtx");
-        }
-        
-        QByteArray maxp = getTable(ttf, "maxp");
-        if (glyphs.length() > 0)
-        {
-            putWord16(maxp, ttf_maxp_numGlyphs, glyphs.length());
-        }
-        tables["maxp"] = maxp;
-        
-        QByteArray hhea = getTable(ttf, "hhea");
-        if (glyphs.length() > 0)
-        {
-            putWord16(hhea, ttf_hhea_numOfLongHorMetrics, glyphs.length());
-        }
-        tables["hhea"] = hhea;
-        
-        QByteArray post = getTable(ttf, "post");
-        if (word(post, ttf_post_format) != post_format30)
-        {
-            putWord(post, ttf_post_format, post_format30);
-            post.truncate(ttf_post_header_length);
-        }
-        tables["post"] = post;
-        
-        // TODO: kern table
-        
-        QByteArray name = getTable(ttf, "name");
-        if (name.length() > 0)
-            tables["name"] = name;
-        
-        QByteArray prep = getTable(ttf, "prep");
-        if (prep.length() > 0)
-            tables["prep"] = prep;
-        
-        QByteArray cvt = getTable(ttf, "cvt ");
-        if (cvt.length() > 0)
-            tables["cvt "] = cvt;
-
-        QByteArray fpgm = getTable(ttf, "fpgm");
-        if (fpgm.length() > 0)
-            tables["fpgm"] = fpgm;
-        
-
-        QByteArray head = getTable(ttf, "head");
-        putWord(head, ttf_head_checkSumAdjustment, 0);
-        tables["head"] = head;
-        
-
-        QByteArray font = createTableDir(tables.keys());
-        QMap<QByteArray,QByteArray>::iterator tableP;
-        for (tableP = tables.begin(); tableP != tables.end(); ++tableP)
-        {
-            writeTable(font, tableP.key(), tableP.value());
-        }
-        
-        uint checkSumAdjustment = 0xB1B0AFBA - calcTableChecksum(font);
-        uint headTable = getTableDirEntry(font, "head");
-        headTable = word(font, headTable + ttf_TableRecord_offset);
-        putWord(font, headTable + ttf_head_checkSumAdjustment, checkSumAdjustment);
-        
-        // done!
-        
-        return font;
-    }
-    
+
+
+	uint getTableDirEntry(const QByteArray& ttf, const QByteArray& ttfTag)
+	{
+		uint nTables = word16(ttf, ttf_numtables);
+		uint pos = ttf_TableRecords;
+		for (uint i=0; i < nTables; ++i)
+		{
+			if (ttfTag == tag(word(ttf, pos + ttf_TableRecord_tag)))
+			{
+				return pos;
+			}
+			pos += ttf_TableRecord_Size;
+		}
+		return 0;
+	}
+
+
+	const QByteArray getTable(const QByteArray& ttf, const QByteArray& ttfTag)
+	{
+		uint pos = getTableDirEntry(ttf, ttfTag);
+		if (pos > 0)
+		{
+			uint offset = word(ttf, pos + ttf_TableRecord_offset);
+			uint length = word(ttf, pos + ttf_TableRecord_length);
+			return QByteArray::fromRawData(ttf.constData() + offset, length);
+		}
+		else
+		{
+			return QByteArray();
+		}
+	}
+
+	QByteArray createTableDir(const QList<QByteArray>& tags)
+	{
+		QByteArray result;
+		uint numTables = tags.length();
+		uint tableRecordsSize = numTables * ttf_TableRecord_Size;
+		result.resize(ttf_TableRecords +  tableRecordsSize);
+		uint entrySelector = 0;
+		uint searchRange = ttf_TableRecord_Size;
+		while (2*searchRange < tableRecordsSize)
+		{
+			searchRange *= 2;
+			++entrySelector;
+		}
+		uint rangeShift = tableRecordsSize - searchRange;
+		
+		putWord(result, ttf_sfnt_version, 0x00010000);
+		putWord16(result, ttf_numtables, numTables);
+		putWord16(result, ttf_searchRange, searchRange);
+		putWord16(result, ttf_entrySelector, entrySelector);
+		putWord16(result, ttf_rangeShift, rangeShift);
+		for (uint i = 0; i < numTables; ++i)
+		{
+			copy(result, ttf_TableRecords + i*ttf_TableRecord_Size + ttf_TableRecord_tag, tags[i], 0, 4);
+			putWord(result, ttf_TableRecords + i*ttf_TableRecord_Size + ttf_TableRecord_checkSum, 0);
+			putWord(result, ttf_TableRecords + i*ttf_TableRecord_Size + ttf_TableRecord_offset, 0);
+			putWord(result, ttf_TableRecords + i*ttf_TableRecord_Size +ttf_TableRecord_length, 0);
+		}
+		return result;
+	}
+
+
+	quint32 calcTableChecksum(QByteArray& table)
+	{
+		quint32 Sum = 0L;
+		for (int pos = 0; pos < table.length(); pos += 4)
+			Sum += word(table, pos);
+		return Sum;
+	}
+
+
+	void writeTable(QByteArray& ttf, const QByteArray& tag, QByteArray& table)
+	{
+		qDebug() << "writing table" << tag << table.size() << "@" << ttf.size();
+		uint length = table.size();
+		while (table.size() & 0x3)
+			table.append('\0');
+		uint offset = ttf.size();
+		uint checksum = calcTableChecksum(table);
+		uint pos = getTableDirEntry(ttf, tag);
+		putWord(ttf, pos + ttf_TableRecord_checkSum, checksum);
+		putWord(ttf, pos + ttf_TableRecord_offset, offset);
+		putWord(ttf, pos + ttf_TableRecord_length, length);
+		ttf.append(table);
+	}
+
+
+	bool hasLongLocaFormat(const QByteArray& ttf)
+	{
+		const QByteArray head = getTable(ttf, "head");
+		uint idxToLocFormat = word16(head, ttf_head_indexToLocFormat);
+		qDebug() << "loca format:" << (void*)idxToLocFormat;
+		return idxToLocFormat == 1;
+	}
+
+
+	QList<quint32> readLoca(const QByteArray& ttf)
+	{
+		QList<quint32> result;
+		const QByteArray loca = getTable(ttf, "loca");
+		if (hasLongLocaFormat(ttf))
+		{
+			for (int i = 0; i < loca.length(); i+=4)
+			{
+				result.append(word(loca, i));
+			}
+		}
+		else
+		{
+			for (int i = 0; i < loca.length(); i+=2)
+			{
+				result.append(word16(loca, i) * 2);
+			}
+		}
+		return result;
+	}
+
+	const QByteArray writeLoca(const QList<uint>& loca, bool longFormat)
+	{
+		QByteArray result;
+		if (longFormat)
+		{
+			for(int i=0; i < loca.length(); ++i)
+				appendWord(result, loca[i]);
+		}
+		else
+		{
+			for(int i=0; i < loca.length(); ++i)
+				appendWord16(result, loca[i] / 2);
+		}
+		return result;
+	}
+
+
+	QList<std::pair<qint16,quint16> > readHmtx(const QByteArray& ttf)
+	{
+		QList<std::pair<qint16,quint16> > result;
+		const QByteArray hhea = getTable(ttf, "hhea");
+		const QByteArray hmtx = getTable(ttf, "hmtx");
+		uint endOfLongHorMetrics = 4 * word16(hhea, ttf_hhea_numOfLongHorMetrics);
+		qint16 advance;
+		quint16 leftSideBearing;
+		uint pos = 0;
+		while (pos < endOfLongHorMetrics)
+		{
+			advance = word16(hmtx, pos);
+			leftSideBearing = word16(hmtx, pos+2);
+			qDebug() << pos << "hmtx" << advance << leftSideBearing;
+			result.append(std::pair<qint16,quint16>(advance, leftSideBearing));
+			pos += 4;
+		}
+		while (pos < hmtx.length())
+		{
+			leftSideBearing = word16(hmtx, pos);
+			qDebug() << pos << "hmtx =" << advance << leftSideBearing;
+			result.append(std::pair<qint16,quint16>(advance, leftSideBearing));
+			pos += 2;
+		}
+		return result;
+	}
+
+
+	QByteArray writeHmtx(const QList<std::pair<qint16,quint16> >& longHorMetrics)
+	{
+		QByteArray result;
+		QList<std::pair<qint16,quint16> >::const_iterator it;
+		int i = 0;
+		for (it = longHorMetrics.cbegin(); it < longHorMetrics.cend(); ++it)
+		{
+			qDebug() << "hmtx" << i++ << it->first << it->second;
+			appendWord16(result, it->first);
+			appendWord16(result, it->second);
+		}
+		return result;
+	}
+
+
+	QMap<uint, uint> readCMap(const QByteArray& ttf)
+	{
+		QMap<uint,uint> result;
+		const QByteArray cmaps = getTable(ttf, "cmap");
+		
+		uint numSubtables = word16(cmaps, ttf_cmap_numberSubtables);
+		uint startOfUnicodeTable = 0;
+		uint format = 0;
+		uint pos = ttf_cmap_encodings;
+		for (int i = 0; i < numSubtables; ++i)
+		{
+			uint platform = word16(cmaps, pos + ttf_cmap_encoding_platformID);
+			uint encoding = word16(cmaps, pos + ttf_cmap_encoding_platformSpecificID);
+			uint offset = word(cmaps, pos + ttf_cmap_encoding_offset);
+			format = word16(cmaps, offset + ttf_cmapx_format);
+			pos += ttf_cmap_encoding_Size;
+			
+			if (format < 4 || format > 12)
+				continue;
+			if (platform == 0 || (platform == 3 && encoding == 1))
+			{
+				startOfUnicodeTable = offset;
+				break;
+			}
+			format = 1; // no such format
+		}
+		qDebug() << "reading cmap format" << format;
+		switch(format)
+		{
+			case 4:
+			{
+				uint segCount2 = word16(cmaps, startOfUnicodeTable + ttf_cmap4_segCountX2);
+				uint endCodes = startOfUnicodeTable + ttf_cmap4_EndCodes;
+				uint startCodes = endCodes + segCount2 + ttf_cmap4_StartCodes_EndCodes;
+				uint idDeltas = startCodes + segCount2 + ttf_cmap4_IdDeltas_StartCodes;
+				uint idRangeOffsets = idDeltas + segCount2 + ttf_cmap4_IdRangeOffsets_IdDeltas;
+				//uint glyphIndexArray = idRangeOffsets + segCount2 + ttf_cmap4_GlyphIds_IdRangeOffsets;
+				
+				for (int seg = 0; seg < segCount2; seg+=2)
+				{
+					uint start = word16(cmaps, startCodes + seg);
+					uint end = word16(cmaps, endCodes + seg);
+					uint idDelta = word16(cmaps, idDeltas + seg);
+					uint idRangeOffset = word16(cmaps, idRangeOffsets + seg);
+					for (uint c = start; c <= end; ++c)
+					{
+						quint16 glyph;
+						if (idRangeOffset > 0)
+						{
+							uint glyphIndexAdress = idRangeOffset + 2*(c-start) + (idRangeOffsets + seg);
+							glyph = word16(cmaps, glyphIndexAdress);
+							if (glyph != 0)
+								glyph += idDelta;
+						}
+						else
+						{
+							glyph = c + idDelta;
+						}
+						if (!result.contains(c))
+						{
+							// search would always find the one in the segment with the lower endcode, i.e. earlier segment
+							if (c < 256 || glyph == 0) qDebug() << "(" << QChar(c) << "," << glyph << ")";
+							result[c] = glyph;
+						}
+						else
+						{
+							// nothing to do. No idea if fonts with overlapping cmap4 segments exist, though.
+						}
+					}
+				}
+				break;
+			}
+			case 6:
+			{
+				uint firstCode = word16(cmaps, startOfUnicodeTable + ttf_cmap6_firstCode);
+				uint count = word16(cmaps, startOfUnicodeTable + ttf_cmap6_entryCount);
+				pos = word16(cmaps, startOfUnicodeTable + ttf_cmap6_glyphIndexArray);
+				for (int i = 0; i < count; ++i)
+				{
+					result[firstCode + i] = word16(cmaps, pos);
+					pos += 2;
+				}
+				break;
+			}
+			case 12:
+			{
+				uint nGroups = word(cmaps, startOfUnicodeTable + ttf_cmap12_nGroups);
+				pos = startOfUnicodeTable + ttf_cmap12_Groups;
+				for (uint grp = 0; grp < nGroups; ++grp)
+				{
+					uint start = word(cmaps, pos + ttf_cmap12_Group_startCharCode);
+					uint end = word(cmaps, pos + ttf_cmap12_Group_endCharCode);
+					uint gid = word(cmaps, pos + ttf_cmap12_Group_startGlyphCode);
+					for (uint c = start; c <= end; ++c)
+					{
+						result[c] = gid;
+						++gid;
+					}
+					pos += ttf_cmap12_Group_Size;
+				}
+				break;
+			}
+			default:
+			{
+				qDebug() << "unsupported cmap format" << format;
+				break;
+			}
+		}
+		return result;
+	}
+
+
+
+	const QByteArray writeCMap(const QMap<uint, uint>& cmap)
+	{
+		// we always write only one table: platform=3(MS), encoding=1(Unicode 16bit)
+		QByteArray result;
+		appendWord16(result, 0); // version
+		appendWord16(result, 1); // number of subtables
+		appendWord16(result, 3); // platformID Microsoft
+		appendWord16(result, 1); // encodingID UnicodeBMP
+		appendWord(result, result.size() + 4); // offset
+		
+		// find the segments
+		
+		QList<uint> chars;
+		QMap<uint, uint>::ConstIterator cit;
+		qDebug() << "writing cmap";
+		for(cit = cmap.cbegin(); cit != cmap.cend(); ++cit)
+		{
+			uint ch = cit.key();
+			if (!QChar::requiresSurrogates(ch) && cit.value() != 0)
+			{
+				qDebug() << "(" << QChar(cit.key()) << "," << cit.value() << ")";
+				chars.append(ch);
+			}
+//			qDebug() << QChar(ch) << QChar::requiresSurrogates(ch) << cit.value();
+		}
+		std::sort(chars.begin(), chars.end());
+		
+		QList<quint16> startCodes;
+		QList<quint16> endCodes;
+		QList<quint16> idDeltas;
+		QList<quint16> rangeOffsets;
+		
+		uint pos = 0;
+		do {
+			quint16 start = chars[pos];
+			quint16 delta = cmap[start] - start;
+			quint16 rangeOffset = 0;
+			quint16 end = start;
+			quint16 next;
+			++pos;
+			while (pos < chars.length() && (next = chars[pos]) == end+1)
+			{
+				end = next;
+				if (delta != (quint16)(cmap[chars[pos]] - next))
+				{
+					rangeOffset = 1; // will be changed later
+				}
+				++pos;
+			}
+			startCodes.append(start);
+			endCodes.append(end);
+			idDeltas.append(delta);
+			rangeOffsets.append(rangeOffset);
+		}
+		while(pos < chars.length());
+		
+		startCodes.append(0xFFFF);
+		endCodes.append(0xFFFF);
+		idDeltas.append(1); // makes gid 0
+		rangeOffsets.append(0);
+		
+		// write the tables
+		
+		uint startOfTable = result.size();
+		result.resize(startOfTable + ttf_cmap4_EndCodes);
+
+		uint segCount = endCodes.length();
+		uint segCountX2 = 2 * segCount;
+		uint entrySelector = 0;
+		uint searchRange = 2;
+		while (searchRange <= segCount)
+		{
+			++entrySelector;
+			searchRange *= 2;
+		}
+		putWord16(result, startOfTable + ttf_cmapx_format, 4);
+		/* ttf_cmap4_length is set later */
+		putWord16(result, startOfTable + ttf_cmap4_language, 0);
+		putWord16(result, startOfTable + ttf_cmap4_segCountX2, segCountX2);
+		putWord16(result, startOfTable + ttf_cmap4_searchRange, searchRange);
+		putWord16(result, startOfTable + ttf_cmap4_entrySelector, entrySelector);
+		putWord16(result, startOfTable + ttf_cmap4_rangeShift, segCountX2 - searchRange);
+		
+		for (uint i = 0; i < segCount; ++i)
+		{
+			appendWord16(result, endCodes[i]);
+		};
+		appendWord16(result, 0); // reservedPad
+		
+		for (uint i = 0; i < segCount; ++i)
+		{
+			appendWord16(result, startCodes[i]);
+		};
+		for (uint i = 0; i < segCount; ++i)
+		{
+			appendWord16(result, idDeltas[i]);
+		};
+		
+		
+		uint startOfIdRangeOffsetTable = result.size();
+		uint startOfGlyphIndexArray = startOfIdRangeOffsetTable + segCountX2;
+		result.resize(startOfGlyphIndexArray);
+		
+		for (uint i = 0; i < segCount; ++i)
+		{
+			uint idRangeOffsetAddress = startOfIdRangeOffsetTable + 2*i;
+			if (rangeOffsets[i] == 0)
+			{
+				quint16 dbg = startCodes[i] + idDeltas[i];
+				qDebug() << QChar(startCodes[i]) << "-" << QChar(endCodes[i]) << "/" << (endCodes[i]-startCodes[i]+1) << "+" << idDeltas[i] << "-->" << dbg;
+				putWord16(result, idRangeOffsetAddress, 0);
+			}
+			else
+			{
+				quint16 idRangeOffset = result.size() - idRangeOffsetAddress;
+				putWord16(result, idRangeOffsetAddress, idRangeOffset);
+
+				qDebug() << QChar(startCodes[i]) << "-" << QChar(endCodes[i]) << "/" << (endCodes[i]-startCodes[i]+1) << "@" << idRangeOffset << "+" << idDeltas[i];
+
+				uint startCode = startCodes[i];
+				uint segLength = (endCodes[i]-startCode+1);
+				for (uint offset = 0; offset < segLength; ++offset)
+				{
+					quint16 glyph = cmap[startCode + offset];
+					if (glyph != 0)
+					{
+						glyph -= idDeltas[i];
+					}
+					appendWord16(result, glyph);
+				}
+			}
+		};
+		
+		putWord16(result, startOfTable + ttf_cmap4_length, result.size() - startOfTable);
+		return result;
+	 }
+	
+	
+	QList<uint> copyGlyphComponents(QByteArray& destGlyf, const QByteArray& srcGlyf, uint srcOffset,
+	                                QMap<uint,uint> newForOldGid, uint& nextFreeGid)
+	{
+		QList<uint> result;
+		
+		uint destStart = destGlyf.size();
+		destGlyf.resize(destStart + ttf_glyf_headerSize);
+		copy(destGlyf, destStart, srcGlyf, srcOffset, ttf_glyf_headerSize);
+		
+		uint pos = srcOffset + ttf_glyf_headerSize;
+		bool haveInstructions = false;
+		uint flags = 0;
+		do {
+			/* flags */
+			flags = word16(srcGlyf, pos);
+			pos += 2;
+			haveInstructions |= (flags & ttf_glyf_ComponentFlag_WE_HAVE_INSTRUCTIONS);
+			appendWord16(destGlyf, flags);
+			
+			/* glyphindex */
+			uint glyphIndex = word16(srcGlyf, pos);
+			pos += 2;
+			if (newForOldGid.contains(glyphIndex))
+			{
+				glyphIndex = newForOldGid[glyphIndex];
+			}
+			else
+			{
+				glyphIndex = nextFreeGid++;
+				result.append(glyphIndex);
+				newForOldGid[glyphIndex] = glyphIndex;
+			}
+			appendWord16(destGlyf, glyphIndex);
+			
+			/* args */
+			if ( flags & ttf_glyf_ComponentFlag_ARG_1_AND_2_ARE_WORDS) {
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // arg1
+				pos += 2;
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // arg2
+				pos += 2;
+			}
+			else {
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // arg1and2
+				pos += 2;
+			}
+			if ( flags & ttf_glyf_ComponentFlag_WE_HAVE_A_SCALE ) {
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // scale
+				pos += 2;
+			} else if ( flags & ttf_glyf_ComponentFlag_WE_HAVE_AN_X_AND_Y_SCALE ) {
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // xscale
+				pos += 2;
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // yscale
+				pos += 2;
+			} else if ( flags & ttf_glyf_ComponentFlag_WE_HAVE_A_TWO_BY_TWO ) {
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // xscale
+				pos += 2;
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // scale01
+				pos += 2;
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // scale10
+				pos += 2;
+				appendWord16(destGlyf, word16(srcGlyf, pos)); // yscale
+				pos += 2;
+			}
+		} while ( flags & ttf_glyf_ComponentFlag_MORE_COMPONENTS );
+			
+			
+
+		if (haveInstructions)
+		{
+			uint numInstr = word16(srcGlyf, pos);
+			appendWord16(destGlyf, numInstr);
+			pos += 2;
+			uint destPos = destGlyf.size();
+			destGlyf.resize(destPos + numInstr);
+			copy(destGlyf, destPos, srcGlyf, pos, numInstr);
+		}
+		
+		return result;
+	}
+	
+
+	QList<uint> copyGlyph(QList<uint>& destLoca, QByteArray& destGlyf, uint destGid,
+	                      const QList<uint>& srcLoca, const QByteArray& srcGlyf, uint srcGid,
+	                      QMap<uint,uint>& newForOldGid, uint& nextFreeGid)
+	{
+		QList<uint> compositeElements;
+		uint glyphStart = srcLoca[srcGid];
+		uint glyphLength = srcLoca[srcGid+1] - glyphStart;
+		destLoca.append(destGlyf.size());
+		int i = 0;
+		if (glyphLength > 0)
+		{
+			uint nrOfContours = word16(srcGlyf, glyphStart);
+			if (nrOfContours > 0)
+			{
+				// simple glyph
+				uint destStart = destGlyf.size();
+				qDebug() << i++ << ":" << nrOfContours << "contours" << glyphStart << "-->" << destStart << "/" << glyphLength;
+				destGlyf.resize(destStart + glyphLength);
+				copy(destGlyf, destStart, srcGlyf, glyphStart, glyphLength);
+			}
+			else
+			{
+				compositeElements.append(copyGlyphComponents(destGlyf, srcGlyf, glyphStart, newForOldGid, nextFreeGid));
+					 qDebug() << i++ << ":" << srcGid << "composite glyph brought" << compositeElements.size() << "more glyphs";
+			}
+		}
+
+		return compositeElements;
+	}
+	
+	
+	QByteArray subsetFace(const QByteArray& ttf, QList<uint>& glyphs)
+	{
+		QMap<QByteArray,QByteArray> tables;
+		
+		
+//		qDebug() << "loca table:" << (void*) oldLoca[0] << (void*) oldLoca[1] << (void*) oldLoca[2] << (void*) oldLoca[3] << (void*) oldLoca[4] << (void*) oldLoca[5] << (void*) oldLoca[6] << (void*) oldLoca[7];
+		
+
+		QMap<uint,uint> newForOldGid;
+		if (glyphs.length() == 0)
+		{
+			tables["loca"] = getTable(ttf, "loca");
+			tables["glyf"] = getTable(ttf, "glyf");
+		}
+		else
+		{
+			QList<uint> oldLoca = readLoca(ttf);
+			const QByteArray oldGlyf = getTable(ttf, "glyf");
+
+			QList<quint32> newLoca;
+			QByteArray newGlyf;
+			glyphs.removeAll(0);
+			glyphs.prepend(0);
+			
+			uint nextFreeGid = glyphs.length();
+			for (int i = 0; i < glyphs.length(); ++i)
+			{
+				uint oldGid = glyphs[i];
+				newForOldGid[oldGid] = i;
+				glyphs.append(copyGlyph(newLoca, newGlyf, i,
+				                        oldLoca, oldGlyf, oldGid,
+				                        newForOldGid, nextFreeGid));
+			}
+			newLoca.append(newGlyf.length());
+			
+			tables["loca"] = writeLoca(newLoca, hasLongLocaFormat(ttf));
+			tables["glyf"] = newGlyf;
+		}
+		
+		
+		QMap<uint,uint> cmap = readCMap(ttf);
+		QMap<uint,uint>::iterator it;
+		uint firstChar = 0xFFFFFFFF;
+		uint lastChar = 0;
+		for (it = cmap.begin(); it != cmap.end(); ++it)
+		{
+			if (glyphs.length() > 0 && !glyphs.contains(it.value()))
+			{
+				it.value() = 0;
+			}
+			else if (it.value() != 0)
+			{
+				if (glyphs.length() > 0)
+				{
+					qDebug() << "MAP" << QChar(it.key()) << it.value() << "-->" << newForOldGid[it.value()];
+					it.value() = newForOldGid[it.value()];
+				}
+				if (it.key() < firstChar)
+					firstChar = it.key();
+				else if (it.key() > lastChar)
+					lastChar = it.key();
+			}
+		}
+		tables["cmap"] = writeCMap(cmap);
+
+		
+		QByteArray os2 = getTable(ttf, "OS/2");
+		if (os2.length() > ttf_os2_usLastCharIndex)
+		{
+			// TODO: adapt unicode ranges
+			putWord16(os2, ttf_os2_usFirstCharIndex, firstChar < 0xFFFF ? firstChar : 0xFFFF);
+			putWord16(os2, ttf_os2_usLastCharIndex, lastChar < 0xFFFF ? lastChar : 0xFFFF);
+			tables["OS/2"] = os2;
+		}
+		
+		if (glyphs.length() > 0)
+		{
+			QList<std::pair<qint16, quint16> > oldHmtx = readHmtx(ttf);
+			QList<std::pair<qint16, quint16> > newHmtx;
+			newHmtx.append(std::pair<qint16, quint16>(1234, 123));
+			for (int i = 1; i < glyphs.length(); ++i)
+				newHmtx.append(newHmtx[0]);
+			QMap<uint,uint>::const_iterator iter;
+			for (iter = newForOldGid.cbegin(); iter != newForOldGid.cend(); ++iter)
+			{
+				qDebug() << "hmtx" << iter.key() << " -> " << iter.value() << "=" << oldHmtx[iter.key()].first;
+				newHmtx[iter.value()] = oldHmtx[iter.key()];
+			}
+			tables["hmtx"] = writeHmtx(newHmtx);
+		}
+		else
+		{
+			tables["hmtx"] = getTable(ttf, "hmtx");
+		}
+		
+		QByteArray maxp = getTable(ttf, "maxp");
+		if (glyphs.length() > 0)
+		{
+			putWord16(maxp, ttf_maxp_numGlyphs, glyphs.length());
+		}
+		tables["maxp"] = maxp;
+		
+		QByteArray hhea = getTable(ttf, "hhea");
+		if (glyphs.length() > 0)
+		{
+			putWord16(hhea, ttf_hhea_numOfLongHorMetrics, glyphs.length());
+		}
+		tables["hhea"] = hhea;
+		
+		QByteArray post = getTable(ttf, "post");
+		if (word(post, ttf_post_format) != post_format30)
+		{
+			putWord(post, ttf_post_format, post_format30);
+			post.truncate(ttf_post_header_length);
+		}
+		tables["post"] = post;
+		
+		// TODO: kern table
+		
+		QByteArray name = getTable(ttf, "name");
+		if (name.length() > 0)
+			tables["name"] = name;
+		
+		QByteArray prep = getTable(ttf, "prep");
+		if (prep.length() > 0)
+			tables["prep"] = prep;
+		
+		QByteArray cvt = getTable(ttf, "cvt ");
+		if (cvt.length() > 0)
+			tables["cvt "] = cvt;
+
+		QByteArray fpgm = getTable(ttf, "fpgm");
+		if (fpgm.length() > 0)
+			tables["fpgm"] = fpgm;
+		
+
+		QByteArray head = getTable(ttf, "head");
+		putWord(head, ttf_head_checkSumAdjustment, 0);
+		tables["head"] = head;
+		
+
+		QByteArray font = createTableDir(tables.keys());
+		QMap<QByteArray,QByteArray>::iterator tableP;
+		for (tableP = tables.begin(); tableP != tables.end(); ++tableP)
+		{
+			writeTable(font, tableP.key(), tableP.value());
+		}
+		
+		uint checkSumAdjustment = 0xB1B0AFBA - calcTableChecksum(font);
+		uint headTable = getTableDirEntry(font, "head");
+		headTable = word(font, headTable + ttf_TableRecord_offset);
+		putWord(font, headTable + ttf_head_checkSumAdjustment, checkSumAdjustment);
+		
+		// done!
+		
+		return font;
+	}
+	
 } // namespace sfnt
 
 
 /// For GPOS lookups
 enum TTF_GPOS_ValueFormat
 {
-    XPlacement = 0x0001,
-    YPlacement = 0x0002,
-    XAdvance = 0x0004,
-    YAdvance = 0x0008,
-    XPlaDevice =0x0010,
-    YPlaDevice =0x0020,
-    XAdvDevice =0x0040,
-    YAdvDevice =0x0080
+	XPlacement = 0x0001,
+	YPlacement = 0x0002,
+	XAdvance = 0x0004,
+	YAdvance = 0x0008,
+	XPlaDevice =0x0010,
+	YPlaDevice =0x0020,
+	XAdvDevice =0x0040,
+	YAdvDevice =0x0080
 };
 
 
 
 KernFeature::KernFeature ( FT_Face face ) : m_valid ( true )
 {
-    FontName = QString (face->family_name) + " " + QString (face->style_name);
-    // 	qDebug() <<"KF"<<FontName;
-    // 	QTime t;
-    // 	t.start();
-    FT_ULong length = 0;
-    if ( !FT_Load_Sfnt_Table ( face, TTAG_GPOS , 0, NULL, &length ) )
-    {
-        // 		qDebug() <<"\t"<<"GPOS table len"<<length;
-        if ( length > 32 )
-        {
-            GPOSTableRaw.resize ( length );
-            FT_Load_Sfnt_Table ( face, TTAG_GPOS, 0, reinterpret_cast<FT_Byte*> ( GPOSTableRaw.data() ), &length );
-            
-            makeCoverage();
-        }
-        else
-            m_valid = false;
-        
-        GPOSTableRaw.clear();
-        //		coverages.clear();
-    }
-    else
-        m_valid = false;
-    
-    if (!m_valid)
-        pairs.clear();
-    // 	qDebug() <<"\t"<<m_valid;
-    // 	qDebug() <<"\t"<<t.elapsed();
+	FontName = QString (face->family_name) + " " + QString (face->style_name);
+	// 	qDebug() <<"KF"<<FontName;
+	// 	QTime t;
+	// 	t.start();
+	FT_ULong length = 0;
+	if ( !FT_Load_Sfnt_Table ( face, TTAG_GPOS , 0, NULL, &length ) )
+	{
+		// 		qDebug() <<"\t"<<"GPOS table len"<<length;
+		if ( length > 32 )
+		{
+			GPOSTableRaw.resize ( length );
+			FT_Load_Sfnt_Table ( face, TTAG_GPOS, 0, reinterpret_cast<FT_Byte*> ( GPOSTableRaw.data() ), &length );
+			
+			makeCoverage();
+		}
+		else
+			m_valid = false;
+		
+		GPOSTableRaw.clear();
+		//		coverages.clear();
+	}
+	else
+		m_valid = false;
+	
+	if (!m_valid)
+		pairs.clear();
+	// 	qDebug() <<"\t"<<m_valid;
+	// 	qDebug() <<"\t"<<t.elapsed();
 }
 
 KernFeature::KernFeature ( const KernFeature & kf )
 {
-    m_valid = kf.m_valid;
-    if ( m_valid )
-        pairs = kf.pairs;
+	m_valid = kf.m_valid;
+	if ( m_valid )
+		pairs = kf.pairs;
 }
 
 
@@ -1255,388 +1256,388 @@
 
 double KernFeature::getPairValue ( unsigned int glyph1, unsigned int glyph2 ) const
 {
-    if (!m_valid)
-        return 0.0;
-    
-    if (pairs.contains(glyph1) &&
-        pairs[glyph1].contains(glyph2))
-    {
-        return pairs[glyph1][glyph2];
-    }
-    
-    //qDebug()<<"Search in classes";
-    foreach (const quint16& coverageId, coverages.keys())
-    {
-        // for each pairpos table, coverage lists covered _first_ (left) glyph
-        if (!coverages[coverageId].contains(glyph1))
-            continue;
-        
-        foreach(const quint16& classDefOffset, classGlyphFirst[coverageId].keys())
-        {
-            const ClassDefTable& cdt(classGlyphFirst[coverageId][classDefOffset]);
-            foreach(const quint16& classIndex, cdt.keys())
-            {
-                const QList<quint16>& gl(cdt[classIndex]);
-                if (!gl.contains(glyph1))
-                    continue;
-                //qDebug()<<"Found G1"<<glyph1<<"in Class"<<classIndex<<"at pos"<<gl.indexOf(glyph1);
-                // Now we got the index of the first glyph class, see if glyph2 is in one of the left glyphs classes attached to this subtable.
-                foreach(const quint16& classDefOffset2, classGlyphSecond[coverageId].keys())
-                {
-                    const ClassDefTable& cdt2(classGlyphSecond[coverageId][classDefOffset2]);
-                    foreach(const quint16& classIndex2, cdt2.keys())
-                    {
-                        const QList<quint16>& gl2(cdt2[classIndex2]);
-                        if (gl2.contains(glyph2))
-                        {
-                            //qDebug()<<"Found G2"<<glyph2<<"in Class"<<classIndex2<<"at pos"<<gl2.indexOf(glyph2);
-                            
-                            double v(classValue[coverageId][classIndex][classIndex2]);
-                            // Cache this pair into "pairs" map.
-                            pairs[glyph1][glyph2] = v;
-                            return v;
-                        }
-                    }
-                }
-            }
-        }
-    }
-    return 0.0;
+	if (!m_valid)
+		return 0.0;
+	
+	if (pairs.contains(glyph1) &&
+		pairs[glyph1].contains(glyph2))
+	{
+		return pairs[glyph1][glyph2];
+	}
+	
+	//qDebug()<<"Search in classes";
+	foreach (const quint16& coverageId, coverages.keys())
+	{
+		// for each pairpos table, coverage lists covered _first_ (left) glyph
+		if (!coverages[coverageId].contains(glyph1))
+			continue;
+		
+		foreach(const quint16& classDefOffset, classGlyphFirst[coverageId].keys())
+		{
+			const ClassDefTable& cdt(classGlyphFirst[coverageId][classDefOffset]);
+			foreach(const quint16& classIndex, cdt.keys())
+			{
+				const QList<quint16>& gl(cdt[classIndex]);
+				if (!gl.contains(glyph1))
+					continue;
+				//qDebug()<<"Found G1"<<glyph1<<"in Class"<<classIndex<<"at pos"<<gl.indexOf(glyph1);
+				// Now we got the index of the first glyph class, see if glyph2 is in one of the left glyphs classes attached to this subtable.
+				foreach(const quint16& classDefOffset2, classGlyphSecond[coverageId].keys())
+				{
+					const ClassDefTable& cdt2(classGlyphSecond[coverageId][classDefOffset2]);
+					foreach(const quint16& classIndex2, cdt2.keys())
+					{
+						const QList<quint16>& gl2(cdt2[classIndex2]);
+						if (gl2.contains(glyph2))
+						{
+							//qDebug()<<"Found G2"<<glyph2<<"in Class"<<classIndex2<<"at pos"<<gl2.indexOf(glyph2);
+							
+							double v(classValue[coverageId][classIndex][classIndex2]);
+							// Cache this pair into "pairs" map.
+							pairs[glyph1][glyph2] = v;
+							return v;
+						}
+					}
+				}
+			}
+		}
+	}
+	return 0.0;
 }
 
 void KernFeature::makeCoverage()
 {
-    if ( GPOSTableRaw.isEmpty() )
-        return;
+	if ( GPOSTableRaw.isEmpty() )
+		return;
+	
+	quint16 FeatureList_Offset= toUint16 ( 6 );
+	quint16 LookupList_Offset = toUint16 ( 8 );
+	
+	// Find the offsets of the kern feature tables
+	quint16 FeatureCount = toUint16 ( FeatureList_Offset );
+	QList<quint16> FeatureKern_Offset;
+	for ( quint16 FeatureRecord ( 0 ); FeatureRecord < FeatureCount; ++ FeatureRecord )
+	{
+		int rawIdx ( FeatureList_Offset + 2 + ( 6 * FeatureRecord ) );
+		quint32 tag ( FT_MAKE_TAG ( GPOSTableRaw.at ( rawIdx ),
+		                           GPOSTableRaw.at ( rawIdx + 1 ),
+		                           GPOSTableRaw.at ( rawIdx + 2 ),
+		                           GPOSTableRaw.at ( rawIdx + 3 ) ) );
+		if ( tag == TTAG_kern )
+		{
+			FeatureKern_Offset << ( toUint16 ( rawIdx + 4 ) + FeatureList_Offset );
+		}
+	}
     
-    quint16 FeatureList_Offset= toUint16 ( 6 );
-    quint16 LookupList_Offset = toUint16 ( 8 );
-    
-    // Find the offsets of the kern feature tables
-    quint16 FeatureCount = toUint16 ( FeatureList_Offset );
-    QList<quint16> FeatureKern_Offset;
-    for ( quint16 FeatureRecord ( 0 ); FeatureRecord < FeatureCount; ++ FeatureRecord )
-    {
-        int rawIdx ( FeatureList_Offset + 2 + ( 6 * FeatureRecord ) );
-        quint32 tag ( FT_MAKE_TAG ( GPOSTableRaw.at ( rawIdx ),
-                                   GPOSTableRaw.at ( rawIdx + 1 ),
-                                   GPOSTableRaw.at ( rawIdx + 2 ),
-                                   GPOSTableRaw.at ( rawIdx + 3 ) ) );
-        if ( tag == TTAG_kern )
-        {
-            FeatureKern_Offset << ( toUint16 ( rawIdx + 4 ) + FeatureList_Offset );
-        }
-    }
-    
-    // Extract indices of lookups for feature kern
-    QList<quint16> LookupListIndex;
-    foreach ( quint16 kern, FeatureKern_Offset )
-    {
-        quint16 LookupCount ( toUint16 ( kern + 2 ) );
-        for ( int llio ( 0 ) ; llio < LookupCount; ++llio )
-        {
-            quint16 Idx ( toUint16 ( kern + 4 + ( llio * 2 ) ) );
-            if ( !LookupListIndex.contains ( Idx ) )
-            {
-                LookupListIndex <<Idx ;
-            }
-        }
-    }
-    
-    
-    // Extract offsets of lookup tables for feature kern
-    QList<quint16> LookupTables;
-    QList<quint16> PairAdjustmentSubTables;
-    for ( int i ( 0 ); i < LookupListIndex.count(); ++i )
-    {
-        int rawIdx ( LookupList_Offset + 2 + ( LookupListIndex[i] * 2 ) );
-        quint16 Lookup ( toUint16 ( rawIdx )  + LookupList_Offset );
-        quint16 SubTableCount ( toUint16 ( Lookup + 4 ) );
-        for ( int stIdx ( 0 ); stIdx < SubTableCount; ++ stIdx )
-        {
-            quint16 SubTable ( toUint16 ( Lookup + 6 + ( 2 * stIdx ) ) + Lookup );
-            
-            // 			quint16 PosFormat ( toUint16 ( SubTable ) );
-            quint16 Coverage_Offset ( toUint16 ( SubTable + 2 ) + SubTable );
-            quint16 CoverageFormat ( toUint16 ( Coverage_Offset ) );
-            
-            if ( 1 == CoverageFormat ) // glyph indices based
-            {
-                quint16 GlyphCount ( toUint16 ( Coverage_Offset + 2 ) );
-                quint16 GlyphID ( Coverage_Offset + 4 );
-                if (GlyphCount == 0) continue;
-                
-                for ( unsigned int gl ( 0 ); gl < GlyphCount; ++gl )
-                {
-                    coverages[SubTable] << toUint16 ( GlyphID + ( gl * 2 ) );
-                }
-            }
-            else if ( 2 == CoverageFormat ) // Coverage Format2 => ranges based
-            {
-                quint16 RangeCount ( toUint16 ( Coverage_Offset + 2 ) );
-                if (RangeCount == 0) continue;
-                
-                // 				int gl_base ( 0 );
-                for ( int r ( 0 ); r < RangeCount; ++r )
-                {
-                    quint16 rBase ( Coverage_Offset + 4 + ( r * 6 ) );
-                    quint16 Start ( toUint16 ( rBase ) );
-                    quint16 End ( toUint16 ( rBase + 2 ) );
-                    // 					quint16 StartCoverageIndex ( toUint16 ( rBase + 4 ) );
-                    // #9842 : for some font such as Gabriola Regular
-                    // the range maybe be specified in reverse order
-                    if (Start <= End)
-                    {
-                        for ( unsigned int gl ( Start ); gl <= End; ++gl )
-                            coverages[SubTable]  << gl;
-                    }
-                    else
-                    {
-                        for ( int gl ( Start ); gl >= (int) End; --gl )
-                            coverages[SubTable]  << gl;
-                    }
-                }
-            }
-            else
-            {
-                //				qDebug() <<"Unknow Coverage Format:"<<CoverageFormat;
-                continue;
-            }
-            
-            makePairs ( SubTable );
-        }
-        
-    }
-    
-    
+	// Extract indices of lookups for feature kern
+	QList<quint16> LookupListIndex;
+	foreach ( quint16 kern, FeatureKern_Offset )
+	{
+		quint16 LookupCount ( toUint16 ( kern + 2 ) );
+		for ( int llio ( 0 ) ; llio < LookupCount; ++llio )
+		{
+			quint16 Idx ( toUint16 ( kern + 4 + ( llio * 2 ) ) );
+			if ( !LookupListIndex.contains ( Idx ) )
+			{
+				LookupListIndex <<Idx ;
+			}
+		}
+	}
+	
+	
+	// Extract offsets of lookup tables for feature kern
+	QList<quint16> LookupTables;
+	QList<quint16> PairAdjustmentSubTables;
+	for ( int i ( 0 ); i < LookupListIndex.count(); ++i )
+	{
+		int rawIdx ( LookupList_Offset + 2 + ( LookupListIndex[i] * 2 ) );
+		quint16 Lookup ( toUint16 ( rawIdx )  + LookupList_Offset );
+		quint16 SubTableCount ( toUint16 ( Lookup + 4 ) );
+		for ( int stIdx ( 0 ); stIdx < SubTableCount; ++ stIdx )
+		{
+			quint16 SubTable ( toUint16 ( Lookup + 6 + ( 2 * stIdx ) ) + Lookup );
+			
+			// 			quint16 PosFormat ( toUint16 ( SubTable ) );
+			quint16 Coverage_Offset ( toUint16 ( SubTable + 2 ) + SubTable );
+			quint16 CoverageFormat ( toUint16 ( Coverage_Offset ) );
+			
+			if ( 1 == CoverageFormat ) // glyph indices based
+			{
+				quint16 GlyphCount ( toUint16 ( Coverage_Offset + 2 ) );
+				quint16 GlyphID ( Coverage_Offset + 4 );
+				if (GlyphCount == 0) continue;
+				
+				for ( unsigned int gl ( 0 ); gl < GlyphCount; ++gl )
+				{
+					coverages[SubTable] << toUint16 ( GlyphID + ( gl * 2 ) );
+				}
+			}
+			else if ( 2 == CoverageFormat ) // Coverage Format2 => ranges based
+			{
+				quint16 RangeCount ( toUint16 ( Coverage_Offset + 2 ) );
+				if (RangeCount == 0) continue;
+				
+				// 				int gl_base ( 0 );
+				for ( int r ( 0 ); r < RangeCount; ++r )
+				{
+					quint16 rBase ( Coverage_Offset + 4 + ( r * 6 ) );
+					quint16 Start ( toUint16 ( rBase ) );
+					quint16 End ( toUint16 ( rBase + 2 ) );
+					// 					quint16 StartCoverageIndex ( toUint16 ( rBase + 4 ) );
+					// #9842 : for some font such as Gabriola Regular
+					// the range maybe be specified in reverse order
+					if (Start <= End)
+					{
+						for ( unsigned int gl ( Start ); gl <= End; ++gl )
+							coverages[SubTable]  << gl;
+					}
+					else
+					{
+						for ( int gl ( Start ); gl >= (int) End; --gl )
+							coverages[SubTable]  << gl;
+					}
+				}
+			}
+			else
+			{
+				//				qDebug() <<"Unknow Coverage Format:"<<CoverageFormat;
+				continue;
+			}
+			
+			makePairs ( SubTable );
+		}
+		
+	}
+	
+	
 }
 
 
 void KernFeature::makePairs ( quint16 subtableOffset )
 {
-    /*
-     Lookup Type 2:
-     Pair Adjustment Positioning Subtable
-     */
-    
-    quint16 PosFormat ( toUint16 ( subtableOffset ) );
-    
-    if ( PosFormat == 1 )
-    {
-        quint16 ValueFormat1 ( toUint16 ( subtableOffset +4 ) );
-        quint16 ValueFormat2 ( toUint16 ( subtableOffset +6 ) );
-        quint16 PairSetCount ( toUint16 ( subtableOffset +8 ) );
-        if ( ValueFormat1 && ValueFormat2 )
-        {
-            for ( int psIdx ( 0 ); psIdx < PairSetCount; ++ psIdx )
-            {
-                int oldSecondGlyph = -1;
-                unsigned int FirstGlyph ( coverages[subtableOffset][psIdx] );
-                quint16 PairSetOffset ( toUint16 ( subtableOffset +10 + ( 2 * psIdx ) ) +  subtableOffset );
-                quint16 PairValueCount ( toUint16 ( PairSetOffset ) );
-                quint16 PairValueRecord ( PairSetOffset + 2 );
-                for ( int pvIdx ( 0 ); pvIdx < PairValueCount; ++pvIdx )
-                {
-                    quint16 recordBase ( PairValueRecord + ( ( 2 + 2 + 2 ) * pvIdx ) );
-                    quint16 SecondGlyph ( toUint16 ( recordBase ) );
-                    qint16 Value1 ( toInt16 ( recordBase + 2 ) );
-                    // #12475 : Per OpenType spec PairValueRecords must be sorted by SecondGlyph.
-                    // If a kerning pair is duplicated, take only the first one into account
-                    // for now. In the future we may have to ignore the GPOS table in such case.
-                    // (http://partners.adobe.com/public/developer/opentype/index_table_formats2.html)
-                    if (oldSecondGlyph >= SecondGlyph)
-                        continue;
-                    pairs[FirstGlyph][SecondGlyph] = double ( Value1 );
-                    oldSecondGlyph = SecondGlyph;
-                }
-            }
-        }
-        else if ( ValueFormat1 && ( !ValueFormat2 ) )
-        {
-            for ( int psIdx ( 0 ); psIdx < PairSetCount; ++ psIdx )
-            {
-                int oldSecondGlyph = -1;
-                unsigned int FirstGlyph ( coverages[subtableOffset][psIdx] );
-                quint16 PairSetOffset ( toUint16 ( subtableOffset +10 + ( 2 * psIdx ) ) +  subtableOffset );
-                quint16 PairValueCount ( toUint16 ( PairSetOffset ) );
-                quint16 PairValueRecord ( PairSetOffset + 2 );
-                for ( int pvIdx ( 0 ); pvIdx < PairValueCount; ++pvIdx )
-                {
-                    quint16 recordBase ( PairValueRecord + ( ( 2 + 2 ) * pvIdx ) );
-                    quint16 SecondGlyph ( toUint16 ( recordBase ) );
-                    qint16 Value1 ( toInt16 ( recordBase + 2 ) );
-                    // #12475 : Per OpenType spec PairValueRecords must be sorted by SecondGlyph.
-                    // If a kerning pair is duplicated, take only the first one into account
-                    // for now. In the future we may have to ignore the GPOS table in such case.
-                    // (http://partners.adobe.com/public/developer/opentype/index_table_formats2.html)
-                    if (oldSecondGlyph >= SecondGlyph)
-                        continue;
-                    pairs[FirstGlyph][SecondGlyph] = double ( Value1 );
-                    oldSecondGlyph = SecondGlyph;
-                }
-            }
-        }
-        else
-        {
-            //			qDebug() <<"ValueFormat1 is null or both ValueFormat1 and ValueFormat2 are null";
-        }
-    }
-    else if ( PosFormat == 2 ) // class kerning
-    {
-        quint16 ValueFormat1 ( toUint16 ( subtableOffset +4 ) );
-        quint16 ValueFormat2 ( toUint16 ( subtableOffset +6 ) );
-        quint16 ClassDef1 ( toUint16 ( subtableOffset +8 )  + subtableOffset );
-        quint16 ClassDef2 ( toUint16 ( subtableOffset +10 ) + subtableOffset );
-        quint16 Class1Count ( toUint16 ( subtableOffset +12 ) );
-        quint16 Class2Count ( toUint16 ( subtableOffset +14 ) );
-        quint16 Class1Record ( subtableOffset +16 );
-        
-        // first extract classses
-        getClass(true, ClassDef1 , subtableOffset );
-        getClass(false, ClassDef2 , subtableOffset );
-        
-        if ( ValueFormat1 && ValueFormat2 )
-        {
-            for ( quint16 C1 ( 0 );C1 < Class1Count; ++C1 )
-            {
-                quint16 Class2Record ( Class1Record + ( C1 * ( 2 * 2 * Class2Count ) ) );
-                for ( quint16 C2 ( 0 );C2 < Class2Count; ++C2 )
-                {
-                    qint16 Value1 ( toInt16 ( Class2Record + ( C2 * ( 2 * 2 ) ) ) );
-                    if (Value1 != 0)
-                    {
-                        classValue[subtableOffset][C1][C2] = double ( Value1 );
-                    }
-                }
-            }
-        }
-        else if ( ValueFormat1 && ( !ValueFormat2 ) )
-        {
-            for ( quint16 C1 ( 1 );C1 < Class1Count; ++C1 )
-            {
-                quint16 Class2Record ( Class1Record + ( C1 * ( 2 * Class2Count ) ) );
-                for ( quint16 C2 ( 1 );C2 < Class2Count; ++C2 )
-                {
-                    qint16 Value1 ( toInt16 ( Class2Record + ( C2 * 2 ) ) );
-                    if (Value1 != 0)
-                    {
-                        classValue[subtableOffset][C1][C2] = double ( Value1 );
-                    }
-                }
-            }
-        }
-        else
-        {
-            //			qDebug() <<"ValueFormat1 is null or both ValueFormat1 and ValueFormat2 are null";
-        }
-        
-    }
-    else
-        qDebug() <<"unknown PosFormat"<<PosFormat;
+	/*
+	 Lookup Type 2:
+	 Pair Adjustment Positioning Subtable
+	 */
+	
+	quint16 PosFormat ( toUint16 ( subtableOffset ) );
+	
+	if ( PosFormat == 1 )
+	{
+		quint16 ValueFormat1 ( toUint16 ( subtableOffset +4 ) );
+		quint16 ValueFormat2 ( toUint16 ( subtableOffset +6 ) );
+		quint16 PairSetCount ( toUint16 ( subtableOffset +8 ) );
+		if ( ValueFormat1 && ValueFormat2 )
+		{
+			for ( int psIdx ( 0 ); psIdx < PairSetCount; ++ psIdx )
+			{
+				int oldSecondGlyph = -1;
+				unsigned int FirstGlyph ( coverages[subtableOffset][psIdx] );
+				quint16 PairSetOffset ( toUint16 ( subtableOffset +10 + ( 2 * psIdx ) ) +  subtableOffset );
+				quint16 PairValueCount ( toUint16 ( PairSetOffset ) );
+				quint16 PairValueRecord ( PairSetOffset + 2 );
+				for ( int pvIdx ( 0 ); pvIdx < PairValueCount; ++pvIdx )
+				{
+					quint16 recordBase ( PairValueRecord + ( ( 2 + 2 + 2 ) * pvIdx ) );
+					quint16 SecondGlyph ( toUint16 ( recordBase ) );
+					qint16 Value1 ( toInt16 ( recordBase + 2 ) );
+					// #12475 : Per OpenType spec PairValueRecords must be sorted by SecondGlyph.
+					// If a kerning pair is duplicated, take only the first one into account
+					// for now. In the future we may have to ignore the GPOS table in such case.
+					// (http://partners.adobe.com/public/developer/opentype/index_table_formats2.html)
+					if (oldSecondGlyph >= SecondGlyph)
+						continue;
+					pairs[FirstGlyph][SecondGlyph] = double ( Value1 );
+					oldSecondGlyph = SecondGlyph;
+				}
+			}
+		}
+		else if ( ValueFormat1 && ( !ValueFormat2 ) )
+		{
+			for ( int psIdx ( 0 ); psIdx < PairSetCount; ++ psIdx )
+			{
+				int oldSecondGlyph = -1;
+				unsigned int FirstGlyph ( coverages[subtableOffset][psIdx] );
+				quint16 PairSetOffset ( toUint16 ( subtableOffset +10 + ( 2 * psIdx ) ) +  subtableOffset );
+				quint16 PairValueCount ( toUint16 ( PairSetOffset ) );
+				quint16 PairValueRecord ( PairSetOffset + 2 );
+				for ( int pvIdx ( 0 ); pvIdx < PairValueCount; ++pvIdx )
+				{
+					quint16 recordBase ( PairValueRecord + ( ( 2 + 2 ) * pvIdx ) );
+					quint16 SecondGlyph ( toUint16 ( recordBase ) );
+					qint16 Value1 ( toInt16 ( recordBase + 2 ) );
+					// #12475 : Per OpenType spec PairValueRecords must be sorted by SecondGlyph.
+					// If a kerning pair is duplicated, take only the first one into account
+					// for now. In the future we may have to ignore the GPOS table in such case.
+					// (http://partners.adobe.com/public/developer/opentype/index_table_formats2.html)
+					if (oldSecondGlyph >= SecondGlyph)
+						continue;
+					pairs[FirstGlyph][SecondGlyph] = double ( Value1 );
+					oldSecondGlyph = SecondGlyph;
+				}
+			}
+		}
+		else
+		{
+			//			qDebug() <<"ValueFormat1 is null or both ValueFormat1 and ValueFormat2 are null";
+		}
+	}
+	else if ( PosFormat == 2 ) // class kerning
+	{
+		quint16 ValueFormat1 ( toUint16 ( subtableOffset +4 ) );
+		quint16 ValueFormat2 ( toUint16 ( subtableOffset +6 ) );
+		quint16 ClassDef1 ( toUint16 ( subtableOffset +8 )  + subtableOffset );
+		quint16 ClassDef2 ( toUint16 ( subtableOffset +10 ) + subtableOffset );
+		quint16 Class1Count ( toUint16 ( subtableOffset +12 ) );
+		quint16 Class2Count ( toUint16 ( subtableOffset +14 ) );
+		quint16 Class1Record ( subtableOffset +16 );
+		
+		// first extract classses
+		getClass(true, ClassDef1 , subtableOffset );
+		getClass(false, ClassDef2 , subtableOffset );
+		
+		if ( ValueFormat1 && ValueFormat2 )
+		{
+			for ( quint16 C1 ( 0 );C1 < Class1Count; ++C1 )
+			{
+				quint16 Class2Record ( Class1Record + ( C1 * ( 2 * 2 * Class2Count ) ) );
+				for ( quint16 C2 ( 0 );C2 < Class2Count; ++C2 )
+				{
+					qint16 Value1 ( toInt16 ( Class2Record + ( C2 * ( 2 * 2 ) ) ) );
+					if (Value1 != 0)
+					{
+						classValue[subtableOffset][C1][C2] = double ( Value1 );
+					}
+				}
+			}
+		}
+		else if ( ValueFormat1 && ( !ValueFormat2 ) )
+		{
+			for ( quint16 C1 ( 1 );C1 < Class1Count; ++C1 )
+			{
+				quint16 Class2Record ( Class1Record + ( C1 * ( 2 * Class2Count ) ) );
+				for ( quint16 C2 ( 1 );C2 < Class2Count; ++C2 )
+				{
+					qint16 Value1 ( toInt16 ( Class2Record + ( C2 * 2 ) ) );
+					if (Value1 != 0)
+					{
+						classValue[subtableOffset][C1][C2] = double ( Value1 );
+					}
+				}
+			}
+		}
+		else
+		{
+			//			qDebug() <<"ValueFormat1 is null or both ValueFormat1 and ValueFormat2 are null";
+		}
+		
+	}
+	else
+		qDebug() <<"unknown PosFormat"<<PosFormat;
 }
 
 KernFeature::ClassDefTable KernFeature::getClass ( bool leftGlyph, quint16 classDefOffset, quint16 coverageId )
 {
-    if (leftGlyph)
-    {
-        if (classGlyphFirst.contains(coverageId) && classGlyphFirst[coverageId].contains(classDefOffset))
-            return classGlyphFirst[coverageId][classDefOffset];
-    }
-    else
-    {
-        if (classGlyphSecond.contains(coverageId) && classGlyphSecond[coverageId].contains(classDefOffset))
-            return classGlyphSecond[coverageId][classDefOffset];
-    }
-    
-    ClassDefTable ret;
-    
-    QList<quint16> excludeList;
-    quint16 ClassFormat ( toUint16 ( classDefOffset ) );
-    if ( ClassFormat == 1 )
-    {
-        quint16 StartGlyph ( toUint16 ( classDefOffset +2 ) );
-        quint16 GlyphCount ( toUint16 ( classDefOffset +4 ) );
-        quint16 ClassValueArray ( classDefOffset + 6 );
-        
-        for ( quint16 CV ( 0 );CV < GlyphCount; ++CV )
-        {
-            excludeList<<StartGlyph + CV;
-            ret[ toUint16 ( ClassValueArray + ( CV * 2 ) ) ] << StartGlyph + CV;
-        }
-    }
-    else if ( ClassFormat == 2 )
-    {
-        quint16 ClassRangeCount ( toUint16 ( classDefOffset + 2 ) );
-        quint16 ClassRangeRecord ( classDefOffset + 4 );
-        for ( int CRR ( 0 ); CRR < ClassRangeCount; ++CRR )
-        {
-            quint16 Start ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) ) );
-            quint16 End ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) + 2 ) );
-            quint16 Class ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) + 4 ) );
-            
-            if (Start <= End)
-            {
-                for ( int gl ( Start ); gl <= (int) End; ++gl )
-                {
-                    excludeList<< (quint16) gl;
-                    ret[Class] << gl;
-                }
-            }
-            else
-            {
-                for ( int gl ( Start ); gl >= (int) End; --gl )
-                {
-                    excludeList<< (quint16) gl;
-                    ret[Class] << gl;
-                }
-            }
-        }
-    }
-    else
-        qDebug() <<"Unknown Class Table type";
-    
-    // if possible (all glyphs are "classed"), avoid to pass through this slow piece of code.
-    if (excludeList.count() != coverages[coverageId].count())
-    {
-        foreach(const quint16& gidx, coverages[coverageId])
-        {
-            if (!excludeList.contains(gidx))
-                ret[0] << gidx;
-        }
-    }
-    if (leftGlyph)
-        classGlyphFirst[coverageId][classDefOffset] = ret;
-    else
-        classGlyphSecond[coverageId][classDefOffset] = ret;
-    
-    return ret;
+	if (leftGlyph)
+	{
+		if (classGlyphFirst.contains(coverageId) && classGlyphFirst[coverageId].contains(classDefOffset))
+			return classGlyphFirst[coverageId][classDefOffset];
+	}
+	else
+	{
+		if (classGlyphSecond.contains(coverageId) && classGlyphSecond[coverageId].contains(classDefOffset))
+			return classGlyphSecond[coverageId][classDefOffset];
+	}
+	
+	ClassDefTable ret;
+	
+	QList<quint16> excludeList;
+	quint16 ClassFormat ( toUint16 ( classDefOffset ) );
+	if ( ClassFormat == 1 )
+	{
+		quint16 StartGlyph ( toUint16 ( classDefOffset +2 ) );
+		quint16 GlyphCount ( toUint16 ( classDefOffset +4 ) );
+		quint16 ClassValueArray ( classDefOffset + 6 );
+		
+		for ( quint16 CV ( 0 );CV < GlyphCount; ++CV )
+		{
+			excludeList<<StartGlyph + CV;
+			ret[ toUint16 ( ClassValueArray + ( CV * 2 ) ) ] << StartGlyph + CV;
+		}
+	}
+	else if ( ClassFormat == 2 )
+	{
+		quint16 ClassRangeCount ( toUint16 ( classDefOffset + 2 ) );
+		quint16 ClassRangeRecord ( classDefOffset + 4 );
+		for ( int CRR ( 0 ); CRR < ClassRangeCount; ++CRR )
+		{
+			quint16 Start ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) ) );
+			quint16 End ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) + 2 ) );
+			quint16 Class ( toUint16 ( ClassRangeRecord + ( CRR * 6 ) + 4 ) );
+			
+			if (Start <= End)
+			{
+				for ( int gl ( Start ); gl <= (int) End; ++gl )
+				{
+					excludeList<< (quint16) gl;
+					ret[Class] << gl;
+				}
+			}
+			else
+			{
+				for ( int gl ( Start ); gl >= (int) End; --gl )
+				{
+					excludeList<< (quint16) gl;
+					ret[Class] << gl;
+				}
+			}
+		}
+	}
+	else
+		qDebug() <<"Unknown Class Table type";
+	
+	// if possible (all glyphs are "classed"), avoid to pass through this slow piece of code.
+	if (excludeList.count() != coverages[coverageId].count())
+	{
+		foreach(const quint16& gidx, coverages[coverageId])
+		{
+			if (!excludeList.contains(gidx))
+				ret[0] << gidx;
+		}
+	}
+	if (leftGlyph)
+		classGlyphFirst[coverageId][classDefOffset] = ret;
+	else
+		classGlyphSecond[coverageId][classDefOffset] = ret;
+	
+	return ret;
 }
 
 quint16 KernFeature::toUint16 ( quint16 index )
 {
-    if ( ( index + 2 ) > GPOSTableRaw.count() )
-    {
-        //                qDebug() << "HORROR!" << index << GPOSTableRaw.count() << FontName ;
-        // Rather no kerning at all than random kerning
-        // 		m_valid = false;
-        return 0;
-    }
-    // FIXME I just do not know how it has to be done *properly*
-    quint8 c1 ( GPOSTableRaw.at ( index ) );
-    quint8 c2 ( GPOSTableRaw.at ( index + 1 ) );
-    quint16 ret ( ( c1 << 8 ) | c2 );
-    return ret;
+	if ( ( index + 2 ) > GPOSTableRaw.count() )
+	{
+		//	qDebug() << "HORROR!" << index << GPOSTableRaw.count() << FontName ;
+		// Rather no kerning at all than random kerning
+		// 		m_valid = false;
+		return 0;
+	}
+	// FIXME I just do not know how it has to be done *properly*
+	quint8 c1 ( GPOSTableRaw.at ( index ) );
+	quint8 c2 ( GPOSTableRaw.at ( index + 1 ) );
+	quint16 ret ( ( c1 << 8 ) | c2 );
+	return ret;
 }
 
 qint16 KernFeature::toInt16 ( quint16 index )
 {
-    if ( ( index + 2 ) > GPOSTableRaw.count() )
-    {
-        return 0;
-    }
-    // FIXME I just do not know how it has to be done *properly*
-    quint8 c1 ( GPOSTableRaw.at ( index ) );
-    quint8 c2 ( GPOSTableRaw.at ( index + 1 ) );
-    qint16 ret ( ( c1 << 8 ) | c2 );
-    return ret;
+	if ( ( index + 2 ) > GPOSTableRaw.count() )
+	{
+		return 0;
+	}
+	// FIXME I just do not know how it has to be done *properly*
+	quint8 c1 ( GPOSTableRaw.at ( index ) );
+	quint8 c2 ( GPOSTableRaw.at ( index + 1 ) );
+	qint16 ret ( ( c1 << 8 ) | c2 );
+	return ret;
 }

Modified: trunk/Scribus/scribus/fonts/sfnt.h
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=20113&path=/trunk/Scribus/scribus/fonts/sfnt.h
==============================================================================
--- trunk/Scribus/scribus/fonts/sfnt.h (original)
+++ trunk/Scribus/scribus/fonts/sfnt.h Thu May 21 23:40:15 2015
@@ -22,34 +22,34 @@
 
 
 namespace sfnt {
-    
-    uchar byte(QByteArray const & bb, uint pos);
-    quint32  word(QByteArray const & bb, uint pos);
-    void  putWord(QByteArray & bb, uint pos, quint32 val);
-    void  appendWord(QByteArray& bb, quint32 val);
-    quint16  word16(QByteArray const & bb, uint pos);
-    void  putWord16(QByteArray & bb, uint pos, quint16 val);
-    void  appendWord16(QByteArray& bb, quint16 val);
-    bool  copy(QByteArray & dst, uint to, const QByteArray & src, uint from, uint len);
-    const QByteArray tag(QByteArray const & bb, uint pos);
-    const QByteArray getTable(const QByteArray& ttf, const QByteArray& ttfTag);
-    
+	
+	uchar byte(QByteArray const & bb, uint pos);
+	quint32  word(QByteArray const & bb, uint pos);
+	void  putWord(QByteArray & bb, uint pos, quint32 val);
+	void  appendWord(QByteArray& bb, quint32 val);
+	quint16  word16(QByteArray const & bb, uint pos);
+	void  putWord16(QByteArray & bb, uint pos, quint16 val);
+	void  appendWord16(QByteArray& bb, quint16 val);
+	bool  copy(QByteArray & dst, uint to, const QByteArray & src, uint from, uint len);
+	const QByteArray tag(QByteArray const & bb, uint pos);
+	const QByteArray getTable(const QByteArray& ttf, const QByteArray& ttfTag);
+	
 
-    QByteArray subsetFace(const QByteArray& ttf, QList<uint>& glyphs);
-    QByteArray extractFace(const QByteArray& ttfColl, int faceIndex);
+	QByteArray subsetFace(const QByteArray& ttf, QList<uint>& glyphs);
+	QByteArray extractFace(const QByteArray& ttfColl, int faceIndex);
 
 /**
  This class checks the post table of a ttf font.
  */
 class SCRIBUS_API PostTable {
 public:
-    bool usable;
-    QString errorMsg;
-    uint numberOfGlyphs() const;
-    QString nameFor(uint glyphId) const;
-    void readFrom(FT_Face face);
+	bool usable;
+	QString errorMsg;
+	uint numberOfGlyphs() const;
+	QString nameFor(uint glyphId) const;
+	void readFrom(FT_Face face);
 private:
-    QList<QString> names;
+	QList<QString> names;
 };
 
 } //namespace
@@ -61,48 +61,48 @@
  */
 class SCRIBUS_API KernFeature
 {
-    typedef QMap<quint16, QList<quint16> > ClassDefTable; // <Class index (0 to N) , list of glyphs >
-    
+	typedef QMap<quint16, QList<quint16> > ClassDefTable; // <Class index (0 to N) , list of glyphs >
+	
 public:
-    /**
-     * Build a ready-to-use kerning pairs table
-     * @param face a valid FT_Face, It won’t be store by KernFeature
-     */
-    KernFeature ( FT_Face face );
-    KernFeature ( const KernFeature& kf );
-    ~KernFeature();
-    
-    /**
-     * Get the kerning value for a pair of glyph indexes.
-     * @param glyph1 Index of the left glyph in logical order
-     * @param glyph2 Index of the right glyph in logical order
-     * @return the unscaled delta to apply to xadvance of the first glyph
-     */
-    double getPairValue ( unsigned int glyph1, unsigned int glyph2 ) const;
-    
-    /**
-     * The table can have been invalidated if something went wrong at any moment.
-     * @return True if valid, False otherwise.
-     */
-    bool isValid() const {return m_valid;}
-    
+	/**
+	 * Build a ready-to-use kerning pairs table
+	 * @param face a valid FT_Face, It won’t be store by KernFeature
+	 */
+	KernFeature ( FT_Face face );
+	KernFeature ( const KernFeature& kf );
+	~KernFeature();
+	
+	/**
+	 * Get the kerning value for a pair of glyph indexes.
+	 * @param glyph1 Index of the left glyph in logical order
+	 * @param glyph2 Index of the right glyph in logical order
+	 * @return the unscaled delta to apply to xadvance of the first glyph
+	 */
+	double getPairValue ( unsigned int glyph1, unsigned int glyph2 ) const;
+	
+	/**
+	 * The table can have been invalidated if something went wrong at any moment.
+	 * @return True if valid, False otherwise.
+	 */
+	bool isValid() const {return m_valid;}
+	
 private:
-    bool m_valid;
-    QByteArray GPOSTableRaw;
-    QMap<quint16,QList<quint16> > coverages;
-    mutable QMap<quint16, QMap<quint16, double> > pairs;
-    QMap< quint16, QMap<quint16, ClassDefTable> > classGlyphFirst; // < subtable offset, map<offset, class definition table> > for first glyph
-    QMap< quint16, QMap<quint16, ClassDefTable> > classGlyphSecond; // < subtable offset, map<offset, class definition table> > for second glyph
-    QMap< quint16, QMap<int, QMap<int, double> > > classValue; // < subtable offset, map<class1, map<class2, value> > >
-    
-    void makeCoverage();
-    void makePairs ( quint16 subtableOffset );
-    
-    ClassDefTable getClass (bool leftGlyph, quint16 classDefOffset, quint16 coverageId );
-    inline quint16 toUint16 ( quint16 index );
-    inline qint16 toInt16 ( quint16 index );
-    
-    QString FontName;// for debugging purpose
+	bool m_valid;
+	QByteArray GPOSTableRaw;
+	QMap<quint16,QList<quint16> > coverages;
+	mutable QMap<quint16, QMap<quint16, double> > pairs;
+	QMap< quint16, QMap<quint16, ClassDefTable> > classGlyphFirst; // < subtable offset, map<offset, class definition table> > for first glyph
+	QMap< quint16, QMap<quint16, ClassDefTable> > classGlyphSecond; // < subtable offset, map<offset, class definition table> > for second glyph
+	QMap< quint16, QMap<int, QMap<int, double> > > classValue; // < subtable offset, map<class1, map<class2, value> > >
+	
+	void makeCoverage();
+	void makePairs ( quint16 subtableOffset );
+	
+	ClassDefTable getClass (bool leftGlyph, quint16 classDefOffset, quint16 coverageId );
+	inline quint16 toUint16 ( quint16 index );
+	inline qint16 toInt16 ( quint16 index );
+	
+	QString FontName;// for debugging purpose
 };
 
 




More information about the scribus-commit mailing list