Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 5978 → Rev 5979

/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
## -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