blob: 2df620b8af1b5f96595a7274e1fe1cf93cfec385 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Viskov Nikolay
*/
#include <stdio.h>
#include <string>
#include <string.h>
#include <stdlib.h>
#if defined(LINUX)
#include <ctype.h>
#endif
#include "T1Font.h"
#include "T1Glyph.h"
T1Font::T1Font(fwchar_t *family, StyleName sn, fchar* pathToFile):Font() {
//this->_famName = family;
_style = sn;
fullName = NULL;
FILE *inputFile;
if( inputFile = fopen(pathToFile, "rb")) {
try {
initFont(inputFile);
} catch (fchar*) {
//printf("%s", str);
}
fclose(inputFile);
//set default ascent and descent
_ascent = 649;
_descent = 195;
fchar path[MAX_STR_LENGTH];
size_t length = strlen(pathToFile) - 3;
strncpy(path, pathToFile, length);
strcpy(path + length, "afm");
if( inputFile = fopen(path, "rb")) {
try {
parseAFM(inputFile);
} catch (...) {
//printf("%s", str);
}
fclose(inputFile);
}
}
}
T1Font::~T1Font(void) {
for( Type1Map::iterator iter = subrsMap.begin(); iter != subrsMap.end(); iter++ ) {
delete iter->second;
}
for( Type1Map::iterator iter = charStringMap.begin(); iter != charStringMap.end(); iter++ ) {
delete iter->second;
}
/*for( Type1AFMMap::iterator iter = afmMap.begin(); iter != afmMap.end(); iter++ ) {
delete[] iter->second;
}*/
delete fullName;
}
Glyph* T1Font::createGlyph(ufshort unicode, ufshort size) {
/*ffloat floatMas[4];
Type1AFMMap::iterator iter = afmMap.find(unicode);
//return iter == glyphCodeMap.end()? NULL : (ufshort)iter->second;
memcpy(floatMas, _boundingBox, 4 * sizeof(ffloat));
if (iter != afmMap.end()) {
//printf("%s\n", iter->second);
fchar* curValue = strstr( iter->second, " B ");
if (curValue != NULL) {
curValue += 3;
floatMas[0] = (ffloat) atof(curValue);
//printf("0 = %f\n", floatMas[0]);
while (*(++curValue) != ' ') {
}
floatMas[1] = (ffloat) atof(curValue);
//printf("1 = %f\n", floatMas[1]);
while (*(++curValue) != ' ') {
}
floatMas[2] = (ffloat) atof(curValue);
//printf("2 = %f\n", floatMas[2]);
while (*(++curValue) != ' ') {
}
floatMas[3] = (ffloat) atof(curValue);
//printf("3 = %f\n", floatMas[3]);
}
}*/
Glyph *glyph = new T1Glyph(&(this->charStringMap), &(this->subrsMap), unicode, size, size / matrixScale, _boundingBox);
return glyph;
}
//TODO: owerwrite this:
fwchar_t* T1Font::getPSName() {
return fullName;
}
ffloat* T1Font::getLineMetrics() {
/*
* metrics[0] - ascent<p>
* metrics[1] - descent<p>
* metrics[2] - external leading<p>
* metrics[3] - underline thickness<p>
* metrics[4] - underline offset<p>
* metrics[5] - strikethrough thickness<p>
* metrics[6] - strikethrough offset<p>
* metrics[7] - maximum fchar width<p>*/
ffloat* floatMas = new ffloat[FONT_METRICS_QUANTITY];
floatMas[0] = _ascent / matrixScale; //ascent
floatMas[1] = _descent / matrixScale; //descent
floatMas[2] = (_height - _ascent - _descent) / matrixScale;//_externalLeading;
floatMas[3] = _underlineThickness / matrixScale;
floatMas[4] = _underlineOffset / matrixScale;
floatMas[5] = _underlineThickness / matrixScale;//_strikeOutSize;
floatMas[6] = -_ascent/(2 * matrixScale);//_strikeOutOffset;
floatMas[7] = ((ffloat)(_boundingBox[3] - _boundingBox[1])) / matrixScale;
return floatMas;
}
bool T1Font::canDisplay(ufshort ch) {
return this->charStringMap.find(ch) != this->charStringMap.end();
}
ufshort T1Font::getUnicodeByIndex(ufshort index) {
Type1GlyphCodeMap::iterator iter = glyphCodeMap.find(index);
return iter == glyphCodeMap.end()? 0 : (ufshort)iter->second;
}
void error(){
//printf("invalidfont");
throw "invalidfont";
}
inline ufshort hexCharToUShort(fchar ch){
return ch >= '0' && ch <= '9' ? ch - '0' :
ch >= 'A' && ch <= 'F' ? ch - 'A' + 10 :
ch >= 'a' && ch <= 'f' ? ch - 'a' + 10 :
0;
}
void static getNextLine(fchar* str, FILE* font) {
ufshort count = 0;
ufchar ch = ' ';
while (!feof(font) && (ch == ' ' || ch == '\n' || ch == '\r')) {
ch = getc(font);
}
str[count] = ch;
while (!feof(font) && ch != '\r' && ch != '\n') {
str[++count] = (ch = getc(font));
}
str[count] = '\0';
}
static ufchar getNextChar(FILE* font) {
ufchar ch;
do {
ch = getc(font);
} while (ch == '\r' || ch == '\n');
return ch;
}
static ufchar decryptNextSimbol(FILE* font, ufshort* r, bool isASCII) {
ufchar clipher = (ufchar)(
isASCII ?
(ufchar) ((hexCharToUShort(getNextChar(font)) << 4 ) + (hexCharToUShort(getNextChar(font)))) :
getc(font)
);
ufchar plain = (ufchar)(clipher ^ (*r >> 8));
*r = ( (ufchar)clipher + *r ) * C1 + C2;
return plain;
}
void static decodeASCIILine(fchar* str, ufshort* r, ufshort n, ufshort length) {
fchar* p = str;
ufchar plain;
ufchar clipher;
ufshort count = 0;
length /= 2;
while(count < length) {
clipher = (ufchar)((hexCharToUShort(*p) << 4 ) + (hexCharToUShort(*(p + 1))));
plain = (ufchar)(clipher ^ (*r >> 8));
*r = ( (ufchar)clipher + *r ) * C1 + C2;
if (count >= n) {
str[count - n] = plain;
}
count ++;
p+= 2;
}
str[count - n] = '\0';
}
void static decodeBinaryLine(fchar* str, ufshort* r, ufshort n, ufshort length) {
fchar* p = str;
ufchar plain;
ufchar clipher;
ufshort count = 0;
while(count < length) {
clipher = (ufchar)*p;
plain = (ufchar)(clipher ^ (*r >> 8));
*r = ( (ufchar)clipher + *r ) * C1 + C2;
if (count >= n) {
str[count - n] = plain;
}
count ++;
p ++;
}
str[count - n] = '\0';
}
void static decodeLine(fchar* str, ufshort* r, ufshort n, bool isASCII, ufshort length) {
if (isASCII) {
decodeASCIILine(str,r,n,length);
} else {
decodeBinaryLine(str,r,n,length);
}
return;
/*fchar* p = str;
ufchar plain;
ufchar clipher;
ufshort count = 0;
if (isASCII) {
length /= 2;
}
while(count < length) {
clipher = (ufchar)(isASCII ? ((hexCharToUShort(*p) << 4 ) + (hexCharToUShort(*(p + 1)))) : *p);
plain = (ufchar)(clipher ^ (*r >> 8));
*r = ( (ufchar)clipher + *r ) * C1 + C2;
//printf("%u ---- %u,%u\n", clipher, plain, *r);
if (count >= n) {
str[count - n] = plain;
}
count ++;
p+= isASCII ? 2 : 1;
}
str[count - n] = '\0';//*/
}
void static getNextDecodeLine(fchar* str, FILE* font, ufshort* r, bool isASCII) {
ufshort count = 0;
ufchar plain;
while(!feof(font)) {
plain = decryptNextSimbol(font, r, isASCII);
str[count ++] = plain;
if (plain == '\r' || plain == '\n') {
break;
}
}
str[count] = '\0';
}
void static getNextDecodeLexeme(fchar* str, FILE* font, ufshort* r, bool isASCII) {
ufchar ch;
ufshort count = 0;
while (!feof(font) && ((ch = decryptNextSimbol(font, r, isASCII)) == ' ' || ch == '\n' || ch == '\r')) {
}
str[count ++] = ch;
while (!feof(font) && (ch = decryptNextSimbol(font, r, isASCII)) != ' ' && ch != '\n' && ch != '\r') {
str[count ++] = ch;
}
str[count] = '\0';
}
void static getNextLexeme(fchar* str, FILE* font) {
ufchar ch;
ufshort count = 0;
while (!feof(font) && ((ch = getc(font)) == ' ' || ch == '\n' || ch == '\r' && ch != '{')) {
}
str[count ++] = ch;
while (!feof(font) && (ch = getc(font)) != ' ' && ch != '\n' && ch != '\r' && ch != '{') {
str[count ++] = ch;
}
str[count] = '\0';
}
ufshort static findUnicode(const fchar *str) {
ufshort count = 0;
ufshort strCount = 0;
ufshort lastStrCount = 0;
while(true) {
if (GLYPH_LIST[count] == str[strCount]) {
count ++;
strCount ++;
//next iteration
} else if ((GLYPH_LIST[count] ^ (1 << 7)) == str[strCount]) {
strCount ++;
if (str[strCount] == '\0') {
return (ufshort)((GLYPH_LIST[count + 1] << 8) + GLYPH_LIST[count + 2]);
}
count = ((GLYPH_LIST[count + 5] << 8) + GLYPH_LIST[count + 6]);
lastStrCount = strCount;
if (!count) {
return FONT_NOT_FOUND_UNICODE_VALUE;
}
//on next level
} else {
strCount = lastStrCount;
for (;!(GLYPH_LIST[count] & (1 << 7)) ; ) {
count ++;
}
count = ((GLYPH_LIST[count + 3] << 8) + GLYPH_LIST[count + 4]);
if (!count) {
return FONT_NOT_FOUND_UNICODE_VALUE;
}
//next on this level
}
}
}
ufshort static getUnicode(fchar *name) {
if (!strncmp(name, ".notdef", 7)) {
return 0;
}
return findUnicode(name);
}
void T1Font::parseAFM(FILE *font) {
fchar curStr[MAX_STR_LENGTH];
while (!feof(font)) {
getNextLexeme(curStr, font);
//printf("%s\n",curStr);
if (!strcmp(curStr, "EndFontMetrics") || !strcmp(curStr, "StartCharMetrics")) {
return;
} else if (!strcmp(curStr, "Ascender")) {
getNextLexeme(curStr, font);
_ascent = (ffloat) fabs(atof(curStr));
//printf("ascend = %f\n", _ascent);
} else if (!strcmp(curStr, "Descender")) {
getNextLexeme(curStr, font);
_descent = (ffloat) fabs(atof(curStr));
//printf("descent = %f\n", _descent);
} /*else if (!strcmp(curStr, "StartCharMetrics")) {
getNextLexeme(curStr, font);
fchar* curValue;
fchar psName[MAX_STR_LENGTH];
ufshort count = (ufshort) atoi(curStr);
for (ufshort i = 0; i < count; i ++) {
getNextLine(curStr, font);
//printf("%s\n",curStr);
curValue = strstr( curStr, " N ");
if (curValue != NULL) {
curValue += 3;
//printf("%s\n", curValue);
ufshort i;
for (i = 0; curValue[i] != ' ' && curValue[i] != '\0'; i ++) {
psName[i] = curValue[i];
}
psName[i] = '\0';
curValue = new fchar[strlen(curStr) + 1];
strcpy(curValue, curStr);
//printf("%u = %s = %s\n",findUnicode(psName),curValue,psName);
afmMap[getUnicode(psName)] = curValue;
}
}
}*/ else {
getNextLine(curStr, font);
}
}
}
void T1Font::initFont(FILE *font) {
fchar curStr[MAX_STR_LENGTH];
DecodeState state = HEADER;
ufshort r = DEF_R_EXEC;
ufshort n = 4;
ufshort lenIV = DEF_LENIV;
ufshort charStringR;
ufshort count = 0;
ufshort tempShort = 0;
ufshort length = 0;
ufshort valueLength = 0;
matrixScale = 1000;
bool isASCII = true;
ufchar ch;
EncodedValue *curValue;
ch = getc(font);
if (ch == 0x80 && getc(font) == 0x01) {
isASCII = false;
} else if (ch == '%' && getc(font) == '!') {
isASCII = true;
} else {
error();
}
while (!feof(font)) {
switch (state) {
case HEADER: {
getNextLexeme(curStr, font);
if (!strcmp(curStr, "/UnderlinePosition")) {
getNextLexeme(curStr, font);
_underlineOffset = (ffloat) - atof(curStr);
} else if (!strcmp(curStr, "/UnderlineThickness")) {
getNextLexeme(curStr, font);
_underlineThickness = (ffloat) atof(curStr);
} else if (strstr(curStr, "/FontBBox") != NULL) {
//getNextLexeme(curStr, font);
while (!feof(font) && ((ch = getc(font)) == '{')) {
}
ungetc(ch, font);
getNextLexeme(curStr, font);
_boundingBox[0] = (ffloat) atof(curStr);
getNextLexeme(curStr, font);
_boundingBox[1] = (ffloat) atof(curStr);
getNextLexeme(curStr, font);
_boundingBox[2] = (ffloat) atof(curStr);
getNextLexeme(curStr, font);
_boundingBox[3] = (ffloat) atof(curStr);
_height = ((ffloat)(_boundingBox[2] -_boundingBox[0]));
} else if (!strcmp(curStr, "/FullName")) {
//getNextLexeme(curStr, font);
while (!feof(font) && ((ch = getc(font)) == '(')) {
}
curStr[count ++] = ch;
while (!feof(font) && (ch = getc(font)) != ')') {
curStr[count ++] = ch;
}
curStr[count] = '\0';
fchar *ptr = curStr;
ch = 0;
fullName = new fwchar_t[count + 1];
while (*ptr != '\0') {
fullName[ch ++] = *ptr;
ptr ++;
}
fullName[ch] = L'\0';
} else if (!strcmp(curStr, "eexec")) {
state = PRIVATE_DIR;
if (isASCII) {
for (count = 0; count < lenIV * 2; count ++) {
if (!isascii(ch = getc(font))) {
error();
}
curStr[count] = ch;
}
decodeASCIILine(curStr, &r, n, count);
} else {
for (count = 0; count < 6; count ++) {
curStr[count] = getc(font);
}
if (curStr[0] != (fchar)0x80 || curStr[1] != 0x02) {
error();
}
for (count = 0; count < lenIV; count ++) {
curStr[count] = getc(font);
}
decodeBinaryLine(curStr, &r, n, count);
}
}
break;
}
case PRIVATE_DIR: {
getNextDecodeLexeme(curStr, font, &r, isASCII);
if (!strcmp(curStr, "/Subrs")) {
getNextDecodeLexeme(curStr, font, &r, isASCII);
valueLength = atoi(curStr);
count = 0;
state = SUBRS_MASSIVE;
getNextDecodeLine(curStr, font, &r, isASCII);
} else if (!strcmp(curStr, "/CharStrings")) {
getNextDecodeLexeme(curStr, font, &r, isASCII);
valueLength = atoi(curStr);
count = 0;
state = CHAR_STRING;
getNextDecodeLine(curStr, font, &r, isASCII);
}
break;
}
case SUBRS_MASSIVE: {
curValue = new EncodedValue();
getNextDecodeLexeme(curStr, font, &r, isASCII);
getNextDecodeLexeme(curStr, font, &r, isASCII);
curValue->number = (ufshort) atoi(curStr);
getNextDecodeLexeme(curStr, font, &r, isASCII);
length = (ufshort) atoi(curStr);
curValue->length = length - lenIV;
getNextDecodeLexeme(curStr, font, &r, isASCII);
for (tempShort = 0; tempShort - length < 0; tempShort ++) {
curStr[tempShort] = decryptNextSimbol(font, &r, isASCII);
}
charStringR = DEF_R_CHARSTRING;
decodeBinaryLine(curStr, &charStringR, lenIV, length);
curValue->text = new fchar[curValue->length];
for (tempShort = 0; tempShort - curValue->length < 0; tempShort ++) {
curValue->text[tempShort] = curStr[tempShort];
}
subrsMap[curValue->number] = curValue;
getNextDecodeLine(curStr, font, &r, isASCII);
if (++count >= valueLength) {
state = PRIVATE_DIR;
count = 0;
}
break;
}
case CHAR_STRING: {
getNextDecodeLexeme(curStr, font, &r, isASCII);
tempShort = getUnicode(curStr + 1);
if (tempShort != FONT_NOT_FOUND_UNICODE_VALUE) {
glyphCodeMap[count] = tempShort;
curValue = new EncodedValue();
curValue->number = tempShort;
getNextDecodeLexeme(curStr, font, &r, isASCII);
length = (ufshort) atoi(curStr);
curValue->length = length - lenIV;
getNextDecodeLexeme(curStr, font, &r, isASCII);
for (tempShort = 0; tempShort - length < 0; tempShort ++) {
curStr[tempShort] = decryptNextSimbol(font, &r, isASCII);
}
charStringR = DEF_R_CHARSTRING;
decodeBinaryLine(curStr, &charStringR, lenIV, length);
curValue->text = new fchar[curValue->length];
for (tempShort = 0; tempShort - curValue->length < 0; tempShort ++) {
curValue->text[tempShort] = curStr[tempShort];
}
charStringMap[curValue->number] = curValue;
} else {
getNextDecodeLexeme(curStr, font, &r, isASCII);
length = (ufshort) atoi(curStr);
getNextDecodeLexeme(curStr, font, &r, isASCII);
for (tempShort = 0; tempShort - length < 0; tempShort ++) {
decryptNextSimbol(font, &r, isASCII);
}
}
getNextDecodeLine(curStr, font, &r, isASCII);
if (++count >= valueLength) {
return;
}
break;
}
}
}
}