Subversion Repositories Scribus

Compare Revisions

Ignore whitespace Rev 5979 → Rev 5980

/branches/Version13x/Scribus/scribus/fonts/ftface.cpp
0,0 → 1,296
 
#include "fonts/ftface.h"
 
#include FT_OUTLINE_H
#include FT_GLYPH_H
 
#include <qobject.h>
#include <qfile.h>
 
#include "scfonts.h"
#include "fonts/scfontmetrics.h"
 
// static:
FT_Library FtFace::library = NULL;
 
/*****
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?
*****/
 
FtFace::FtFace(QString fam, QString sty, QString vari, QString scname,
QString psname, QString path, int face)
: ScFaceData(), m_face(NULL)
{
family = fam;
style = sty;
variant = vari;
scName = scname;
psName = psname;
fontFile = path;
faceIndex = face;
if (!library) {
if (FT_Init_FreeType( &library ))
qDebug(QObject::tr("Freetype2 library not available"));
}
}
 
 
FtFace::~FtFace() {
unload();
}
 
 
FT_Face FtFace::ftFace() const {
if (!m_face) {
if (FT_New_Face( library, QFile::encodeName(fontFile), faceIndex, & m_face )) {
status = ScFace::BROKEN;
m_face = NULL;
qDebug(QObject::tr("Font %1(%2) is broken").arg(fontFile).arg(faceIndex));
}
else {
load();
}
}
return m_face;
}
 
void FtFace::load() const
{
ScFaceData::load();
 
if (!m_face) {
if (FT_New_Face( library, QFile::encodeName(fontFile), faceIndex, & m_face )) {
status = ScFace::BROKEN;
m_face = NULL;
qDebug(QObject::tr("Font %1(%2) is broken").arg(fontFile).arg(faceIndex));
return;
}
}
const_cast<FtFace*>(this)->isStroked = false;
m_encoding = 0;
m_uniEM = static_cast<double>(m_face->units_per_EM);
 
m_descent = m_face->descender / m_uniEM;
m_ascent = m_face->ascender / m_uniEM;
m_height = m_face->height / m_uniEM;
m_xHeight = m_height;
m_capHeight = m_height;
m_maxAdvanceWidth = m_face->max_advance_width / m_uniEM;
m_underlinePos = m_face->underline_position / m_uniEM;
m_strikeoutPos = m_ascent / 3;
m_strokeWidth = m_face->underline_thickness / m_uniEM;
const_cast<FtFace*>(this)->isFixedPitch = m_face->face_flags & 4;
 
//FIXME: FT_Set_Charmap(m_face, m_face->charmaps[m_encoding]);
setBestEncoding(m_face);
FT_UInt gindex = 0;
FT_ULong charcode = FT_Get_First_Char( m_face, &gindex );
int goodGlyph = 0;
int invalidGlyph = 0;
bool error;
while ( gindex != 0 )
{
error = FT_Load_Glyph( m_face, gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
if (error)
{
++invalidGlyph;
qDebug(QObject::tr("Font %1 has broken glyph %2 (charcode %3)").arg(fontFile).arg(gindex).arg(charcode));
charcode = FT_Get_Next_Char( m_face, charcode, &gindex );
continue;
}
if (gindex > maxGlyph)
const_cast<FtFace*>(this)->maxGlyph = gindex;
++goodGlyph;
if (m_face->glyph->format == FT_GLYPH_FORMAT_PLOTTER)
const_cast<FtFace*>(this)->isStroked = true;
charcode = FT_Get_Next_Char( m_face, charcode, &gindex );
}
if (invalidGlyph > 0) {
status = ScFace::BROKENGLYPHS;
}
}
 
 
void FtFace::unload() const
{
if (m_face) {
FT_Done_Face( m_face );
m_face = NULL;
}
// clear caches
ScFaceData::unload();
}
 
 
uint FtFace::char2CMap(QChar ch) const
{
// FIXME use cMap cache
FT_Face face = ftFace();
uint gl = FT_Get_Char_Index(face, ch.unicode());
return gl;
}
 
 
void FtFace::loadGlyph(uint gl) const
{
ScFace::GlyphData GRec;
FT_Face face = ftFace();
if (FT_Load_Glyph( face, gl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ))
{
qDebug(QObject::tr("Font %1 has broken glyph %2").arg(fontFile).arg(gl));
m_glyphWidth[gl] = 1;
}
else {
double ww = face->glyph->metrics.horiAdvance / m_uniEM;
double x, y;
bool error = false;
FPointArray outlines = traceGlyph(face, gl, 10, &x, &y, &error);
if (!error)
{
m_glyphWidth[gl] = ww;
GRec.Outlines = outlines;
GRec.x = x;
GRec.y = y;
GRec.broken = false;
}
else {
m_glyphWidth[gl] = 1;
}
}
m_glyphOutline[gl] = GRec;
if (GRec.broken && status < ScFace::BROKENGLYPHS)
status = ScFace::BROKENGLYPHS;
}
 
 
double FtFace::glyphKerning(uint gl, uint gl2, double size) const
{
FT_Vector delta;
FT_Face face = ftFace();
double result = 0;
/****
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) )
{
FT_Error error = FT_Get_Kerning(face, gl, gl2, FT_KERNING_UNSCALED, &delta);
if (error) {
qDebug(QString("Error %2 when accessing kerning pair for font %1").arg(scName).arg(error));
}
else {
result = delta.x / m_uniEM * size;
}
}
else {
qDebug(QString("Font %1 has no kerning pairs (according to Freetype)").arg(scName));
}
return result;
}
 
 
GlyphMetrics FtFace::glyphBBox (uint gl, double sz) const
{
FT_Face face = ftFace();
GlyphMetrics result;
FT_Error error = FT_Load_Glyph( face, gl, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
if (!error) {
double w = (face->glyph->metrics.width + QABS((double)face->glyph->metrics.horiBearingX)) / m_uniEM * sz;
result.width = QMAX(w, face->glyph->metrics.horiAdvance / m_uniEM * sz);
double height = face->glyph->metrics.height / m_uniEM * sz;
result.ascent = face->glyph->metrics.horiBearingY / m_uniEM * sz;
result.descent = result.ascent - height;
}
else {
result.width = result.ascent = sz;
result.descent = 0;
}
return result;
}
 
/// copied from Freetype's FT_Stream_ReadAt()
FT_Error ftIOFunc( FT_Stream stream, unsigned long pos, unsigned char* buffer, unsigned long count)
{
FT_Error error = FT_Err_Ok;
FT_ULong read_bytes;
if ( pos >= stream->size )
{
qDebug( "ftIOFunc: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
pos, stream->size );
return FT_Err_Invalid_Stream_Operation;
}
if ( stream->read )
read_bytes = stream->read( stream, pos, buffer, count );
else
{
read_bytes = stream->size - pos;
if ( read_bytes > count )
read_bytes = count;
memcpy( buffer, stream->base + pos, read_bytes );
}
stream->pos = pos + read_bytes;
if ( read_bytes < count )
{
qDebug( "ftIOFunc: invalid read; expected %lu bytes, got %lu\n",
count, read_bytes );
error = FT_Err_Invalid_Stream_Operation;
}
return error;
}
 
 
bool FtFace::glyphNames(QMap<QChar, std::pair<uint, QString> >& GList) const
{
return GlyNames(ftFace(), GList);
}
 
 
void FtFace::RawData(QByteArray & bb) const
{
FT_Stream fts = ftFace()->stream;
bb.resize(fts->size);
bool error = ftIOFunc(fts, 0L, reinterpret_cast<FT_Byte *>(bb.data()), fts->size);
if (error)
{
qDebug(QObject::tr("Font %1 is broken (read stream), no embedding").arg(fontFile));
bb.resize(0);
status = QMAX(status, ScFace::BROKENGLYPHS);
}
/*
if (showFontInformation)
{
QFile f(fontFile);
qDebug(QObject::tr("RawData for Font %1(%2): size=%3 filesize=%4").arg(fontFile).arg(faceIndex_).arg(bb.size()).arg(f.size()));
}
*/
}
 
 
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