home *** CD-ROM | disk | FTP | other *** search
- //========================================================================
- //
- // FontOutputDev.cc
- //
- // Copyright 1999 Emmanuel Lesueur
- //
- //========================================================================
-
- #ifdef __GNUC__
- #pragma implementation
- #endif
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <ctype.h>
- #define Object ZZObject
- #include <graphics/gfx.h>
- #include <graphics/text.h>
- #undef Object
- #include "GString.h"
- #include "gmem.h"
- #include "config.h"
- #include "Error.h"
- #include "GfxState.h"
- #include "GfxFont.h"
- #include "FontOutputDev.h"
- #include "XOutputFontInfo.h"
-
- static GfxFontEncoding* enc[]={
- &isoLatin1Encoding,
- &isoLatin2Encoding,
- &symbolEncoding,
- &zapfDingbatsEncoding
- };
-
- //------------------------------------------------------------------------
- // Font map
- //------------------------------------------------------------------------
-
- static FontMapEntry fontMap[] = {
- {"Courier", "courier.font",100,FS_NORMAL,0},
- {"Courier-Bold", "courier.font",100,FSF_BOLD,0},
- {"Courier-BoldOblique", "courier.font",100,FSF_BOLD|FSF_ITALIC,0},
- {"Courier-Oblique", "courier.font",100,FSF_ITALIC,0},
- {"Helvetica", "helvetica.font",100,FS_NORMAL,0},
- {"Helvetica-Bold", "helvetica.font",100,FSF_BOLD,0},
- {"Helvetica-BoldOblique", "helvetica.font",100,FSF_BOLD|FSF_ITALIC,0},
- {"Helvetica-Oblique", "helvetica.font",100,FSF_ITALIC,0},
- {"Symbol", "StandardSymL.font",100,FS_NORMAL,2},
- {"Times-Bold", "times.font",100,FSF_BOLD,0},
- {"Times-BoldItalic", "times.font",100,FSF_BOLD|FSF_ITALIC,0},
- {"Times-Italic", "times.font",100,FSF_ITALIC,0},
- {"Times-Roman", "times.font",100,FS_NORMAL,0},
- {"ZapfDingbats", "Dingbats.font",100,FS_NORMAL,3},
- {NULL}
- };
- static const int fontMapSize=sizeof(fontMap)/sizeof(fontMap[0])-1;
-
- FontMapEntry *userFontMap;
-
-
- //------------------------------------------------------------------------
- // Font substitutions
- //------------------------------------------------------------------------
-
- const char* defFontsNames[] = {
- "« Sans-serif »",
- "« Sans-serif Italic »",
- "« Sans-serif Bold »",
- "« Sans-serif Italic Bold »",
- "« Serif »",
- "« Serif Italic »",
- "« Serif Bold »",
- "« Serif Italic Bold »",
- "« Fixed »",
- "« Fixed Italic »",
- "« Fixed Bold »",
- "« Fixed Italic Bold »",
- /* "« Symbolic »",
- "« Symbolic Italic »",
- "« Symbolic Bold »",
- "« Symbolic Italic Bold »",*/
- };
-
- struct FontSubst {
- char *xFont;
- int style;
- double mWidth;
- };
-
- // index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
- static FontSubst fontSubst[] = {
- {"helvetica.font", FS_NORMAL, 0.833},
- {"helvetica.font", FSF_ITALIC, 0.833},
- {"helvetica.font", FSF_BOLD, 0.889},
- {"helvetica.font", FSF_BOLD|FSF_ITALIC, 0.889},
- {"times.font", FS_NORMAL, 0.788},
- {"times.font", FSF_ITALIC, 0.722},
- {"times.font", FSF_BOLD, 0.833},
- {"times.font", FSF_BOLD|FSF_ITALIC, 0.778},
- {"courier.font", FS_NORMAL, 0.600},
- {"courier.font", FSF_ITALIC, 0.600},
- {"courier.font", FSF_BOLD, 0.600},
- {"courier.font", FSF_BOLD|FSF_ITALIC, 0.600},
- /* {"StandardSymL.font",FS_NORMAL, 0.576},
- {"StandardSymL.font",FSF_ITALIC, 0.576},
- {"StandardSymL.font",FSF_BOLD, 0.576},
- {"StandardSymL.font",FSF_BOLD|FSF_ITALIC, 0.576},*/
- };
- static const int fontSubstSize=sizeof(fontSubst)/sizeof(fontSubst[0]);
-
- const char* getAFont(GfxFont* gfxFont,GfxFontEncoding*& encoding,
- int& style,double& m1, double& m2) {
-
- encoding = &isoLatin1Encoding;
- style = 0;
- m1 = 1;
- m2 = 1;
-
- if(gfxFont->is16Bit())
- return fontSubst[0].xFont;
- else {
-
- GString* pdfFont = gfxFont->getName();
- FontMapEntry* p = NULL;
-
- if (pdfFont) {
- for (p = userFontMap; p->pdfFont; ++p) {
- if (!pdfFont->cmp(p->pdfFont))
- break;
- }
- if (!p->pdfFont) {
- for (p = fontMap; p->pdfFont; ++p) {
- if (!pdfFont->cmp(p->pdfFont))
- break;
- }
- }
- }
-
- if (p && p->pdfFont) {
- m1 = m2 = p->mWidth / 100.0;
- style = p->style;
- encoding = enc[p->encoding];
- return p->xFont;
- } else {
- //~ Some non-symbolic fonts are tagged as symbolic.
- // if (gfxFont->isSymbolic()) {
- // index = 12;
- // encoding = symbolEncoding;
- // } else
- int index;
- if (gfxFont->isFixedWidth()) {
- index = 8;
- } else if (gfxFont->isSerif()) {
- index = 4;
- } else {
- index = 0;
- }
- if (gfxFont->isBold())
- index += 2;
- if (gfxFont->isItalic())
- index += 1;
-
- const char* defFontName = defFontsNames[index];
-
- for (p = userFontMap; p->pdfFont; ++p) {
- if (!strcmp(p->pdfFont, defFontName))
- break;
- }
-
- if (p && p->pdfFont) {
- m1 = m2 = p->mWidth / 100.0;
- style = p->style;
- encoding = enc[p->encoding];
- return p->xFont;
- } else {
-
- double w1, w2, v;
- int code;
-
- if ((code = gfxFont->getCharCode("m")) >= 0)
- w1 = gfxFont->getWidth(code);
- else
- w1 = 0;
- w2 = fontSubst[index].mWidth;
- if (gfxFont->getType() == fontType3) {
- // This is a hack which makes it possible to substitute for some
- // Type 3 fonts. The problem is that it's impossible to know what
- // the base coordinate system used in the font is without actually
- // rendering the font. This code tries to guess by looking at the
- // width of the character 'm' (which breaks if the font is a
- // subset that doesn't contain 'm').
- if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) {
- w1 /= w2;
- m1 = m2 = w1;
- }
- double* fm = gfxFont->getFontMatrix();
- v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]);
- m2 *= v;
- m2 *= v;
- } else if (!gfxFont->isSymbolic()) {
- if (w1 > 0.01 && w1 < 0.9 * w2) {
- w1 /= w2;
- if (w1 < 0.8)
- w1 = 0.8;
- m1 = m2 = w1;
- }
- }
- style = fontSubst[index].style;
- return fontSubst[index].xFont;
- }
- }
- }
- }
-
- #if 0
- void clearUserFontMap() {
- if(userFontMap) {
- gfree(userFontMap);
- userFontMap = NULL;
- }
- }
-
- void resetUserFontMap() {
- clearUserFontMap();
-
- for (n = 0; devFontMap[n].pdfFont; ++n) ;
- userFontMap = (FontMapEntry *)gmalloc((n+1) * sizeof(FontMapEntry));
- for (i = 0; i < n; ++i) {
- char* s = devFontMap[i].devFont;
- int style = FS_NORMAL;
- GfxFontEncoding* encoding = &isoLatin1Encoding;
- double m = 1;
- if(*s=='[') {
- ++s;
- bool ok=true;
- do {
- switch(*s++) {
- case '\0':
- error(-1, "Unterminated font option.\n");
- ok = false;
- s = devFontMap[i].devFont;
- break;
- case '1':
- encoding = &isoLatin1Encoding;
- break;
- case '2':
- encoding = &isoLatin2Encoding;
- break;
- case 'z':
- encoding = &zapfDingbatsEncoding;
- break;
- case 's':
- encoding = &symbolEncoding;
- break;
- case 'B':
- style |= FSF_BOLD;
- break;
- case 'I':
- style |= FSF_ITALIC;
- break;
- case ']':
- ok = false;
- break;
- default:
- error(-1, "Invalid font flag : %c\n", s[-1]);
- break;
- }
- } while(ok);
- }
- userFontMap[i].pdfFont = devFontMap[i].pdfFont;
- userFontMap[i].xFont = s;
- userFontMap[i].mWidth = m;
- userFontMap[i].style = style;
- userFontMap[i].encoding = encoding;
- }
- userFontMap[n].pdfFont = NULL;
- }
- #endif
-
-
- FontOutputDev::FontOutputDev() : beg(NULL),cur(NULL),end(NULL) {
- }
-
- FontOutputDev::~FontOutputDev() {
- Entry *p = cur;
- if (p != beg)
- do {
- --p;
- delete p->pdfFont;
- } while (p != beg);
- gfree(beg);
- }
-
- void FontOutputDev::updateFont(GfxState *state) {
- if (GfxFont* gfxFont = state->getFont()) {
- unsigned n = cur - beg;
- Entry *p = beg;
- while (n > 0) {
- unsigned k = n / 2;
- Entry *q = p + k;
- int cmp = gfxFont->getName()->cmp(q->pdfFont);
- if (cmp > 0) {
- p = q + 1;
- n -= k + 1;
- } else if(cmp != 0)
- n = k;
- else {
- p = q;
- break;
- }
- }
- if (n == 0) {
- if (cur == end) {
- unsigned sz = ((end - beg) * 3) / 2 + 16;
- ptrdiff_t k = cur - beg;
- ptrdiff_t l = p - beg;
- beg = (Entry*)grealloc(beg, sz * sizeof(*beg));
- end = beg + sz;
- cur = beg + k;
- p = beg + l;
- }
-
- double m1, m2;
- int style;
- GfxFontEncoding* encoding;
- GString* pdfFont = new GString(gfxFont->getName());
- const char* xFont = getAFont(gfxFont, encoding, style, m1, m2);
-
- // move entries after the two preceding lines to avoid leaving
- // the object in an incoherent state in case of an exception.
- if (p != cur)
- memmove(p + 1, p, (cur - p) * sizeof(*p));
- p->pdfFont = pdfFont;
- p->xFont = xFont;
- p->style = style;
- p->encoding = encoding == &isoLatin1Encoding ? 0 :
- encoding == &isoLatin2Encoding ? 1 :
- encoding == &symbolEncoding ? 2 : 3;
- p->m = int(100 * m1 + 0.5);
- ++cur;
- }
- }
- }
-
-
- DefaultFontOutputDev::DefaultFontOutputDev() {
- beg = (Entry*)gmalloc((numDefFonts + fontMapSize) * sizeof(*beg));
- end = beg + numDefFonts + fontMapSize;
- Entry* p = beg;
- for (int k = 0; k < fontMapSize; ++k) {
- p->pdfFont = new GString(fontMap[k].pdfFont);
- FontMapEntry* q;
- for (q = userFontMap; q->pdfFont; ++q) {
- if (!strcmp(q->pdfFont, p->pdfFont->getCString()))
- break;
- }
- if (!q || !q->pdfFont)
- q = fontMap + k;
- p->xFont = q->xFont;
- p->m = q->mWidth;
- p->style = q->style;
- p->encoding = q->encoding;
- cur = ++p;
- }
- for (int k = 0; k < numDefFonts; ++k) {
- p->pdfFont = new GString((char*)defFontsNames[k]);
- FontMapEntry* q;
- for (q = userFontMap; q->pdfFont; ++q) {
- if (!strcmp(q->pdfFont, p->pdfFont->getCString()))
- break;
- }
- if (q && q->pdfFont) {
- p->xFont = q->xFont;
- p->m = q->mWidth;
- p->style = q->style;
- p->encoding = q->encoding;
- } else {
- p->xFont = fontSubst[k].xFont;
- p->m = (int)(fontSubst[k].mWidth * 100 + 0.5);
- p->style = fontSubst[k].style;
- p->encoding = /*k >= 12 ? 2 :*/ 0;
- }
- cur = ++p;
- }
- }
-
-