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