/branches/Version13x/Scribus/scribus/fonts/scface_ttf.cpp |
---|
0,0 → 1,210 |
/* |
For general Scribus (>=1.3.2) copyright and licensing information please refer |
to the COPYING file provided with the program. Following this notice may exist |
a copyright and/or license notice that predates the release of Scribus 1.3.2 |
for which a new license (GPL+exception) is in place. |
*/ |
#include <qfile.h> |
#include <qstring.h> |
#include <qobject.h> |
#include <sys/types.h> |
#include "fonts/scface_ttf.h" |
#include "fonts/scfontmetrics.h" |
#include "util.h" |
#include "scconfig.h" |
namespace { |
uint word(QByteArray const & bb, uint pos) |
{ |
unsigned char * pp = reinterpret_cast<unsigned char*>(bb.data()) + pos; |
return pp[0] << 24 | pp[1] << 16 | pp[2] << 8 | pp[3]; |
} |
uint word16(QByteArray const & bb, uint pos) |
{ |
unsigned char * pp = reinterpret_cast<unsigned char*>(bb.data()) + pos; |
return pp[0] << 8 | pp[1]; |
} |
QString tag(QByteArray const & bb, uint pos) |
{ |
char buf[5] = "1234"; |
buf[0] = bb.data()[pos]; |
buf[1] = bb.data()[pos+1]; |
buf[2] = bb.data()[pos+2]; |
buf[3] = bb.data()[pos+3]; |
return buf; |
} |
bool copy(QByteArray & dst, uint to, QByteArray & src, uint from, uint len) |
{ |
if (!dst.data()) |
return false; |
if (!src.data()) |
return false; |
if (to + len > dst.size()) |
return false; |
if (from + len > src.size()) |
return false; |
memcpy(dst.data() + to, src.data() + from, len); |
return true; |
} |
} //namespace |
void ScFace_ttf::RawData(QByteArray & bb) { |
if (formatCode == ScFace::TTCF) { |
QByteArray coll; |
FtFace::RawData(coll); |
// access table for faceIndex |
if (faceIndex >= static_cast<int>(word(coll, 8))) |
{ |
bb.resize(0); |
return; |
} |
static const uint OFFSET_TABLE_LEN = 12; |
static const uint TDIR_ENTRY_LEN = 16; |
uint faceOffset = word(coll, 12 + 4 * faceIndex); |
uint nTables = word16(coll, faceOffset + 4); |
sDebug(QObject::tr("extracting face %1 from font %2 (offset=%3, nTables=%4)").arg(faceIndex).arg(fontFile).arg(faceOffset).arg(nTables)); |
uint headerLength = OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * nTables; |
uint tableLengths = 0; |
// sum table lengths incl padding |
for (uint i=0; i < nTables; ++i) |
{ |
tableLengths += word(coll, faceOffset + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 12); |
tableLengths = (tableLengths+3) & ~3; |
} |
bb.resize(headerLength + tableLengths); |
if (! bb.data()) |
return; |
// write header |
sDebug(QObject::tr("memcpy header: %1 %2 %3").arg(0).arg(faceOffset).arg(headerLength)); |
if (!copy(bb, 0, coll, faceOffset, headerLength)) |
return; |
uint pos = headerLength; |
for (uint i=0; i < nTables; ++i) |
{ |
uint tableSize = word(coll, faceOffset + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 12); |
uint tableStart = word(coll, faceOffset + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 8); |
sDebug(QObject::tr("table '%1'").arg(tag(coll, tableStart))); |
sDebug(QObject::tr("memcpy table: %1 %2 %3").arg(pos).arg(tableStart).arg(tableSize)); |
if (!copy(bb, pos, coll, tableStart, tableSize)) break; |
// write new offset to table entry |
sDebug(QObject::tr("memcpy offset: %1 %2 %3").arg(OFFSET_TABLE_LEN + TDIR_ENTRY_LEN*i + 8).arg(pos).arg(4)); |
memcpy(bb.data() + OFFSET_TABLE_LEN + TDIR_ENTRY_LEN * i + 8, &pos, 4); |
pos += tableSize; |
// pad |
while ((pos & 3) != 0) |
bb.data()[pos++] = '\0'; |
} |
} |
else if (formatCode == ScFace::TYPE42) { |
FtFace::RawData(bb); |
} |
else { |
FtFace::RawData(bb); |
} |
} |
bool ScFace_ttf::EmbedFont(QString &str) |
{ |
if (formatCode == ScFace::TYPE42) { |
//easy: |
QByteArray bb; |
FtFace::RawData(bb); |
str += bb; |
return true; |
} |
QString tmp4; |
QString tmp2 = ""; |
QString tmp3 = ""; |
int counter = 0; |
char *buf[50]; |
FT_ULong charcode; |
FT_UInt gindex; |
FT_Face face = ftFace(); |
if (!face) { |
return false; |
} |
const FT_Stream fts = face->stream; |
if (ftIOFunc(fts, 0L, NULL, 0)) { |
return(false); |
} |
str+="%!PS-TrueTypeFont\n"; |
str+="11 dict begin\n"; |
str+="/FontName /" + psName + " def\n"; |
str+="/Encoding /ISOLatin1Encoding where {pop ISOLatin1Encoding} {StandardEncoding} ifelse def\n"; |
str+="/PaintType 0 def\n/FontMatrix [1 0 0 1 0 0] def\n"; |
str+="/FontBBox ["+FontBBox+"] def\n"; |
str+="/FontType 42 def\n"; |
str+="/FontInfo 8 dict dup begin\n"; |
str+="/FamilyName (" + psName + ") def\n"; |
str+="end readonly def\n"; |
unsigned char *tmp = new unsigned char[65535]; |
int length; |
char linebuf[80]; |
str += "/sfnts ["; |
int poso=0; |
do { |
int posi=0; |
length= fts->size - fts->pos; |
if (length > 65534) { |
length = 65534; |
} |
if (!ftIOFunc(fts, 0L, tmp, length)) |
{ |
str+="\n<\n"; |
for (int j = 0; j < length; j++) |
{ |
unsigned char u=tmp[posi]; |
linebuf[poso]=((u >> 4) & 15) + '0'; |
if(u>0x9f) linebuf[poso]+='a'-':'; |
++poso; |
u&=15; linebuf[poso]=u + '0'; |
if(u>0x9) linebuf[poso]+='a'-':'; |
++posi; |
++poso; |
if (poso > 70) |
{ |
linebuf[poso++]='\n'; |
linebuf[poso++]=0; |
str += linebuf; |
poso = 0; |
} |
} |
linebuf[poso++]=0; |
str += linebuf; |
poso = 0; |
str += "00\n>"; |
} |
else { |
sDebug(QObject::tr("Font %1 is broken (read stream), no embedding").arg(fontFile).arg(gindex)); |
str += "\n] def\n"; |
status = QMAX(status,ScFace::BROKENGLYPHS); |
return false; |
} |
} while (length==65534); |
str += "\n] def\n"; |
delete tmp; |
gindex = 0; |
charcode = FT_Get_First_Char(face, &gindex ); |
while (gindex != 0) |
{ |
FT_Get_Glyph_Name(face, gindex, buf, 50); |
tmp2 += "/"+QString(reinterpret_cast<char*>(buf))+" "+tmp3.setNum(gindex)+" def\n"; |
charcode = FT_Get_Next_Char(face, charcode, &gindex ); |
counter++; |
} |
tmp4.setNum(counter); |
str += "/CharStrings " + tmp4 + " dict dup begin\n"+tmp2; |
str += "end readonly def\n"; |
str += "FontName currentdict end definefont pop\n"; |
return(true); |
} |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Author Date Id Revision |
\ No newline at end of property |
/branches/Version13x/Scribus/scribus/fonts/scfontmetrics.cpp |
---|
0,0 → 1,612 |
/* |
For general Scribus (>=1.3.2) copyright and licensing information please refer |
to the COPYING file provided with the program. Following this notice may exist |
a copyright and/or license notice that predates the release of Scribus 1.3.2 |
for which a new license (GPL+exception) is in place. |
*/ |
#include <qpainter.h> |
#include <qcolor.h> |
#include <qwmatrix.h> |
#include <qpixmap.h> |
#include <qstringlist.h> |
#include <qmap.h> |
#include <qregexp.h> |
#include "scribusdoc.h" |
#include "scfonts.h" |
#include "style.h" |
#include "scfontmetrics.h" |
#include "scpainter.h" |
#include "fpoint.h" |
#include "fpointarray.h" |
#include "page.h" |
#include "util.h" |
// this code contains a set of font related functions |
// that don't really fit within ScFonts. |
static FPoint firstP; |
static bool FirstM; |
static QMap<FT_ULong, QString> adobeGlyphNames; |
static const char* table[] = { |
//#include "glyphnames.txt.q" |
NULL}; |
// private functions |
static void readAdobeGlyphNames(); |
static QString adobeGlyphName(FT_ULong charcode); |
static int traceMoveto( FT_Vector *to, FPointArray *composite ); |
static int traceLineto( FT_Vector *to, FPointArray *composite ); |
static int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, FPointArray *composite ); |
static int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, FPointArray *composite ); |
FT_Outline_Funcs OutlineMethods = |
{ |
(FT_Outline_MoveTo_Func) traceMoveto, |
(FT_Outline_LineTo_Func) traceLineto, |
(FT_Outline_ConicTo_Func) traceQuadraticBezier, |
(FT_Outline_CubicTo_Func) traceCubicBezier, |
0, |
0 |
}; |
const double FTSCALE = 64.0; |
int setBestEncoding(FT_Face face) |
{ |
FT_ULong charcode; |
FT_UInt gindex; |
bool foundEncoding = false; |
int countUniCode = 0; |
int chmapUniCode = -1; |
int chmapCustom = -1; |
int retVal = 0; |
//FT_CharMap defaultEncoding = face->charmap; |
// int defaultchmap=face->charmap ? FT_Get_Charmap_Index(face->charmap) : 0; |
// Since the above function is only available in FreeType 2.1.10 its replaced by |
// the following line, assuming that the default charmap has the index 0 |
int defaultchmap = 0; |
for(int u = 0; u < face->num_charmaps; u++) |
{ |
if (face->charmaps[u]->encoding == FT_ENCODING_UNICODE ) |
{ |
FT_Set_Charmap(face, face->charmaps[u]); |
chmapUniCode = u; |
gindex = 0; |
charcode = FT_Get_First_Char( face, &gindex ); |
while ( gindex != 0 ) |
{ |
countUniCode++; |
charcode = FT_Get_Next_Char( face, charcode, &gindex ); |
} |
} |
if (face->charmaps[u]->encoding == FT_ENCODING_ADOBE_CUSTOM) |
{ |
chmapCustom = u; |
foundEncoding = true; |
retVal = 1; |
break; |
} |
else if (face->charmaps[u]->encoding == FT_ENCODING_MS_SYMBOL) |
{ |
chmapCustom = u; |
foundEncoding = true; |
retVal = 2; |
break; |
} |
} |
int mapToSet=defaultchmap; |
if (chmapUniCode>0 && countUniCode >= face->num_glyphs-1) |
{ |
mapToSet=chmapUniCode; |
//FT_Set_Charmap(face, face->charmaps[chmapUniCode]); |
retVal = 0; |
} |
else |
if (foundEncoding) |
{ |
mapToSet=chmapCustom; |
//FT_Set_Charmap(face, face->charmaps[chmapCustom]); |
} |
else |
{ |
mapToSet=defaultchmap; |
//FT_Set_Charmap(face, defaultEncoding); |
retVal = 0; |
} |
//Fixes #2199, missing glyphs from 1.2.1->1.2.2 |
//If the currently wanted character map is not already Unicode... |
//if (FT_Get_Charmap_Index(face->charmap)!=chmapUniCode) |
if (mapToSet!=chmapUniCode) |
{ |
//Change map so we can count the chars in it |
FT_Set_Charmap(face, face->charmaps[mapToSet]); |
//Count the characters in the current map |
gindex = 0; |
int countCurrMap=0; |
charcode = FT_Get_First_Char( face, &gindex ); |
while ( gindex != 0 ) |
{ |
countCurrMap++; |
charcode = FT_Get_Next_Char( face, charcode, &gindex ); |
} |
//If the last Unicode map we found before has more characters, |
//then set it to be the current map. |
if (countUniCode>countCurrMap) |
{ |
mapToSet=chmapUniCode; |
//FT_Set_Charmap(face, face->charmaps[chmapUniCode]); |
retVal = 0; |
} |
} |
// if (face->charmap == NULL || mapToSet!=FT_Get_Charmap_Index(face->charmap)) |
FT_Set_Charmap(face, face->charmaps[mapToSet]); |
return retVal; |
} |
FPointArray traceGlyph(FT_Face face, FT_UInt glyphIndex, int chs, double *x, double *y, bool *err) |
{ |
bool error = false; |
//AV: not threadsave, but tracechar is only used in ReadMetrics() and fontSample() |
static FPointArray pts; |
FPointArray pts2; |
pts.resize(0); |
pts2.resize(0); |
firstP = FPoint(0,0); |
FirstM = true; |
error = FT_Set_Char_Size( face, 0, chs*6400, 72, 72 ); |
if (error) |
{ |
*err = error; |
return pts2; |
} |
if (glyphIndex == 0) |
{ |
*err = true; |
return pts2; |
} |
double uniEM = static_cast<double>(face->units_per_EM); |
error = FT_Load_Glyph( face, glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP ); |
if (error) |
{ |
*err = error; |
return pts2; |
} |
error = FT_Outline_Decompose(&face->glyph->outline, &OutlineMethods, reinterpret_cast<void*>(&pts)); |
if (error) |
{ |
*err = error; |
return pts2; |
} |
*x = face->glyph->metrics.horiBearingX / 6400.0; |
*y = face->glyph->metrics.horiBearingY / 6400.0; |
QWMatrix ma; |
ma.scale(0.01, -0.01); |
pts.map(ma); |
pts.translate(0, chs); |
pts2.putPoints(0, pts.size()-2, pts, 0); |
return pts2; |
} |
FPointArray traceChar(FT_Face face, uint chr, int chs, double *x, double *y, bool *err) |
{ |
bool error = false; |
FT_UInt glyphIndex; |
error = FT_Set_Char_Size( face, 0, chs*64, 72, 72 ); |
if (error) |
{ |
*err = error; |
return FPointArray(); |
} |
glyphIndex = FT_Get_Char_Index(face, chr); |
return traceGlyph(face, glyphIndex, chs, x, y, err); |
} |
QPixmap FontSample(ScFace * fnt, int s, QString ts, QColor back, bool force) |
{ |
FT_Face face; |
FT_Library library; |
double x, y, ymax; |
bool error; |
int pen_x; |
FPoint gp; |
error = FT_Init_FreeType( &library ); |
error = FT_New_Face( library, QFile::encodeName(fnt->fontFilePath()), fnt->faceIndex(), &face ); |
int encode = setBestEncoding(face); |
double uniEM = static_cast<double>(face->units_per_EM); |
int h = qRound(face->height / uniEM) * s + 1; |
double a = static_cast<double>(face->descender) / uniEM * s + 1; |
int w = qRound((face->bbox.xMax - face->bbox.xMin) / uniEM) * s * (ts.length()+1); |
if (w < 1) |
w = s * (ts.length()+1); |
if (h < 1) |
h = s; |
QPixmap pm(w, h); |
pm.fill(); |
pen_x = 0; |
ymax = 0.0; |
ScPainter *p = new ScPainter(&pm, pm.width(), pm.height()); |
p->setFillMode(1); |
p->setLineWidth(0.0); |
p->setBrush(back); |
p->drawRect(0.0, 0.0, static_cast<double>(w), static_cast<double>(h)); |
p->setBrush(Qt::black); |
FPointArray gly; |
uint dv; |
dv = ts[0].unicode(); |
error = false; |
gly = traceChar(face, dv, s, &x, &y, &error); |
if (((encode != 0) || (error)) && (!force)) |
{ |
error = false; |
FT_ULong charcode; |
FT_UInt gindex; |
gindex = 0; |
charcode = FT_Get_First_Char(face, &gindex ); |
for (uint n = 0; n < ts.length(); ++n) |
{ |
gly = traceChar(face, charcode, s, &x, &y, &error); |
if (error) |
break; |
if (gly.size() > 3) |
{ |
gly.translate(static_cast<double>(pen_x) / FTSCALE, a); |
gp = getMaxClipF(&gly); |
ymax = QMAX(ymax, gp.y()); |
p->setupPolygon(&gly); |
p->fillPath(); |
} |
pen_x += face->glyph->advance.x; |
charcode = FT_Get_Next_Char(face, charcode, &gindex ); |
if (gindex == 0) |
break; |
} |
} |
else |
{ |
for (uint n = 0; n < ts.length(); ++n) |
{ |
dv = ts[n].unicode(); |
error = false; |
gly = traceChar(face, dv, s, &x, &y, &error); |
if (gly.size() > 3) |
{ |
gly.translate(static_cast<double>(pen_x) / FTSCALE, a); |
gp = getMaxClipF(&gly); |
ymax = QMAX(ymax, gp.y()); |
p->setupPolygon(&gly); |
p->fillPath(); |
} |
pen_x += face->glyph->advance.x; |
} |
} |
p->end(); |
pm.resize(QMIN(qRound(gp.x()), w), QMIN(qRound(ymax), h)); |
delete p; |
FT_Done_FreeType( library ); |
return pm; |
} |
/** Same as FontSample() with \n strings support added. |
09/26/2004 petr vanek |
QPixmap fontSamples(ScFace * fnt, int s, QString ts, QColor back) |
{ |
QStringList lines = QStringList::split("\n", ts); |
QPixmap ret(640, 480); |
QPixmap sample; |
QPainter *painter = new QPainter(&ret); |
int y = 0; |
int x = 0; |
ret.fill(back); |
for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) |
{ |
sample = FontSample(fnt, s, *it, back); |
if (!sample.isNull()) |
painter->drawPixmap(0, y, sample, 0, 0); |
y = y + sample.height(); |
if (x < sample.width()) |
x = sample.width(); |
} // for |
delete(painter); |
QPixmap final(x, y); |
if ((x != 0) && (y != 0)) |
{ |
QPainter *fpainter = new QPainter(&final); |
fpainter->drawPixmap(0, 0, ret, 0, 0, x, y); |
delete(fpainter); |
} |
return final; |
} |
*/ |
bool GlyNames(FT_Face face, QMap<QChar, std::pair<uint, QString> >& GList) |
{ |
bool error; |
char buf[50]; |
FT_ULong charcode; |
FT_UInt gindex; |
setBestEncoding(face); |
gindex = 0; |
charcode = FT_Get_First_Char(face, &gindex ); |
const bool hasPSNames = FT_HAS_GLYPH_NAMES(face); |
if (adobeGlyphNames.empty()) |
readAdobeGlyphNames(); |
while (gindex != 0) |
{ |
bool notfound = true; |
if (hasPSNames) |
notfound = FT_Get_Glyph_Name(face, gindex, &buf, 50); |
// just in case FT gives empty string or ".notdef" |
// no valid glyphname except ".notdef" starts with '.' |
if (notfound || buf[0] == '\0' || buf[0] == '.') |
GList.insert(QChar(static_cast<uint>(charcode)), std::make_pair(gindex,adobeGlyphName(charcode))); |
else |
GList.insert(QChar(static_cast<uint>(charcode)), std::make_pair(gindex,QString(reinterpret_cast<char*>(buf)))); |
charcode = FT_Get_Next_Char(face, charcode, &gindex ); |
} |
return true; |
} |
/* |
bool GlyIndex(ScFace * fnt, QMap<uint, PDFlib::GlNamInd> *GListInd) |
{ |
struct PDFlib::GlNamInd gln; |
bool error; |
char buf[50]; |
FT_Library library; |
FT_Face face; |
FT_ULong charcode; |
FT_UInt gindex; |
uint counter1 = 32; |
uint counter2 = 0; |
error = FT_Init_FreeType(&library); |
error = FT_New_Face(library, QFile::encodeName(fnt->fontFilePath()), fnt->faceIndex(), &face); |
setBestEncoding(face); |
gindex = 0; |
charcode = FT_Get_First_Char(face, &gindex ); |
const bool hasPSNames = FT_HAS_GLYPH_NAMES(face); |
if (adobeGlyphNames.empty()) |
readAdobeGlyphNames(); |
while (gindex != 0) |
{ |
bool notfound = true; |
if (hasPSNames) |
notfound = FT_Get_Glyph_Name(face, gindex, buf, 50); |
// just in case FT gives empty string or ".notdef" |
// no valid glyphname except ".notdef" starts with '.' |
if (notfound || buf[0] == '\0' || buf[0] == '.') |
gln.Name = "/" + adobeGlyphName(charcode); |
else |
gln.Name = "/" + QString(buf); |
gln.Code = counter1 + counter2; |
GListInd->insert(charcode, gln); |
charcode = FT_Get_Next_Char(face, charcode, &gindex ); |
counter1++; |
if (counter1 > 255) |
{ |
counter1 = 32; |
counter2 += 0x100; |
} |
} |
FT_Done_FreeType( library ); |
return true; |
} |
*/ |
static int traceMoveto( FT_Vector *to, FPointArray *composite ) |
{ |
double tox = ( to->x / FTSCALE ); |
double toy = ( to->y / FTSCALE ); |
if (!FirstM) |
{ |
composite->addPoint(firstP); |
composite->addPoint(firstP); |
composite->setMarker(); |
} |
else |
FirstM = false; |
composite->addPoint(tox, toy); |
composite->addPoint(tox, toy); |
firstP.setXY(tox, toy); |
return 0; |
} |
static int traceLineto( FT_Vector *to, FPointArray *composite ) |
{ |
double tox = ( to->x / FTSCALE ); |
double toy = ( to->y / FTSCALE ); |
if ( !composite->hasLastQuadPoint(tox, toy, tox, toy, tox, toy, tox, toy)) |
composite->addQuadPoint(tox, toy, tox, toy, tox, toy, tox, toy); |
return 0; |
} |
static int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, FPointArray *composite ) |
{ |
double x1 = ( control->x / FTSCALE ); |
double y1 = ( control->y / FTSCALE ); |
double x2 = ( to->x / FTSCALE ); |
double y2 = ( to->y / FTSCALE ); |
if ( !composite->hasLastQuadPoint(x2, y2, x1, y1, x2, y2, x2, y2)) |
composite->addQuadPoint(x2, y2, x1, y1, x2, y2, x2, y2); |
return 0; |
} |
static int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, FPointArray *composite ) |
{ |
double x1 = ( p->x / FTSCALE ); |
double y1 = ( p->y / FTSCALE ); |
double x2 = ( q->x / FTSCALE ); |
double y2 = ( q->y / FTSCALE ); |
double x3 = ( to->x / FTSCALE ); |
double y3 = ( to->y / FTSCALE ); |
if ( !composite->hasLastQuadPoint(x3, y3, x2, y2, x3, y3, x3, y3) ) |
{ |
composite->setPoint(composite->size()-1, FPoint(x1, y1)); |
composite->addQuadPoint(x3, y3, x2, y2, x3, y3, x3, y3); |
} |
return 0; |
} |
/// init the Adobe Glyph List |
void readAdobeGlyphNames() { |
adobeGlyphNames.clear(); |
QRegExp pattern("(\\w*);([0-9A-Fa-f]{4})"); |
for (uint i=0; table[i]; ++i) { |
if (pattern.search(table[i]) >= 0) { |
FT_ULong unicode = pattern.cap(2).toULong(0, 16); |
qDebug("%s", QString("reading glyph name %1 fo unicode %2(%3)").arg(pattern.cap(1)).arg(unicode).arg(pattern.cap(2)).ascii()); |
adobeGlyphNames.insert(unicode, pattern.cap(1)); |
} |
} |
} |
/// if in AGL, use that name, else use "uni1234" or "u12345" |
QString adobeGlyphName(FT_ULong charcode) { |
static const char HEX[] = "0123456789ABCDEF"; |
QString result; |
if (adobeGlyphNames.contains(charcode)) |
return adobeGlyphNames[charcode]; |
else if (charcode < 0x10000) { |
result = QString("uni") + HEX[charcode>>12 & 0xF] |
+ HEX[charcode>> 8 & 0xF] |
+ HEX[charcode>> 4 & 0xF] |
+ HEX[charcode & 0xF]; |
} |
else { |
result = QString("u"); |
for (int i= 28; i >= 0; i-=4) { |
if (charcode & (0xF << i)) |
result += HEX[charcode >> i & 0xF]; |
} |
} |
return result; |
} |
/* |
double Cwidth(ScribusDoc *, ScFace* scFace, QString ch, int Size, QString ch2) |
{ |
double width; |
FT_Vector delta; |
FT_Face face; |
uint c1 = ch.at(0).unicode(); |
uint c2 = ch2.at(0).unicode(); |
double size10=Size/10.0; |
if (scFace->canRender(ch[0])) |
{ |
width = scFace->charWidth(ch[0])*size10; |
face = scFace->ftFace(); |
/\**** |
Ok, this looks like a regression between Freetype 2.1.9 -> 2.1.10. |
Ignoring the value of FT_HAS_KERNING for now -- AV |
****\/ |
if (true || FT_HAS_KERNING(face) ) |
{ |
uint cl = FT_Get_Char_Index(face, c1); |
uint cr = FT_Get_Char_Index(face, c2); |
FT_Error error = FT_Get_Kerning(face, cl, cr, FT_KERNING_UNSCALED, &delta); |
if (error) { |
qDebug(QString("Error %2 when accessing kerning pair for font %1").arg(scFace->scName()).arg(error)); |
} |
else { |
double uniEM = static_cast<double>(face->units_per_EM); |
width += delta.x / uniEM * size10; |
} |
} |
else { |
qDebug(QString("Font %1 has no kerning pairs (according to Freetype)").arg(scFace->scName())); |
} |
return width; |
} |
else |
return size10; |
} |
double RealCWidth(ScribusDoc *, ScFace* scFace, QString ch, int Size) |
{ |
double w, ww; |
uint c1 = ch.at(0).unicode(); |
FT_Face face; |
if (scFace->canRender(ch.at(0))) |
{ |
face = scFace->ftFace(); |
uint cl = FT_Get_Char_Index(face, c1); |
int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); |
if (!error) { |
double uniEM = static_cast<double>(face->units_per_EM); |
w = (face->glyph->metrics.width + fabs((double)face->glyph->metrics.horiBearingX)) / uniEM * (Size / 10.0); |
ww = face->glyph->metrics.horiAdvance / uniEM * (Size / 10.0); |
return QMAX(ww, w); |
} |
else |
sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error)); |
} |
return static_cast<double>(Size / 10.0); |
} |
double RealCHeight(ScribusDoc *, ScFace* scFace, QString ch, int Size) |
{ |
double w; |
uint c1 = ch.at(0).unicode(); |
FT_Face face; |
if (scFace->canRender(ch.at(0))) |
{ |
face = scFace->ftFace(); |
uint cl = FT_Get_Char_Index(face, c1); |
int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); |
if (!error) { |
double uniEM = static_cast<double>(face->units_per_EM); |
w = face->glyph->metrics.height / uniEM * (Size / 10.0); |
} |
else { |
sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error)); |
w = Size / 10.0; |
} |
return w; |
} |
else |
return static_cast<double>(Size / 10.0); |
} |
double RealCAscent(ScribusDoc *, ScFace* scFace, QString ch, int Size) |
{ |
double w; |
uint c1 = ch.at(0).unicode(); |
FT_Face face; |
if (scFace->canRender(ch.at(0))) |
{ |
face = scFace->ftFace(); |
uint cl = FT_Get_Char_Index(face, c1); |
int error = FT_Load_Glyph(face, cl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); |
if (! error) { |
double uniEM = static_cast<double>(face->units_per_EM); |
w = face->glyph->metrics.horiBearingY / uniEM * (Size / 10.0); |
} |
else { |
sDebug(QString("internal error: missing glyph: %1 (char %2) error=%3").arg(c1).arg(ch).arg(error)); |
w = Size / 10.0; |
} |
return w; |
} |
else |
return static_cast<double>(Size / 10.0); |
} |
double RealFHeight(ScribusDoc *, ScFace* scFace, int Size) |
{ |
FT_Face face = scFace->ftFace(); |
double uniEM = static_cast<double>(face->units_per_EM); |
return face->height / uniEM * (Size / 10.0); |
} |
*/ |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Author Date Id Revision |
\ No newline at end of property |
/branches/Version13x/Scribus/scribus/fonts/scface.cpp |
---|
0,0 → 1,280 |
#include "scribusapi.h" |
#include "fonts/scface.h" |
double ScFace::ScFaceData::glyphKerning(uint gl1, uint gl2, double sz) const |
{ |
return 0.0; |
} |
bool ScFace::ScFaceData::glyphNames(QMap<QChar, std::pair<uint, QString> >& gList) const |
{ |
return false; |
} |
QMap<QString,QString> ScFace::ScFaceData::fontDictionary(double sz) const |
{ |
return QMap<QString, QString>(); |
} |
GlyphMetrics ScFace::ScFaceData::glyphBBox(uint gl, double sz) const |
{ |
GlyphMetrics res; |
res.width = sz; |
res.ascent = sz; |
res.descent = 0; |
return res; |
} |
double ScFace::ScFaceData::glyphWidth(uint gl, double size) const |
{ |
if (! m_glyphWidth.contains(gl)) { |
loadGlyph(gl); |
} |
return m_glyphWidth[gl] * size; |
} |
FPointArray ScFace::ScFaceData::glyphOutline(uint gl, double sz) const |
{ |
if (! m_glyphWidth.contains(gl)) { |
loadGlyph(gl); |
} |
FPointArray res = m_glyphOutline[gl].Outlines.copy(); |
if (sz != 1.0) |
res.scale(sz, sz); |
return res; |
} |
FPoint ScFace::ScFaceData::glyphOrigin(uint gl, double sz) const |
{ |
if (! m_glyphWidth.contains(gl)) { |
loadGlyph(gl); |
} |
const struct GlyphData & res(m_glyphOutline[gl]); |
return FPoint(res.x, res.y) * sz; |
} |
/***** |
ScFace lifecycle: unchecked -> loaded -> glyphs checked |
| \-> broken glyphs |
\-> broken |
usable() == ! broken |
embeddable() == glyphs_checked |
canRender(unicode) -> CharMap cache? -> loadChar/Glyph -> !broken |
Glyphs: width status |
-1000 unkown |
-2000 broken |
>= 0 ok, outline valid |
CharMap: unicode -> glyph index |
uint[256][256] |
unicode ignores: < 32, ... |
unicode emulate: spaces, hyphen, ligatures?, diacritics? |
*****/ |
ScFace::ScFace() |
{ |
m = new ScFaceData(); |
m->refs = 1; |
m->usage = 0; |
m->status = ScFace::NULLFACE; |
m->typeCode = ScFace::UNKNOWN_TYPE; |
m->formatCode = ScFace::UNKNOWN_FORMAT; |
m->scName = ""; |
m->family = ""; |
m->style = ""; |
m->variant = ""; |
m->psName = ""; |
m->fontFile = "(None)"; |
m->faceIndex = -1; |
m->forDocument = ""; |
m->usable = false; |
m->embedPs = false; |
m->subset = false; |
m->maxGlyph = 0; |
m->cachedStatus = ScFace::UNKNOWN; |
} |
ScFace::ScFace(ScFaceData* data) |
{ |
m = data; |
m->refs = 1; |
m->cachedStatus = ScFace::UNKNOWN; |
} |
ScFace::ScFace(const ScFace& other) |
{ |
m = other.m; |
++(m->refs); |
} |
ScFace::~ScFace() |
{ |
if ( m && --(m->refs) == 0 ) { |
m->unload(); |
delete m; |
m = 0; |
} |
} |
ScFace& ScFace::operator=(const ScFace& other) |
{ |
++(other.m->refs); |
if ( m && --(m->refs) == 0 ) { |
m->unload(); |
delete m; |
} |
m = other.m; |
} |
/** two ScFaces are equal if they either are both NULLFACEs or they |
agree on family, style, variant and fontpath |
*/ |
bool ScFace::operator==(const ScFace& other) const |
{ |
return ( (isNone() && other.isNone() ) |
|| (m == other.m) |
|| (m->family == other.m->family |
&& m->style == other.m->style |
&& m->variant == other.m->variant |
&& m->fontFile == other.m->fontFile |
&& m-> faceIndex == other.m->faceIndex) ); |
} |
const ScFace& ScFace::none() |
{ |
static ScFace NONE; |
return NONE; |
} |
void ScFace::increaseUsage() const |
{ |
m->usage++; |
} |
void ScFace::decreaseUsage() const |
{ |
if (m->usage == 1) |
unload(); |
m->usage--; |
} |
void ScFace::unload() const |
{ |
if (m->status >= ScFace::LOADED && usable()) { |
m->unload(); |
} |
// clear caches |
m->m_glyphWidth.clear(); |
m->m_glyphOutline.clear(); |
m->m_cMap.clear(); |
m->status = ScFace::UNKNOWN; |
} |
uint ScFace::char2CMap(QChar ch) const |
{ |
if (m->status == ScFace::UNKNOWN) { |
m->load(); |
} |
return m->char2CMap(ch); |
} |
bool ScFace::canRender(QChar ch) const |
{ |
if (!usable()) |
return false; |
else if (ch.unicode() < 32) { |
return ch.unicode() == 28 || ch.unicode() == 13 || ch.unicode() == 9; |
} |
else { |
uint gl = char2CMap(ch); // calls load() |
if (gl != 0) { |
m->loadGlyph(gl); |
return ! m->m_glyphOutline[gl].broken; |
} |
else { |
return false; |
} |
} |
} |
double ScFace::charWidth(QChar ch, double size, QChar ch2) const |
{ |
if (!canRender(ch)) // calls loadGlyph() |
return size; |
else if (ch.unicode() == 28 || ch.unicode() == 13 || ch.unicode() == 9) |
return ch.unicode() == 9 ? 1.0 : 0.0; |
else { |
uint gl1 = char2CMap(ch); |
uint gl2 = ch2.unicode() != 32 ? char2CMap(ch2) : 0; |
double width = glyphWidth(gl1, size); |
if (gl2 != 0) |
width += glyphKerning(gl1, gl2, size); |
// qDebug(QString("scface::glyphkerning: %1_%2 = %3 (%4, %5)").arg(ch).arg(ch2).arg(glyphKerning(gl1, gl2,size)).arg(gl1).arg(gl2)); |
return width; |
} |
} |
bool ScFace::EmbedFont(QString &str) |
{ |
if (m->status == ScFace::UNKNOWN) { |
m->load(); |
} |
return m->EmbedFont(str); |
} |
bool ScFace::glyphNames(QMap<QChar, std::pair<uint, QString> >& gList) |
{ |
if (m->status == ScFace::UNKNOWN) { |
m->load(); |
} |
return m->glyphNames(gList); |
} |
void ScFace::RawData(QByteArray & bb) |
{ |
if (m->status == ScFace::UNKNOWN) { |
m->load(); |
} |
m->RawData(bb); |
} |
void ScFace::checkAllGlyphs() |
{ |
if (m->status == ScFace::UNKNOWN) { |
m->load(); |
} |
if (m->status != ScFace::LOADED) { |
return; |
} |
for (uint gl=0; gl <= m->maxGlyph; ++gl) { |
if (! m->m_glyphWidth.contains(gl)) { |
m->loadGlyph(gl); |
m->m_glyphWidth.remove(gl); |
m->m_glyphOutline.remove(gl); |
} |
} |
} |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Author Date Id Revision |
\ No newline at end of property |
/branches/Version13x/Scribus/scribus/fonts/scface_ps.cpp |
---|
___________________________________________________________________ |
Added: svn:eol-style |
## -0,0 +1 ## |
+native |
\ No newline at end of property |
Added: svn:keywords |
## -0,0 +1 ## |
+Author Date Id Revision |
\ No newline at end of property |
/branches/Version13x/Scribus/scribus/fonts/scface_ttf.h |
---|
0,0 → 1,31 |
/* |
For general Scribus (>=1.3.2) copyright and licensing information please refer |
to the COPYING file provided with the program. Following this notice may exist |
a copyright and/or license notice that predates the release of Scribus 1.3.2 |
for which a new license (GPL+exception) is in place. |
*/ |
#ifndef SCFACE_TTF_H |
#define SCFACE_TTF_H |
#include "scribusapi.h" |
#include "fonts/ftface.h" |
/* |
Class ScFace_ttf |
Subclass of ScFace, specifically for TrueType fonts. |
Implements: RealName() and EmbedFont(). |
*/ |
class SCRIBUS_API ScFace_ttf : public FtFace |
{ |
public: |
ScFace_ttf(QString fam, QString sty, QString alt, QString scname, QString psname, QString path, int face) |
: FtFace(fam, sty, alt, scname, psname, path, face ) |
{ |
formatCode = ScFace::SFNT; |
} |
bool EmbedFont(QString &str); |
void RawData(QByteArray & bb); |
}; |
#endif |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Author Date Id Revision |
\ No newline at end of property |
/branches/Version13x/Scribus/scribus/fonts/scfontmetrics.h |
---|
0,0 → 1,36 |
/* |
For general Scribus (>=1.3.2) copyright and licensing information please refer |
to the COPYING file provided with the program. Following this notice may exist |
a copyright and/or license notice that predates the release of Scribus 1.3.2 |
for which a new license (GPL+exception) is in place. |
*/ |
#ifndef SCFONTMETRICS_H |
#define SCFONTMETRICS_H |
#include <utility> |
#include <qglobal.h> |
#include <qstring.h> |
#include <qcolor.h> |
#include <ft2build.h> |
#include FT_FREETYPE_H |
#include FT_OUTLINE_H |
#include FT_GLYPH_H |
#include "scribusapi.h" |
#include "fpoint.h" |
#include "fpointarray.h" |
class ScFace; |
class Scribusdoc; |
int SCRIBUS_API setBestEncoding(FT_Face face); |
FPointArray SCRIBUS_API traceChar(FT_Face face, uint chr, int chs, double *x, double *y, bool *err); |
FPointArray SCRIBUS_API traceGlyph(FT_Face face, uint chr, int chs, double *x, double *y, bool *err); |
QPixmap SCRIBUS_API FontSample(const ScFace& fnt, int s, QString ts, QColor back, bool force = false); |
//QPixmap SCRIBUS_API fontSamples(const ScFace& fnt, int s, QString ts, QColor back); |
bool SCRIBUS_API GlyNames(FT_Face face, QMap<QChar, std::pair<uint, QString> >& GList); |
//bool SCRIBUS_API GlyIndex(ScFace * fnt, QMap<uint, PDFlib::GlNamInd> *GListInd); |
#endif |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Author Date Id Revision |
\ No newline at end of property |
/branches/Version13x/Scribus/scribus/fonts/scface.h |
---|
0,0 → 1,340 |
#ifndef SC_FACE_H |
#define SC_FACE_H |
/* ScFace responsibilities: |
font storage: type, format, filepath, index, document-local, substitute, etc. |
usage: use, embed, subset, ... |
face info: family, effect, alternative, flags, charset |
encoding: CMap2String, glyphnames, |
metrics: cwidth, bearing, bbox, "real" widths, paths |
opentype: apply features, script support (-) |
embedding: fontdictionary, rawdata, embedPS, embedPDF, subsetPS, subsetPDF |
virtual: dispatch to constituents, handle embedding (-) |
*/ |
#include <qstring.h> |
#include <qvector.h> |
#include <qmap.h> |
#include <qarray.h> |
#include <utility> |
#include "fpointarray.h" |
struct GlyphMetrics { |
double width; |
double ascent; |
double descent; |
}; |
/*! \brief Base Class ScFace : This is a total rewrite of the old Foi class. |
It uses a shared private implementation which must be a subclass of ScFontData. |
ScFace objects are quite small and can be handled like value objects. Reference |
counting ensures that the shared data is freed when the last ScFace object is |
destructed. |
ScFaceData has caches for face and glyph data. load() fills those caches for |
face data, loadGlyph() fills the cache for glyphs. caches are always filled by |
need, so you can call unload() any time (well, better not multithreaded...) |
without producing errors. the increaseUsage() and decreaseUsage() keep track |
of at how many places a face is used and automatically unload when the count |
reaches zero. |
Other data is recalculated on demand. The implementation can choose to do its |
own caching for this data. |
ScFace uses a sophisticated lifecycle which controls the state of initialisation |
and the performed checks. the normal lilecycle goes: |
UNKNOWN --load()--> LOADED --checkAllGlyphs()--> CHECKED |
If the face can not be loaded, the status changes to BROKEN. |
If only some glyphs can not be loaded, the status changes to |
BROKENGLYPHS. These fonts can still be used and subsetted(outlined), |
but not embedded. |
ScFace constructors are only accessible to the ScFonts class which does |
some checking before creating a new ScFace. These checks are recorded |
in a cache and only reexecuted if the font file changes. |
The field 'cachedStatus' allows load() to switch directly to one of the |
states BROKEN, CHECKED or BROKENGLYPHS if this state was reached during a |
previous run of Scribus. |
*/ |
class SCRIBUS_API ScFace |
{ |
public: |
enum Status { UNKNOWN, LOADED, CHECKED, BROKENGLYPHS, BROKEN, NULLFACE }; |
enum FontType { TYPE0, TYPE1, TYPE3, TTF, CFF, OTF, UNKNOWN_TYPE }; |
enum FontFormat { PFA, PFB, TYPE2, TYPE42, |
// handled by freetype: PFB_MAC, DFONT, HQX, MACBIN, |
SFNT, TTCF, UNKNOWN_FORMAT }; |
struct GlyphData { |
FPointArray Outlines; |
double x; |
double y; |
bool broken; |
GlyphData() : Outlines(), x(0), y(0), broken(true) {} |
}; |
/// see accessors for ScFace for docs |
struct ScFaceData { |
/// controls destruction |
mutable int refs; |
/// controls load() |
mutable int usage; |
QString scName; |
QString fontFile; |
int faceIndex; |
QString psName; |
QString family; |
QString style; |
QString variant; |
QString forDocument; |
mutable ScFace::Status status; |
ScFace::FontType typeCode; |
ScFace::FontFormat formatCode; |
bool usable; |
bool embedPs; |
bool subset; |
bool isStroked; |
bool isFixedPitch; |
bool hasNames; |
uint maxGlyph; |
virtual ~ScFaceData() { }; |
protected: |
friend class ScFace; |
Status cachedStatus; |
// caches |
mutable QMap<uint,double> m_glyphWidth; |
mutable QMap<uint,GlyphData> m_glyphOutline; |
mutable QMap<uint, uint> m_cMap; |
// fill caches & members |
virtual void load() const |
{ |
m_glyphWidth.clear(); |
m_glyphOutline.clear(); |
m_cMap.clear(); |
status = QMAX(cachedStatus, ScFace::LOADED); |
} |
virtual void unload() const |
{ |
m_glyphWidth.clear(); |
m_glyphOutline.clear(); |
m_cMap.clear(); |
status = ScFace::UNKNOWN; |
} |
virtual void loadGlyph(uint gl) const {} |
// dummy implementations |
virtual double ascent(double sz) const { return sz; } |
virtual double descent(double sz) const { return 0.0; } |
virtual double xHeight(double sz) const { return sz; } |
virtual double capHeight(double sz) const { return sz; } |
virtual double height(double sz) const { return sz; } |
virtual double strikeoutPos(double sz) const { return sz / 2; } |
virtual double underlinePos(double sz) const { return -1.0; } |
virtual double strokeWidth(double sz) const { return 0.1; } |
virtual double maxAdvanceWidth(double sz) const { return sz; } |
virtual uint char2CMap(QChar ch) const { return 0; } |
virtual double glyphKerning(uint gl1, uint gl2, double sz) const; |
virtual QMap<QString,QString> fontDictionary(double sz=1.0) const; |
virtual GlyphMetrics glyphBBox(uint gl, double sz) const; |
virtual bool EmbedFont(QString &str) const { return false; } |
virtual void RawData(QByteArray & bb) const {} |
virtual bool glyphNames(QMap<QChar, std::pair<uint, QString> >& gList) const; |
// these use the cache: |
virtual double glyphWidth(uint gl, double sz) const; |
virtual FPointArray glyphOutline(uint gl, double sz) const; |
virtual FPoint glyphOrigin (uint gl, double sz) const; |
}; |
ScFace(); |
ScFace(const ScFace& other); |
~ScFace(); |
/// used as a null object |
static const ScFace& none(); |
/// test for null object |
bool isNone() const { return m->status == NULLFACE; } |
ScFace& operator=(const ScFace& other); |
/** two ScFaces are equal if they either are both NULLFACEs or they |
agree on family, style, variant and fontpath |
*/ |
bool operator==(const ScFace& other) const ; |
bool operator!=(const ScFace& other) const { return ! (*this == other); } |
bool EmbedFont(QString &str); |
void RawData(QByteArray & bb); |
bool glyphNames(QMap<QChar, std::pair<uint, QString> >& gList); |
/// prevent unloading of face data |
void increaseUsage() const; |
/// unload face data if not used any more |
void decreaseUsage() const; |
/// unload face data. It will be reloaded on need |
void unload() const; |
/// the name Scribus uses for this font |
QString scName() const { return m->scName; } |
/// the name PostScript uses for this font |
QString psName() const { return m->psName; } |
/// the physical location of the fontfile |
QString fontPath() const { return m->faceIndex >= 0 ? QString("%1(%2)").arg(m->fontFile).arg(m->faceIndex+1) : m->fontFile; } |
/// the file path of the fontfile |
QString fontFilePath() const { return m->fontFile; } |
/// if the fontfile contains more than one face, the index, else -1 |
int faceIndex() const { return m->faceIndex; } |
/// path name of the document this face is local to |
QString localForDocument() const { return m->forDocument; } |
/// font type, eg. Type1 or TTF |
FontType type() const { return m->typeCode; } |
/// font format, which might be a little more complicated |
FontFormat format()const { return m->formatCode; } |
/// test if this face can be used in documents |
bool usable() const { return m->usable && !isNone(); } |
/// test if this face can be embedded in PS/PDF |
bool embedPs() const { return m->embedPs && m->status < BROKENGLYPHS; } |
/// test if this face can be embedded as outlines in PS/PDF |
bool subset() const { return m->subset && m->status < BROKEN; } |
void usable(bool flag) { m->usable = flag; } |
void embedPs(bool flag) { m->embedPs = flag; } |
void subset(bool flag) { m->subset = flag; } |
/// deprecated? tells if the face has PS names |
bool hasNames() const { return m->hasNames; } |
/// tells if this font is an outline font |
bool isStroked() const { return m->isStroked; } |
/// tells if this font is a fixed pitch font |
bool isFixedPitch()const { return m->isFixedPitch; } |
/// tells if this is an OTF/CFF font |
bool isOTF() const { return m->typeCode == OTF; } |
/// returns the highest glyph index in this face |
uint maxGlyph() const { return m->maxGlyph; } |
/// returns the font family as seen by Scribus |
QString family() const { return m->family; } |
/// returns the font style as seen by Scribus (eg. bold, Italic) |
QString style() const { return m->style; } |
/// returns an additional discriminating String for this face |
QString variant() const { return m->variant; } |
// font metrics |
double ascent(double sz=1.0) const { return m->ascent(sz); } |
double descent(double sz=1.0) const { return m->descent(sz); } |
double xHeight(double sz=1.0) const { return m->xHeight(sz); } |
double capHeight(double sz=1.0) const { return m->capHeight(sz); } |
double height(double sz=1.0) const { return m->height(sz); } |
double strikeoutPos(double sz=1.0) const { return m->strikeoutPos(sz); } |
double underlinePos(double sz=1.0) const { return m->underlinePos(sz); } |
double strokeWidth(double sz=1.0) const { return m->strokeWidth(sz); } |
double maxAdvanceWidth(double sz=1.0) const { return m->maxAdvanceWidth(sz); } |
/// deprecated |
QString stemV(double sz=1.0) const { return fontDictionary(sz)["/StemV"]; } |
/// deprecated |
QString italicAngle(double sz=1.0) const { return fontDictionary(sz)["/ItalicAngle"]; } |
/// deprecated |
QString fontBBox(double sz=1.0) const { return fontDictionary(sz)["/FontBBox"]; } |
/// returns a map of values used for font dictionaries in PS/PDF |
QMap<QString,QString> fontDictionary(double sz=1.0) const { return m->fontDictionary(sz); } |
// glyph interface |
/// returns the glyphs normal advance width at size 'sz' |
double glyphWidth(uint gl, double sz=1.0) const { return m->glyphWidth(gl, sz); } |
/// returns the glyph kerning between 'gl1' and 'gl2' at size 'sz' |
double glyphKerning(uint gl1, uint gl2, double sz=1.0) const { return m->glyphKerning(gl1, gl2, sz); } |
/// returns the glyphs bounding box at size 'sz', ie. the area where this glyph will produce marks |
GlyphMetrics glyphBBox(uint gl, double sz=1.0) const { return m->glyphBBox(gl, sz); } |
/// returns the glyph's outline as a cubic Bezier path |
FPointArray glyphOutline(uint gl, double sz=1.0) const { return m->glyphOutline(gl, sz); } |
/// returns the glyph's origin FIXME: what's that exactly? |
FPoint glyphOrigin(uint gl, double sz=1.0) const { return m->glyphOrigin(gl, sz); } |
// char interface |
/// test if the face can render this char |
bool canRender(QChar ch) const; |
/// translate unicode to glyph index |
uint char2CMap(QChar ch) const; |
/// returns the combined glyph width and kerning for 'ch' if followed by 'ch2' |
double charWidth(QChar ch, double sz=1.0, QChar ch2 = QChar(32)) const; |
/// deprecated, see glyphBBox() |
double realCharWidth(QChar ch, double sz=1.0) const { return glyphBBox(char2CMap(ch),sz).width; } |
/// deprecated, see glyphBBox() |
double realCharHeight(QChar ch, double sz=1.0) const { GlyphMetrics gm=glyphBBox(char2CMap(ch),sz); return gm.ascent + gm.descent; } |
/// deprecated, see glyphBBox() |
double realCharAscent(QChar ch, double sz=1.0) const { return glyphBBox(char2CMap(ch),sz).ascent; } |
/// deprecated, see glyphBBox() |
double realCharDescent(QChar ch, double sz=1.0) const { return glyphBBox(char2CMap(ch),sz).descent; } |
private: |
friend class SCFonts; |
ScFace(ScFaceData* md); |
ScFaceData* m; |
void initFaceData(); |
void checkAllGlyphs(); |
}; |
#endif |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Author Date Id Revision |
\ No newline at end of property |
/branches/Version13x/Scribus/scribus/fonts/scface_ps.h |
---|
0,0 → 1,235 |
/* |
For general Scribus (>=1.3.2) copyright and licensing information please refer |
to the COPYING file provided with the program. Following this notice may exist |
a copyright and/or license notice that predates the release of Scribus 1.3.2 |
for which a new license (GPL+exception) is in place. |
*/ |
#ifndef SCFACE_PS_H |
#define SCFACE_PS_H |
#include <qstring.h> |
#include <qstrlist.h> |
#include <qstringlist.h> |
#include <qdict.h> |
#include <qfont.h> |
#include <qmap.h> |
#include <ft2build.h> |
#include FT_FREETYPE_H |
#include FT_OUTLINE_H |
#include FT_GLYPH_H |
#include "scribusapi.h" |
#include "fpointarray.h" |
#include "scconfig.h" |
/* |
Class ScFace_postscript |
Subclass of ScFace, for PostScript fonts that could possibly have a .afm file |
associated with them for metrics information. |
*/ |
class ScFace_postscript : public FtFace |
{ |
public: |
ScFace_postscript(QString fam, QString sty, QString alt, QString scname, QString psname, QString path, int face) : |
FtFace(fam,sty,alt,scname,psname,path,face) |
{ |
isFixedPitch = false; |
typeCode = ScFace::TYPE1; |
} |
virtual void load() // routine by Franz Schmid - modified by Alastair M. Robinson |
{ |
ScFaceData::load(); |
bool error; |
FT_Face face = ftFace(); |
if (!face) |
{ |
usable = false; |
qDebug(QObject::tr("Font %1 is broken (no Face), discarding it").arg(fontFile)); |
return; |
} |
QString afnm = fontFile.left(fontFile.length()-3); |
QFile afm(afnm+"afm"); |
if(!(afm.exists())) |
{ |
afm.setName(afnm+"Afm"); |
} |
if(!(afm.exists())) |
{ |
afm.setName(afnm+"AFM"); |
} |
if(!(afm.exists())) |
{ |
afm.setName(afnm+"pfm"); |
} |
if(!(afm.exists())) |
{ |
afm.setName(afnm+"Pfm"); |
} |
if(!(afm.exists())) { |
afm.setName(afnm+"PFM"); |
} |
if (afm.exists()) |
error = FT_Attach_File(face, afm.name()); |
// Ascent = tmp.setNum(face->ascender); |
// Descender = tmp.setNum(face->descender); |
// CapHeight = Ascent; |
// ItalicAngle = "0"; |
// StdVW = "1"; |
// FontBBox = tmp.setNum(face->bbox.xMin)+" "+tmp2.setNum(face->bbox.yMin)+" "+tmp3.setNum(face->bbox.xMax)+" "+tmp4.setNum(face->bbox.yMax); |
/* |
setBestEncoding(face); |
gindex = 0; |
charcode = FT_Get_First_Char( face, &gindex ); |
int goodGlyph = 0; |
int invalidGlyph = 0; |
while ( gindex != 0 ) |
{ |
error = FT_Load_Glyph( face, gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); |
if (error) |
{ |
++invalidGlyph; |
sDebug(QObject::tr("Font %1 has broken glyph %2 (charcode %3)").arg(fontPath()).arg(gindex).arg(charcode)); |
charcode = FT_Get_Next_Char( face, charcode, &gindex ); |
continue; |
} |
++goodGlyph; |
double ww = face->glyph->metrics.horiAdvance / uniEM; |
if (face->glyph->format == FT_GLYPH_FORMAT_PLOTTER) |
isStroked = true; |
error = false; |
outlines = traceChar(face, charcode, 10, &x, &y, &error); |
if (!error) |
{ |
CharWidth.insert(charcode, ww); |
GRec.Outlines = outlines.copy(); |
GRec.x = x; |
GRec.y = y; |
GlyphArray.insert(charcode, GRec); |
} |
charcode = FT_Get_Next_Char( face, charcode, &gindex ); |
} |
*/ |
} |
}; |
/* |
Class ScFace_pfb |
Subclass of ScFace, specifically for Adobe type 1 .pfb fonts. |
Implements: RealName() and EmbedFont(). |
*/ |
class ScFace_pfb : public ScFace_postscript |
{ |
public: |
ScFace_pfb(QString fam, QString sty, QString alt, QString scname, QString psname, QString path, int face) : |
ScFace_postscript(fam,sty,alt,scname,psname,path,face) |
{ |
formatCode = ScFace::PFB; |
} |
virtual bool EmbedFont(QString &str) |
{ |
QByteArray bb; |
RawData(bb); |
QString tmp2 = ""; |
if ((bb.size() > 2) && (bb[0] == char(0x80)) && (static_cast<int>(bb[1]) == 1)) |
{ |
QString tmp3=""; |
QString tmp4 = ""; |
uint posi,cxxc=0; |
for (posi = 6; posi < bb.size(); ++posi) |
{ |
if ((bb[posi] == char(0x80)) && (posi+1 < bb.size()) && (static_cast<int>(bb[posi+1]) == 2)) |
break; |
str += bb[posi]; |
} |
uint ulen; |
if (posi+6 < bb.size()) |
{ |
ulen = bb[posi+2] & 0xff; |
ulen |= (bb[posi+3] << 8) & 0xff00; |
ulen |= (bb[posi+4] << 16) & 0xff0000; |
ulen |= (bb[posi+5] << 24) & 0xff000000; |
posi += 6; |
if (posi + ulen > bb.size()) |
ulen = bb.size() - posi - 1; |
char linebuf[80]; |
cxxc=0; |
for (uint j = 0; j < ulen; ++j) |
{ |
unsigned char u=bb[posi]; |
linebuf[cxxc]=((u >> 4) & 15) + '0'; |
if(u>0x9f) linebuf[cxxc]+='a'-':'; |
++cxxc; |
u&=15; linebuf[cxxc]=u + '0'; |
if(u>0x9) linebuf[cxxc]+='a'-':'; |
++posi; |
++cxxc; |
if (cxxc > 72) |
{ |
linebuf[cxxc++]='\n'; |
linebuf[cxxc++]=0; |
str += linebuf; |
cxxc = 0; |
} |
} |
linebuf[cxxc]=0; |
str += linebuf; |
str += "\n"; |
} |
posi += 6; |
for (uint j = posi; j < bb.size(); ++j) |
{ |
if ((bb[j] == static_cast<char>(0x80)) && (j+1 < bb.size()) && (static_cast<int>(bb[j+1]) == 3)) |
break; |
if(bb[j]=='\r') |
str+="\n"; |
else |
str += bb[j]; |
} |
str += "\n"; |
cxxc = 0; |
return true; |
} |
else |
{ |
qDebug(QObject::tr("Font %1 cannot be read, no embedding").arg(fontFile)); |
return false; |
} |
} |
}; |
/* |
Class ScFace_pfa |
Subclass of ScFace, specifically for Adobe type 1 and type 3 .pfa fonts. |
Implements: RealName() and EmbedFont(). |
*/ |
class ScFace_pfa : public ScFace_postscript |
{ |
public: |
ScFace_pfa(QString fam, QString sty, QString alt, QString scname, QString psname, QString path, int face) : |
ScFace_postscript(fam,sty,alt,scname,psname,path,face) |
{ |
formatCode = ScFace::PFA; |
} |
virtual bool EmbedFont(QString &str) |
{ |
QByteArray bb; |
RawData(bb); |
if (bb.size() > 2 && bb[0] == '%' && bb[1] == '!') |
{ |
// this is ok since bb will not contain '\0' |
str.append(bb); |
return true; |
} |
return false; |
} |
}; |
#endif |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Author Date Id Revision |
\ No newline at end of property |
/branches/Version13x/Scribus/scribus/fonts/CMakeLists.txt |
---|
0,0 → 1,16 |
INCLUDE_DIRECTORIES( |
${CMAKE_SOURCE_DIR} |
${CMAKE_SOURCE_DIR}/scribus |
) |
SET(SCRIBUS_FONTS_LIB_SOURCES |
scface.cpp |
ftface.cpp |
scface_ps.cpp |
scface_ttf.cpp |
scfontmetrics.cpp |
) |
SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") |
ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |
Added: svn:keywords |
+Author Date Id Revision |
\ No newline at end of property |