View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0004645 | Scribus | Fonts | public | 2006-11-29 14:11 | 2016-04-04 03:15 |
Reporter | pierremarchand | Assigned To | avox | ||
Priority | normal | Severity | feature | Reproducibility | always |
Status | assigned | Resolution | open | ||
OS | linux | ||||
Product Version | 1.3.4cvs | ||||
Summary | 0004645: Fine tune kerning pairs | ||||
Description | An experimental patch related to bypass fonts files metrics kerning pairs without edit the font file. | ||||
Tags | kerning | ||||
Patch | |||||
2006-11-29 22:33
|
ftface.diff (5,498 bytes)
Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.8 diff -u -r1.1.2.8 ftface.cpp --- scribus/fonts/ftface.cpp 12 Sep 2006 16:00:18 -0000 1.1.2.8 +++ scribus/fonts/ftface.cpp 29 Nov 2006 22:34:05 -0000 @@ -6,6 +6,7 @@ #include <qobject.h> #include <qfile.h> +#include <qdir.h> #include "scfonts.h" #include "fonts/scfontmetrics.h" @@ -51,6 +52,7 @@ FtFace::~FtFace() { unload(); + } @@ -133,6 +135,7 @@ if (invalidGlyph > 0) { status = ScFace::BROKENGLYPHS; } + loadUserFontRessource(); } @@ -142,8 +145,11 @@ FT_Done_Face( m_face ); m_face = NULL; } + qDebug(QString("FtFace[%1] is in unload process").arg(scName)); + saveKerningCache(); // clear caches ScFaceData::unload(); + } @@ -196,6 +202,16 @@ double FtFace::glyphKerning(uint gl, uint gl2, double size) const { + const std::pair<uint,uint> pairkern(gl,gl2); + if (kerningCache.contains(pairkern)) + { + qDebug(QString("the [%1,%2] kerning pair comes from cache and is : %3").arg(gl).arg(gl2).arg(kerningCache[pairkern])); + return kerningCache[pairkern] / m_uniEM * size ; + } + else + { + qDebug(QString("the [%1,%2] kerning pair is not cached").arg(gl).arg(gl2)); + } FT_Vector delta; FT_Face face = ftFace(); double result = 0; @@ -206,11 +222,13 @@ if (true || FT_HAS_KERNING(face) ) { FT_Error error = FT_Get_Kerning(face, gl, gl2, FT_KERNING_UNSCALED, &delta); - if (error) { + if (error) + { qDebug(QString("Error %2 when accessing kerning pair for font %1").arg(scName).arg(error)); } else { result = delta.x / m_uniEM * size; + updateKerningCache(gl,gl2 , delta.x); } } else { @@ -304,4 +322,104 @@ */ } +void FtFace::loadUserFontRessource() const +{ + QString ufrPath(QDir::homeDirPath () + "/.scribus/fonts/"+psName+".ufr"); + + QFile ufr(QFile::encodeName( ufrPath )); + if(!ufr.exists()) + { + qDebug(QString("load -> ufrFile[%1] doesn't exist").arg(QFile::encodeName( ufrPath ))); + return; + } + + if(!ufr.open( IO_ReadOnly ) ) + { + qDebug(QString("load -> Can't open ufrFile[%1]").arg(QFile::encodeName( ufrPath ))); + return; + } + + QDomDocument ufrdom( "ufr" ); + if ( !ufrdom.setContent( &ufr ) ) { + ufr.close(); + return; + } + ufr.close(); + + QDomNodeList kernpair(ufrdom.elementsByTagName ( "kernpair")); + QString left; + QString right; + QString value; + if(!kerningCache.isEmpty()) + kerningCache.clear(); + if(kernpair.count()) + { + for(uint i=0;i<kernpair.count();++i) + { + left= kernpair.item(i).attributes().namedItem("left").nodeValue(); + right=kernpair.item(i).attributes().namedItem("right").nodeValue(); + value=kernpair.item(i).attributes().namedItem("value").nodeValue(); + kerningCache.insert(std::pair<uint,uint>(left.toUInt(),right.toUInt()), value.toDouble()); + qDebug(QString("load -> pair[%1,%2] inserted with value '%3'").arg(left).arg(right).arg(value)); + } + } +} + +void FtFace::updateKerningCache(uint gl,uint gl2, double adj) const +{ + + const std::pair<uint,uint> pairkern(gl,gl2); + kerningCache.insert(pairkern,adj); +} +void FtFace::saveKerningCache() const +{ + if(kerningCache.isEmpty()) + { + qDebug(QString("kerningCache is Empty")); + return; + } + QString ufrPath(QDir::homeDirPath () + "/.scribus/fonts/"+psName+".ufr"); + QFile ufr(QFile::encodeName( ufrPath)); + if(!psName.isEmpty()) + { + + if(!ufr.open( IO_WriteOnly ) ) + { + qDebug(QString("save -> Can't open ufrFile[%1]").arg(QFile::encodeName( ufrPath ))); + return; + } + qDebug(QString("save-> ufrFile[%1] is opened").arg(QFile::encodeName( ufrPath ))); + } + else + { + return; + } + + QDomDocument kerningCache_dom( "MyML" ); + QDomElement root = kerningCache_dom.createElement( "ufr" ); + kerningCache_dom.appendChild( root ); + + QDomElement kern = kerningCache_dom.createElement( "kern" ); + root.appendChild( kern ); + QDomElement kernpair; + for(QMap<std::pair<uint,uint>,double>::iterator it=kerningCache.begin();it != kerningCache.end(); ++it) + { + kernpair = kerningCache_dom.createElement("kernpair"); + kernpair.setAttribute("left",it.key().first); + kernpair.setAttribute("right",it.key().second); + kernpair.setAttribute("value",it.data()); + kern.appendChild(kernpair); + + } + + QTextStream ufrstream( &ufr ); + + kerningCache_dom.save(ufrstream , 1); + ufr.flush(); + ufr.close(); +} + + + + Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 29 Nov 2006 22:34:07 -0000 @@ -5,6 +5,7 @@ #include <qstring.h> //#include <qvector.h> #include <qmap.h> +#include <qdom.h> //#include <qarray.h> #include "scribusapi.h" @@ -85,6 +86,10 @@ void load () const; void unload () const; void loadGlyph (uint ch) const; + void loadUserFontRessource() const; + void updateKerningCache(uint,uint,double) const; + void saveKerningCache() const; + protected: mutable FT_Face m_face; @@ -111,6 +116,8 @@ mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + mutable QMap<std::pair<uint,uint>,double> kerningCache; + }; |
2006-11-29 23:23
|
ftface2.diff (6,116 bytes)
Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.8 diff -u -r1.1.2.8 ftface.cpp --- scribus/fonts/ftface.cpp 12 Sep 2006 16:00:18 -0000 1.1.2.8 +++ scribus/fonts/ftface.cpp 29 Nov 2006 23:29:34 -0000 @@ -6,6 +6,7 @@ #include <qobject.h> #include <qfile.h> +#include <qdir.h> #include "scfonts.h" #include "fonts/scfontmetrics.h" @@ -51,6 +52,7 @@ FtFace::~FtFace() { unload(); + } @@ -133,6 +135,7 @@ if (invalidGlyph > 0) { status = ScFace::BROKENGLYPHS; } + loadUserFontRessource(); } @@ -142,8 +145,11 @@ FT_Done_Face( m_face ); m_face = NULL; } + qDebug(QString("FtFace[%1] is in unload process").arg(scName)); + saveKerningCache(); // clear caches ScFaceData::unload(); + } @@ -196,6 +202,16 @@ double FtFace::glyphKerning(uint gl, uint gl2, double size) const { + const std::pair<uint,uint> pairkern(gl,gl2); + if (kerningCache.contains(pairkern)) + { + qDebug(QString("the [%1,%2] kerning pair comes from cache and is : %3").arg(gl).arg(gl2).arg(kerningCache[pairkern])); + return kerningCache[pairkern] / m_uniEM * size ; + } + else + { + qDebug(QString("the [%1,%2] kerning pair is not cached").arg(gl).arg(gl2)); + } FT_Vector delta; FT_Face face = ftFace(); double result = 0; @@ -206,11 +222,13 @@ if (true || FT_HAS_KERNING(face) ) { FT_Error error = FT_Get_Kerning(face, gl, gl2, FT_KERNING_UNSCALED, &delta); - if (error) { + if (error) + { qDebug(QString("Error %2 when accessing kerning pair for font %1").arg(scName).arg(error)); } else { result = delta.x / m_uniEM * size; + updateKerningCache(gl,gl2 , delta.x); } } else { @@ -304,4 +322,122 @@ */ } +void FtFace::loadUserFontRessource() const +{ + QString ufrPath(QDir::homeDirPath () + "/.scribus/fonts/"+psName+".ufr"); + + QFile ufr(QFile::encodeName( ufrPath )); + if(!ufr.exists()) + { + qDebug(QString("load -> ufrFile[%1] doesn't exist").arg(QFile::encodeName( ufrPath ))); + return; + } + + if(!ufr.open( IO_ReadOnly ) ) + { + qDebug(QString("load -> Can't open ufrFile[%1]").arg(QFile::encodeName( ufrPath ))); + return; + } + + QDomDocument ufrdom( "ufr" ); + if ( !ufrdom.setContent( &ufr ) ) { + ufr.close(); + return; + } + ufr.close(); + + QDomNodeList kernpair(ufrdom.elementsByTagName ( "kernpair")); + QString left; + QString right; + QString value; + if(!kerningCache.isEmpty()) + kerningCache.clear(); + if(kernpair.count()) + { + for(uint i=0;i<kernpair.count();++i) + { + left= kernpair.item(i).attributes().namedItem("left").nodeValue(); + right=kernpair.item(i).attributes().namedItem("right").nodeValue(); + value=kernpair.item(i).attributes().namedItem("value").nodeValue(); + kerningCache.insert(std::pair<uint,uint>(nameGlyph(left),nameGlyph(right)), value.toDouble()); + qDebug(QString("load -> pair[%1,%2] inserted with value '%3'").arg(left).arg(right).arg(value)); + } + } +} + +void FtFace::updateKerningCache(uint gl,uint gl2, double adj) const +{ + + const std::pair<uint,uint> pairkern(gl,gl2); + kerningCache.insert(pairkern,adj); +} +void FtFace::saveKerningCache() const +{ + if(kerningCache.isEmpty()) + { + qDebug(QString("kerningCache is Empty")); + return; + } + QString ufrPath(QDir::homeDirPath () + "/.scribus/fonts/"+psName+".ufr"); + QFile ufr(QFile::encodeName( ufrPath)); + if(!psName.isEmpty()) + { + + if(!ufr.open( IO_WriteOnly ) ) + { + qDebug(QString("save -> Can't open ufrFile[%1]").arg(QFile::encodeName( ufrPath ))); + return; + } + qDebug(QString("save-> ufrFile[%1] is opened").arg(QFile::encodeName( ufrPath ))); + } + else + { + return; + } + + QDomDocument kerningCache_dom( "MyML" ); + QDomElement root = kerningCache_dom.createElement( "ufr" ); + kerningCache_dom.appendChild( root ); + + QDomElement kern = kerningCache_dom.createElement( "kern" ); + root.appendChild( kern ); + QDomElement kernpair; + for(QMap<std::pair<uint,uint>,double>::iterator it=kerningCache.begin();it != kerningCache.end(); ++it) + { + kernpair = kerningCache_dom.createElement("kernpair"); + kernpair.setAttribute("left",glyphName(it.key().first)); + kernpair.setAttribute("right",glyphName(it.key().second)); + kernpair.setAttribute("value",it.data()); + kern.appendChild(kernpair); + + } + + QTextStream ufrstream( &ufr ); + + kerningCache_dom.save(ufrstream , 1); + ufr.flush(); + ufr.close(); +} + +QString FtFace::glyphName(uint g) const +{ + if(glyphList.isEmpty()) + glyphNames(glyphList); + + return glyphList[g].second; +} + +uint FtFace::nameGlyph(QString n) const +{ + if(nameList.isEmpty()) + { + glyphNames(glyphList); + for(QMap<uint, std::pair<QChar, QString> >::iterator it=glyphList.begin(); it != glyphList.end(); ++it) + { + nameList.insert(it.data().second, it.key()); + } + } + return nameList[n]; +} + Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 29 Nov 2006 23:29:37 -0000 @@ -5,6 +5,7 @@ #include <qstring.h> //#include <qvector.h> #include <qmap.h> +#include <qdom.h> //#include <qarray.h> #include "scribusapi.h" @@ -85,6 +86,12 @@ void load () const; void unload () const; void loadGlyph (uint ch) const; + void loadUserFontRessource() const; + void updateKerningCache(uint,uint,double) const; + void saveKerningCache() const; + QString glyphName(uint) const; + uint nameGlyph(QString) const; + protected: mutable FT_Face m_face; @@ -111,6 +118,10 @@ mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + mutable QMap<std::pair<uint,uint>,double> kerningCache; + mutable QMap<uint, std::pair<QChar, QString> > glyphList; + mutable QMap<QString,uint> nameList; + }; |
|
One more word. My idea is that the most you can cache and save in an editable way, the most you can tune in scribus font handling. The very deep idea is to have a cache for OpenType-like features that you can edit and then give these features to type1 fonts for example. Brief, it's an idea, who knows what can it gives ? |
|
I had similar ideas, making fonts customizable in many ways. About your patch: maybe that code should go into scface.{h,cpp}, so that non-FT fonts could also profit from it, should we implement those. In my view saving the font customisation data should not be automatic, but explicit. In the long run a customized font should allow: * customized kerning, including kern classes * pre-scaling * merging fonts, eg. symbol fonts or Type1 expert fonts to get better Unicode coverage * customize encoding * customizing leading, space width and other params * storing default font substitutions * store preferences for embedding/subsetting * grouping of font families and optical sizes * store licence information * group fonts into sets For that I planned to extend the current fontcache into a fontmanagement database. What do you think? |
|
Please do not put this in 1.3.4. We do not need more to debug. |
|
No, I didnt plan to do it in 1.3.4 (didnt we have a feature stop? :-) ) |
|
Would this feature also cover "faked" spaces, that are missing in the original font, e.g. an automatically or manually created thin space, that could be stored for use in Scribus? |
|
I plan to implement those spaces independently of font customisation. I already started with ZWSPACE and ZWNBSPACE; also NBSPACE and NBHYPHEN and SHYPHEN do not need to be present in a font. I think only normal width spaces need to be configurable, the others are fixed proportions of an EM, no? What do you think of emulating dashes by scaling hyphen horizontally? |
|
>>plan to implement those spaces independently of font customisation. Wow, thanks a lot! >>I think only normal width spaces need to be configurable, the others are fixed proportions of an EM, no? Not exactly, but other measurements seem to disappear due to anglo-american predominance in computer typography; see 3400 >>What do you think of emulating dashes by scaling hyphen horizontally? Why not? If they have the right size, it doesn't matter on what original dimensions they're based. It's only important to have the right proportions at hand. |
|
>> I think only normal width spaces need >> to be configurable, the others are fixed >> proportions of an EM, no? > > Not exactly, but other measurements seem to > disappear due to anglo-american predominance > in computer typography; see 3400 Actually, Avox is right. There are "convention spaces" an EM is a full em width and an en is half an em wide. There are many more, proportions are available in the "Adding typographic spaces to fonts with FontForge" tutorial I wrote for the wiki. 3400 makes no sense, an EM is now the width of an "M", and neither is an EN the width of an "N". Still, I wouldn't hard-code them, just because if you make it possible to customize some, you should rather do it for all. By the way just make sure that the space sizes are saved with the file too. If people have set different thicknesses for the same space name, that's likely to cause trouble somewhere. ---- > What do you think of emulating dashes by scaling hyphen horizontally? No, that's bad typography practice, don't do it. |
|
Short: I think that if Scribus needs to store font informations, and in this, a fontmanagement database is necessary, users needs to be presented a ,if not simple (font programs are not), at least clear font management _file_ format. Yes, I think that's offer to store all what scribus knows about fonts into files is the best way to save work for scribus' developers (because the font customization tool is there, a text editor) and can quickly give users full power over their fonts. Very short: Thinking of an efficient text-based afm-but-more-powerfull-like could be of some interest. >* customized kerning, including kern classes Storing kern classes would be far more efficient than what I did. >* merging fonts, eg. symbol fonts or Type1 expert fonts to get better Unicode coverage It gives me the idea of a new definition of metafont ! Could we imagine font paths as a root and glyphs as leaves and a way to abstract on these basis. If I want to merge two glyphs, as a user I put in a file something like glyph://MinionPro/Bold/emdash glyph://GillSans/Reg/Thin/Ucircumflex and why not gsub://MinionPro/Reg/liga and Ok, I stop it | |
|
New step: After a long and deep think about what you stated, I stoped tweaking {sc,ft}_face and began to work on Vface, a virtual face. I think i'll can test into it all suggestions you made except "advanced typographic features" as we can find un OT or sil fonts since layout() runs in position by position. If you can send a word for pre-processing before including it in the --- more than 1000 lines loop :-) --- actual layout sub, it could be processed in a harbuzz buffer and come back with features applied, but maybe I didn't understood well how the whole thing works. For the Vface, if you have time to expose which methods are required and which are for XXface internal use, it would save me a bunch of time. |
|
nb: It's not the place where my work is yet but, my idea is to build a type 3 font for embedding in pdf. What do tou think of the idea, and if it's not that bad one, will be somebody to help ? |
|
I got the following list of required methods to implement in a face class with grep|sed|sort|uniq , kind of "brute force":-) Does it match all ? -------------------- ascent canRender char2CMap charWidth descent family glyphKerning glyphOrigin glyphOutline height isNone pointSize psName realCharAscent realCharHeight realCharWidth replacementName scName subset toString type usable ----------------- |
|
Hi Pierre, I recently converted ScFace to the "private implementation" pattern, aka "handle". This means that ScFace is a handle class and all interesting stuff and the subclassing is done in ScFaceData: ScFaceData <------------ ScFace ^ | ------+----------------- | | | FtFace HarfBuzzFace VFace | FtFace_ttf This means that all methods in ScFaceData mut be implemented. The following have reasonable defaults: * glyphWidth * glyphOrigin * glyphOutline Those three rely on loadGlyph() to fill the caches. loadFace() must fill all other member variables of ScFaceData. For VFace you could forward most methods to the contained faces, even glyphWidth/Origin/Outline. Especially the last would avoid double caching. EmbedFont() should just return false for now since that will not work if a VFace is containing several faces. Same for RawData(). has |
|
layout() is waiting to be renamed to legacy_layout and to be replaced by a new layout() function (codename NLS). A lot of that stuff is in flux, so it would be best if you concentrate on the stuff you can implement within ScFace. For an overview of the new system, checkout http://rants.scribus.net/2006/10/31/boston-text-layout-summit/ Pending changes include: * replacement of the StoryText class * rewrite of DrawObj_Item, layoutGlyphs(), drawGlyphs() * switch between layout() and legacy_layout() depending on a user flag Advanced features will be controlled by an attribute list in CharStyle, eg. [+smallcap,-stdlig,+oldstyle]. Some of those which can be implemented on a char-by-char basis might find their way into legacy_layout(). I also plan to implement a few emulating features, eg. fake_smallcaps, fake_oldstyle etc. Other font management functionality will go into ScFonts, which also needs a full rewrite. |
2006-12-06 22:58
|
vface.h (3,246 bytes)
/* vface.h intended to provide virtual font pierre marchand - 2006 */ /* ALL THIS IS DUMMY IMPLEMENTATION FOR TEST PURPOSE ONLY I'm far to be an xml designer or however it has to be called, so I present the xml/ufr format quite simply (no schema inside). <font name="foo" path="bar"> <glyph codepoint="XXXX" /> . . . . </font> ... to say that you can have as many font elements as you want and other ones will come asap ! */ #ifndef V_FACE_H #define V_FACE_H #include <qstring.h> #include <qmap.h> #include <qdom.h> #include <qfile.h> #include <qdict.h> #include "scribusapi.h" #include "fonts/scface.h" #include "fonts/scfontmetrics.h" //#include "fpointarray.h" #include <ft2build.h> #include FT_FREETYPE_H struct SCRIBUS_API VFace : public ScFace::ScFaceData { VFace(QString fam, QString sty, QString scname, QString path); virtual ~VFace(); void load() const; void unload() const; void loadRessource() const; void loadGlyphs() const; struct Glyph { double width; double ascent; double descent; FPointArray outline; double x; double y; bool broken; Glyph() : outline(), x(0), y(0), broken(true) {}; }; void updateGlyphNames(FT_Face face, uint gl, QChar ch) const; // font metrics double ascent(double sz=1.0) const { return v_ascent * sz; } double descent(double sz=1.0) const { return v_descent * sz; } double xHeight(double sz=1.0) const { return v_xHeight * sz; } double capHeight(double sz=1.0) const { return v_capHeight * sz; } double height(double sz=1.0) const { return v_height * sz; } double strikeoutPos(double sz=1.0) const { return v_strikeoutPos * sz; } double underlinePos(double sz=1.0) const { return v_underlinePos * sz; } double strokeWidth(double sz=1.0) const { return v_strokeWidth; } double maxAdvanceWidth(double sz=1.0) const { return v_maxAdvanceWidth * sz; } // QString ascentAsString() const { return Ascent; } // QString descentAsString() const { return Descender; } // QString capHeightAsString() const { return CapHeight; } // QString FontBBoxAsString() const { return FontBBox; } // QString ItalicAngleAsString() const { return ItalicAngle; } uint char2CMap(QChar ch)const{return v_char[ch];} GlyphMetrics glyphBBox (uint gl, double sz) const; double glyphWidth(uint gl, double sz) const; FPointArray glyphOutline(uint gl, double sz) const; FPoint glyphOrigin(uint gl, double sz) const; double glyphKerning (uint gl1, uint gl2, double sz) const; mutable double v_ascent; mutable double v_descent; mutable double v_height; mutable double v_xHeight; mutable double v_capHeight; mutable double v_strikeoutPos; mutable double v_underlinePos; mutable double v_strokeWidth; mutable double v_maxAdvanceWidth; // Stock mutable QMap <QChar, QString> v_font; // < codepoint, font name > mutable QMap <QString, QString> v_path; // < font name, font file path > mutable QMap <uint,std::pair<QChar, QString> > v_name; // < glyph index < codepoint , name of glyph> > mutable QMap <QChar, uint> v_char; // < codepoint, glyph index > mutable QMap <std::pair<uint,uint>, double> v_kern; mutable QMap <uint,Glyph> v; // < glyph index, glyph > }; #endif |
2006-12-06 22:58
|
vface.cpp (13,383 bytes)
/* vface.cpp */ #include "vface.h" VFace::VFace(QString fam, QString sty, QString scname, QString path) : ScFaceData() { family = fam; style = sty; scName = scname; variant =""; psName = scname.simplifyWhiteSpace().lower().replace(" ","_") ; fontFile = path; faceIndex = 0; } VFace::~VFace() { unload(); } void VFace::unload() const { ScFaceData::unload(); v_font.clear(); v_path.clear(); v_name.clear(); v_char.clear(); v_kern.clear(); v.clear(); } void VFace::load() const { ScFaceData::load(); loadRessource(); loadGlyphs(); } void VFace::loadRessource() const { QFile ufr(QFile::encodeName( fontFile )); if(!ufr.open( IO_ReadOnly ) ) { qDebug(QString("VFace::loadRessource() : Can't open ufrFile[%1]").arg(QFile::encodeName( fontFile ))); return; } QDomDocument ufrdom( "ufr" ); if ( !ufrdom.setContent( &ufr ) ) { ufr.close(); qDebug(QString("VFace::loadRessource() : Can't build DOM for ufrFile[%1]").arg(QFile::encodeName( fontFile ))); return; } ufr.close(); // Load Fonts QDomNodeList fontlist(ufrdom.elementsByTagName ( "font")); QString fn, fp;//fontname fontpath if(!v_font.isEmpty()) v_font.clear(); if(fontlist.count()) { for(uint i=0; i < fontlist.count(); ++i) { fn = fontlist.item(i).attributes().namedItem("name").nodeValue(); fp = fontlist.item(i).attributes().namedItem("path").nodeValue(); v_path.insert(fn,fp); } } // Load codepoints and map them whith font names QString cd;//codepoint QDomNodeList gnod;//glyphnode list bool ok;// required by toUInt if(fontlist.count()) { for(uint i=0; i < fontlist.count(); ++i) { fn = fontlist.item(i).attributes().namedItem("name").nodeValue(); gnod = fontlist.item(i).childNodes(); if(gnod.count()) { for(uint ii=0; ii < gnod.count() ; ++ii) { cd = gnod.item(ii).attributes().namedItem("codepoint").nodeValue(); v_font.insert( QChar(cd.toUInt(&ok,16)), fn); } } } } // Load kerning pairs QDomNodeList kernpair(ufrdom.elementsByTagName ( "kernpair")); QString left; QString right; QString value; if(kernpair.count()) { for(uint i=0;i<kernpair.count();++i) { left = kernpair.item(i).attributes().namedItem("left").nodeValue(); right= kernpair.item(i).attributes().namedItem("right").nodeValue(); value= kernpair.item(i).attributes().namedItem("value").nodeValue(); v_kern.insert(std::pair<uint,uint>(left.toUInt(),right.toUInt()), value.toDouble()); qDebug(QString("pair[%1,%2] inserted with value '%3'").arg(left).arg(right).arg(value)); } } } void VFace::loadGlyphs() const { // For each codepoint in v_font, we want to load the corresponding glyph index // and once we have glyph index, load the glyph in v // first we load as many fontfiles as there are font elements FT_Library ftlib; if (FT_Init_FreeType( &ftlib )) { qDebug(QString("VFace::loadGlyphs() : Freetype2 library not available")); return; } QDict<FT_FaceRec> face; QDictIterator<FT_FaceRec> f_it( face ); FT_Face tmpface; face.setAutoDelete(true); for(QMap <QString, QString>::iterator it=v_path.begin(); it != v_path.end(); ++it) face.insert(it.key(), new FT_FaceRec); Glyph *grec; // a glyph slot uint gindex = 0;// a glyph index double uniEM; for(;f_it.current(); ++f_it) { tmpface = f_it.current(); if(FT_New_Face(ftlib, QFile::encodeName( v_path[f_it.currentKey()]), 0, &tmpface )) { qDebug(QString("VFace::loadGlyphs() : Unable to load face [%1]").arg(f_it.currentKey())); } else { uniEM = static_cast<double>(f_it.current()->units_per_EM); v_ascent = v_ascent > (f_it.current()->ascender / uniEM) ? v_ascent : (f_it.current()->ascender / uniEM); v_descent = v_descent > (f_it.current()->descender / uniEM) ? v_descent : (f_it.current()->descender / uniEM); v_height = v_height > (f_it.current()->height / uniEM) ? v_height : (f_it.current()->height / uniEM); v_xHeight = v_height; v_capHeight = v_height; v_maxAdvanceWidth = v_maxAdvanceWidth > (f_it.current()->max_advance_width / uniEM) ? v_maxAdvanceWidth : (f_it.current()->max_advance_width / uniEM); v_strikeoutPos = v_ascent / 3; v_underlinePos = v_underlinePos > (f_it.current()->underline_position / uniEM) ? v_underlinePos : (f_it.current()->underline_position / uniEM); v_strokeWidth = v_strokeWidth > (f_it.current()->underline_thickness / uniEM) ? v_strokeWidth : (f_it.current()->underline_thickness / uniEM) ; // We have valid face. begin to load codepoints from v_font. Because it's just test, we don't check it too much ;-) for(QMap <QChar, QString>::iterator it=v_font.begin(); it != v_font.end(); ++it) { if(it.data() == f_it.currentKey()) { gindex = FT_Get_Char_Index(f_it.current(),it.key()); v_char.insert(it.key(), gindex ); if(FT_Load_Glyph(f_it.current(), gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP )) { qDebug(QString("VFace::loadGlyphs() : Unable to load glyph [%1] of face [%2]").arg(gindex).arg(f_it.currentKey())); } else { grec = new(Glyph); double x, y; bool error = false; FPointArray outlines = traceGlyph( f_it.current(), gindex, 10, &x, &y, &error); if(!error) { grec->outline = outlines.copy(); grec->x = x; grec->y = y; grec->width = f_it.current()->glyph->metrics.horiAdvance / uniEM; grec->ascent = f_it.current()->glyph->metrics.horiBearingY / uniEM; grec->descent = (f_it.current()->glyph->metrics.height / uniEM) - grec->ascent ; grec->broken = false; } v.insert(gindex, *grec); updateGlyphNames( f_it.current(), gindex, it.key()); delete(grec); } } } } FT_Done_Face(tmpface); } FT_Done_FreeType(ftlib); } QString uniName(FT_ULong charcode) { static const char HEX[] = "0123456789ABCDEF"; QString result; 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; } void VFace::updateGlyphNames(FT_Face face, uint gl, QChar ch) const { char buf[50]; FT_ULong charcode = ch.unicode(); FT_UInt gindex = gl; setBestEncoding(face); const bool hasPSNames = FT_HAS_GLYPH_NAMES(face); 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] == '.') { v_name.insert(gindex, std::make_pair( QChar(static_cast<uint>(charcode)), uniName(charcode) ) ); v_char.insert(QChar(static_cast<uint>(charcode)), gindex); } else { v_name.insert(gindex, std::make_pair( QChar(static_cast<uint>(charcode)), QString(reinterpret_cast<char*>(buf)) ) ); v_char.insert(QChar(static_cast<uint>(charcode)), gindex); } } GlyphMetrics VFace::glyphBBox (uint gl, double sz) const { GlyphMetrics ret; ret.width = v[gl].width * sz; ret.ascent = v[gl].ascent * sz; ret.descent = v[gl].descent *sz; return ret; } double VFace::glyphWidth(uint gl, double sz) const { if (gl >= ScFace::CONTROL_GLYPHS) return 0.0; else return v[gl].width * sz; } FPointArray VFace::glyphOutline(uint gl, double sz) const { if (gl >= ScFace::CONTROL_GLYPHS) return FPointArray(); FPointArray res = v[gl].outline.copy(); if (sz != 1.0) res.scale(sz, sz); return res; } FPoint VFace::glyphOrigin(uint gl, double sz) const { if (gl >= ScFace::CONTROL_GLYPHS) return FPoint(0,0); return FPoint(v[gl].x, v[gl].y) * sz; } double VFace::glyphKerning (uint gl1, uint gl2, double sz) const { std::pair<uint,uint> kp(gl1,gl2); if(v_kern.contains(kp)) return v_kern[kp]; return 0.0; // TODO if gl1 and gl2 come from the same font file, load their kerning pair if exists. } /* old stuff, I put it here to keep the code. // Experiences with cache and other cool stuff void ScFace::ScFaceData::loadUserFontRessource() const { QString ufrPath(QDir::homeDirPath () + "/.scribus/fonts/"+psName+".ufr"); QFile ufr(QFile::encodeName( ufrPath )); if(!ufr.exists()) { qDebug(QString("load -> ufrFile[%1] doesn't exist").arg(QFile::encodeName( ufrPath ))); return; } if(!ufr.open( IO_ReadOnly ) ) { qDebug(QString("load -> Can't open ufrFile[%1]").arg(QFile::encodeName( ufrPath ))); return; } QDomDocument ufrdom( "ufr" ); if ( !ufrdom.setContent( &ufr ) ) { ufr.close(); return; } ufr.close(); // Load kerning pair QDomNodeList kernpair(ufrdom.elementsByTagName ( "kernpair")); QString left; QString right; QString value; if(!kerningCache.isEmpty()) kerningCache.clear(); if(kernpair.count()) { for(uint i=0;i<kernpair.count();++i) { left = kernpair.item(i).attributes().namedItem("left").nodeValue(); right= kernpair.item(i).attributes().namedItem("right").nodeValue(); value= kernpair.item(i).attributes().namedItem("value").nodeValue(); kerningCache.insert(std::pair<uint,uint>(nameGlyph(left),nameGlyph(right)), value.toDouble()); qDebug(QString("load -> pair[%1,%2] inserted with value '%3'").arg(left).arg(right).arg(value)); } } // Load metrics QDomNodeList met(ufrdom.elementsByTagName ( "metrics")); QString g,w,a,d; if(!metricsCache.isEmpty()) metricsCache.clear(); if(met.count()) { for(uint i = 0; i < met.count(); ++i) { g = met.item(i).attributes().namedItem("glyph").nodeValue(); w = met.item(i).attributes().namedItem("width").nodeValue(); a = met.item(i).attributes().namedItem("ascent").nodeValue(); d = met.item(i).attributes().namedItem("descent").nodeValue(); updateMetricsCache(nameGlyph(g),w.toDouble(),a.toDouble(),d.toDouble()); } } // Load extra font files QDomNodeList font(ufrdom.elementsByTagName ( "extrafont")); QString name,path; if(!extraFontFile.isEmpty()) extraFontFile.clear(); if(font.count()) { for(uint i = 0; i <font.count();++i) { name = font.item(i).attributes().namedItem("name").nodeValue(); path = font.item(i).attributes().namedItem("path").nodeValue(); extraFontFile.insert(name,path); } } // Load glyphs from extra font files QDomNodeList eg(ufrdom.elementsByTagName ( "extraglyph")); QString fname, exglyph; bool ok; if(foreignGlyph.isEmpty()) foreignGlyph.clear(); if(eg.count()) { for(uint i=0;i<eg.count();++i) { fname = eg.item(i).attributes().namedItem("font").nodeValue(); exglyph = eg.item(i).attributes().namedItem("uniglyph").nodeValue(); foreignGlyph.insert(exglyph.toUInt(&ok,16),fname); } } } void ScFace::ScFaceData::updateKerningCache(uint gl,uint gl2, double adj) const { const std::pair<uint,uint> pairkern(gl,gl2); kerningCache.insert(pairkern,adj); } void ScFace::ScFaceData::updateMetricsCache(uint gl, double w, double a, double d) const { GlyphMetrics gm; gm.width = w; gm.ascent = a; gm.descent = d; metricsCache.insert(gl, gm); } void ScFace::ScFaceData::saveKerningCache() const { if(kerningCache.isEmpty()) { qDebug(QString("kerningCache is Empty")); return; } QString ufrPath(QDir::homeDirPath () + "/.scribus/fonts/"+psName+".ufr"); QFile ufr(QFile::encodeName( ufrPath)); if(!psName.isEmpty()) { if(!ufr.open( IO_WriteOnly ) ) { qDebug(QString("save -> Can't open ufrFile[%1]").arg(QFile::encodeName( ufrPath ))); return; } qDebug(QString("save-> ufrFile[%1] is opened").arg(QFile::encodeName( ufrPath ))); } else { return; } QDomDocument kerningCache_dom( "MyML" ); QDomElement root = kerningCache_dom.createElement( "ufr" ); kerningCache_dom.appendChild( root ); QDomElement kern = kerningCache_dom.createElement( "kern" ); root.appendChild( kern ); QDomElement kernpair; for(QMap<std::pair<uint,uint>,double>::iterator it=kerningCache.begin();it != kerningCache.end(); ++it) { kernpair = kerningCache_dom.createElement("kernpair"); kernpair.setAttribute("left",glyphName(it.key().first)); kernpair.setAttribute("right",glyphName(it.key().second)); kernpair.setAttribute("value",it.data()); kern.appendChild(kernpair); } QDomElement gl = kerningCache_dom.createElement( "glyphs" ); root.appendChild(gl); QDomElement met; for(QMap<uint,GlyphMetrics>::iterator it=metricsCache.begin(); it != metricsCache.end(); ++it) { met = kerningCache_dom.createElement("metrics"); met.setAttribute("glyph",glyphName(it.key())); met.setAttribute("width",it.data().width); met.setAttribute("ascent",it.data().ascent); met.setAttribute("descent",it.data().descent); gl.appendChild(met); } //Save to file QTextStream ufrstream( &ufr ); kerningCache_dom.save(ufrstream , 1); ufr.flush(); ufr.close(); } QString ScFace::ScFaceData::glyphName(uint g) const { if(glyphList.isEmpty()) glyphNames(glyphList); return glyphList[g].second; } uint ScFace::ScFaceData::nameGlyph(QString n) const { if(nameList.isEmpty()) { glyphNames(glyphList); for(QMap<uint, std::pair<QChar, QString> >::iterator it=glyphList.begin(); it != glyphList.end(); ++it) { nameList.insert(it.data().second, it.key()); } } return nameList[n]; } */ |
|
I upload a first shot of "Virtual face class". At least it compiles :) I'll see tomorrow if it works. I didn't upload the patch of scfont I made to load virtual fonts, so don't hope to try. Virtual font file (.ufr( user font ressource)) should look like that : <ufr> <info name="family"> family </info> etc. <font name="foo" path="bar.ufr"> <glyph codepoint="XXXX" /> etc. </font> <font name="anotherfont" path="/ano/ther/font.ufr> <glyph codepoint="YYYY" /> </font> etc. <pairkern left="XXXX" right="YYYY" value="nnn" /> etc. <ufr> Of course codepoint is unicode. Later glyph would be describe as <glyph sourcecodepoint="XXXX" destcodepoint="XYXY" /> |
2006-12-12 16:14
|
|
|
I get some bad headache,and the first visual result. It's not very impressive but I put it here to givee an idea. |
|
cool. did you manually select outline style and large spacing? |
|
Andreas, are you kidding me ? Outline style and large spacing is the basis of my headache. For retrieving glyphs from fontfile, I made a large use of code present in FtFace. And I continue to wonder why when _you_ get width by " double ww = face->glyph->metrics.horiAdvance / m_uniEM; ", it seems to work, it was necessary for me ---just to get "displayable" glyph --- to hack that in "gmet.width = tmpface->glyph->metrics.horiAdvance / (uniEM * 10);". I also made large use of qDebug and saw that "tmpface->units_per_EM" returns 1000 for the two faces involved in the example, which seems quite normal, but "tmpface->glyph->metrics.horiAdvance" is about 30000 or so for each glyph. I guess I missed something somewhere and continue to read freetype.h (think i gonna print it to sleep with one day :-). Second, I can't find what is in charge of drawing glyphs (though bt gives page_item calling VFace::glyphOutline) and just imitated the way you load outlines in m_glyphOutline (I mean with traceGlyph call to get FpointArray)and then return the outline via VFace::glyphOutline and... wait and see ! Ok. I have to leave now. But as you can imagine, I have very lot beaucoup muchos questions about font driving in Scribus. nb: I put last version of Vface and try to make a diff of my changes in, mainly, ScFont. |
2006-12-12 19:29
|
|
|
I forgot to diff scface.h %------------------------------------------- @@ -68,10 +69,10 @@ { public: enum Status { UNKNOWN, LOADED, CHECKED, BROKENGLYPHS, BROKEN, NULLFACE }; - enum FontType { TYPE0, TYPE1, TYPE3, TTF, CFF, OTF, UNKNOWN_TYPE }; + enum FontType { TYPE0, TYPE1, TYPE3, TTF, CFF, OTF, VIRTUAL, UNKNOWN_TYPE }; enum FontFormat { PFA, PFB, TYPE2, TYPE42, // handled by freetype: PFB_MAC, DFONT, HQX, MACBIN, - SFNT, TTCF, UNKNOWN_FORMAT }; + SFNT, TTCF, MIXED, UNKNOWN_FORMAT }; static const uint CONTROL_GLYPHS = 2000000000; // 2 billion %--------------------------------------------------------------------------- A new FontType -> VIRTUAL and a new FontFormat -> MIXED And about outlined style in the snapshot, it comes from "stroke" was set to true in "VFace::VFace(...)". |
2006-12-13 14:12
|
|
2006-12-13 19:46
|
|
2006-12-13 20:46
|
|
|
vface-0.0.0.tar.gz is intended to work, must say, I hope it will work for you. Now that it can display some glyphs, next step is to export them. And next next step is to provide more customizations. |
2006-12-13 23:32
|
|
|
PDF export still doesn't work, but printing seems to be ok. Next next step soon ! |
|
I upload a full featured ufr file. I'd like to know what do you think of that. 1/ Are features intesting ? 2/ Can you imagine to write such files for your own purpose or is it really too much complicated and need some{thing, gui} to help? 3/Ideas ? |
2006-12-14 22:33
|
|
2006-12-15 20:33
|
|
2006-12-15 20:43
|
|
2006-12-16 14:59
|
|
|
I upload a new version of vface with a 1 in it because you can now export to pdf. If someone could find time to test it, it would be good even if I know that it is not solid. edit: This morning, I said on irc there was a problem with fileloader but I guess it was too soon in the morning. There is a "quick and dirty" workaround in the diff. |
|
Come back. Actually, I didn't gave up with vface. But before I continue in this way I would be interested in push a bit OTF in Scribus, because as far as I can see Harfbuzz is not ready and Scribus team prepares the QT4 switch. So, I just took libotf, made a simple c++ wrapper and tried it out. It's yet experimental and needs a big load of work but I got a result (see scribus-otf.png). For now, i experimented with GSUB table only because all can be done before _the big loop_. My idea to process GPOS is to set a context string at the beginning of _the big loop_ and the layout does not ask a char to the font but an index in the context string to the font. I guess it's not crystal clear. Feel free to ask precisions. |
2007-03-17 12:51
|
|
2007-03-17 12:54
|
myotf-patch.diff (23,567 bytes)
Index: scribus/pageitem_textframe.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/pageitem_textframe.cpp,v retrieving revision 1.1.2.152 diff -u -8 -p -r1.1.2.152 pageitem_textframe.cpp --- scribus/pageitem_textframe.cpp 11 Mar 2007 15:12:07 -0000 1.1.2.152 +++ scribus/pageitem_textframe.cpp 17 Mar 2007 12:53:28 -0000 @@ -537,17 +537,47 @@ static double opticalRightMargin(const S rightCorr = itemText.charStyle(b).font().charWidth(chr, chs / 10.0); rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); } return rightCorr; } return 0.0; } +// TEST +static void prepareText(StoryText& itemText, int begin, int end) +{ + /* here, it could be possible to send text to a substitution engine */ + /* example (pseudopseudocode): + QString final = itemText.charStyle(i)->font->subtitute(itemText.text(begin , end - begin), itemText.charStyle(i)->font->sub_features_set()); + + for(int i = begin, i <= end ; ++i) + { + if(final.at(i)) itemText.item(i)->ch = final.at(i); + else itemText.remove(i); + } + + + */ + + if(itemText.charStyle(begin).font().isOTF()) + { + QString os = itemText.text(begin, end - begin ); + QString ns = itemText.charStyle(begin).font().otfSub(os); + if(os != ns) + { + CharStyle back = itemText.charStyle(begin); + itemText.removeChars(begin , end); + itemText.insertChars( begin , ns ); + itemText.setCharStyle(begin , ns.length() , back ); + } + } +} +// ENDTEST void PageItem_TextFrame::layout() { if (BackBox != NULL && BackBox->invalid) { // qDebug("textframe: len=%d, going back", itemText.length()); invalid = false; PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); if (!prevInChain) @@ -671,16 +701,44 @@ void PageItem_TextFrame::layout() { desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; } current.startLine(firstInFrame()); outs = false; OFs = 0; MaxChars = 0; + //TEST + CharStyle control_charstyle; + int begin_prepare; + int end_prepare = begin_prepare = firstInFrame(); + for (int a = firstInFrame(); a < itemText.length(); ++a) + { + if(a == begin_prepare) + { + control_charstyle = itemText.charStyle(a); + continue; + } + if(control_charstyle != itemText.charStyle(a)) + { + end_prepare = a-1; + prepareText(itemText, begin_prepare, end_prepare); + begin_prepare = end_prepare = a; + control_charstyle = itemText.charStyle(a); + continue; + } + if(a == itemText.length() -1) + { + prepareText(itemText, begin_prepare, a + 1); + break; + } + ++end_prepare; + } + // ENDTEST + // BIGLOOP for (int a = firstInFrame(); a < itemText.length(); ++a) { hl = itemText.item(a); if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) style = itemText.paragraphStyle(a); if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); Index: scribus/fonts/CMakeLists.txt =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/CMakeLists.txt,v retrieving revision 1.1.2.1 diff -u -8 -p -r1.1.2.1 CMakeLists.txt --- scribus/fonts/CMakeLists.txt 23 Jul 2006 12:07:47 -0000 1.1.2.1 +++ scribus/fonts/CMakeLists.txt 17 Mar 2007 12:53:31 -0000 @@ -5,12 +5,24 @@ ${CMAKE_SOURCE_DIR}/scribus SET(SCRIBUS_FONTS_LIB_SOURCES scface.cpp ftface.cpp scface_ps.cpp scface_ttf.cpp scfontmetrics.cpp +myotf.cpp ) +SET(OTF_DIR ${CMAKE_MODULE_PATH}) +FIND_PACKAGE(OTF REQUIRED) +IF(OTF_FOUND) + SET(HAVE_OTF 1) + MESSAGE("LIBOTF Library found") +ELSE(OTF_FOUND) + MESSAGE(FATAL_ERROR "Could not find the libOtf Library") +ENDIF(OTF_FOUND) + +LINK_LIBRARIES ( ${OTF_LIBRARIES}) + SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.9 diff -u -8 -p -r1.1.2.9 ftface.cpp --- scribus/fonts/ftface.cpp 11 Jan 2007 15:29:46 -0000 1.1.2.9 +++ scribus/fonts/ftface.cpp 17 Mar 2007 12:53:32 -0000 @@ -136,36 +136,57 @@ void FtFace::load() const ++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; } + //TEST libotf + if(typeCode == ScFace::OTF) + { + _otf = new myotf(QFile::encodeName(fontFile)); + //here we make otf init "by hand" and it's just intended to work with the MinionPro shipped with adobe reader + otfScript = "latn"; + otfLang = "default"; + otfSubFeatures.append("liga"); + otfSubFeatures.append("dlig"); + otfSubFeatures.append("onum"); + otfPosFeatures.append("kern"); + otfPosFeatures.append("cpsp"); + } } void FtFace::unload() const { if (m_face) { FT_Done_Face( m_face ); m_face = NULL; } // clear caches + if(_otf) delete _otf; 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; + if(m_cMap.contains(ch.unicode())) + { + return m_cMap[ch.unicode()]; + } + else + { + FT_Face face = ftFace(); + uint gl = FT_Get_Char_Index(face, ch.unicode()); + m_cMap.insert(ch.unicode(), gl); + return gl; + } } void FtFace::loadGlyph(uint gl) const { if (m_glyphWidth.contains(gl)) return; @@ -307,9 +328,32 @@ void FtFace::RawData(QByteArray & bb) co // 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())); } */ } - +QString FtFace::otfSub(QString s) const +{ + if(typeCode == ScFace::OTF) + { + _otf->set_table("GSUB"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + _otf->set_features(otfSubFeatures); + int nbg = _otf->procstring(s); + QString newstring; + for (int i = 0; i < nbg ; ++i) + { + newstring += QChar(_otf->unicode( _otf->otfString()->glyphs[i].glyph_id )); + m_cMap.insert(_otf->unicode( _otf->otfString()->glyphs[i].glyph_id), _otf->otfString()->glyphs[i].glyph_id); + } + qDebug(QString("oldstring is \"%1\" and new string os \"%2\"").arg(s).arg(newstring)); + return newstring; +// CharStyle backstyle = itemText.charStyle(begin); +// itemText.removeChars(begin , end); +// itemText.insertChars( begin , newstring); +// itemText.setCharStyle(begin , nbg , backstyle ); + } + return s; +} Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -8 -p -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 17 Mar 2007 12:53:32 -0000 @@ -107,11 +107,21 @@ protected: mutable double m_height; mutable double m_xHeight; mutable double m_capHeight; mutable double m_maxAdvanceWidth; mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + //TEST libotf + public: + mutable QStringList otfSubFeatures; + mutable QStringList otfPosFeatures; + mutable QString otfScript; + mutable QString otfLang; + QString otfSub(QString s) const ; + //void otfPos(const StoryText& itemText, int begin, int end) ; + mutable myotf * _otf; + }; #endif Index: scribus/fonts/myotf.cpp =================================================================== RCS file: scribus/fonts/myotf.cpp diff -N scribus/fonts/myotf.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.cpp 17 Mar 2007 12:53:33 -0000 @@ -0,0 +1,525 @@ +/* un test de libotf mer18jan */ + + +#include "myotf.h" + + + +void +myotf::set_subalt (bool b) +{ + subAlt = b; +} + +int +myotf::get_glyph_used() +{ + return mys.used; +} + +myotf::myotf (QString n) +{ + nom = n; + my = OTF_open ((char*)nom.ascii()); + subAlt = false; + glyphAlloc = false; + if (OTF_get_table (my, "head") == 0) + head = 1; + else + head = 0; + if (OTF_get_table (my, "name") == 0) + name = 1; + else + name = 0; + if (OTF_get_table (my, "cmap") == 0) + cmap = 1; + else + cmap = 0; + if (OTF_get_table (my, "GDEF") == 0) + GDEF = 1; + else + GDEF = 0; + if (OTF_get_table (my, "GSUB") == 0) + GSUB = 1; + else + GSUB = 0; + if (OTF_get_table (my, "GPOS") == 0) + GPOS = 1; + else + GPOS = 0; + // if (GSUB){ OTF_get_scripts (my, 1); OTF_get_features (my, 1);} + // if (GPOS){ OTF_get_scripts (my, 0); OTF_get_features (my, 0);} + +/* + std::cout << "head : " << head << "\n"; + std::cout << "name : " << name << "\n"; + std::cout << "cmap : " << cmap << "\n"; + std::cout << "GDEF : " << GDEF << "\n"; + std::cout << "GSUB : " << GSUB << "\n"; + std::cout << "GPOS : " << GPOS << "\n"; +*/ +} + +myotf::~myotf () +{ + if (glyphAlloc) + free (mys.glyphs); + OTF_close (my); +} + +int +myotf::procstring (QString s) +{ + int n = s.length(); + if (glyphAlloc) + free (mys.glyphs); + mys.size = n; + mys.used = n; + mys.glyphs = (OTF_Glyph *) calloc (n , sizeof (OTF_Glyph)); + glyphAlloc = true; + OTF_error = 0; + for (int i = 0; i < n; i++) + { + mys.glyphs[i].c = s[i].unicode(); + mys.glyphs[i].glyph_id = 0; + } + + if(OTF_drive_cmap (my, &mys))OTF_perror("drive_cmap ") ; + + for (int i = 0; i < mys.used; i++) + { + std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode( my, mys.glyphs[i].glyph_id) << " : " << dec; + } + cout << "\n"; + + QString fe; + for (QStringList::iterator ife = curFeatures.begin (); + ife != curFeatures.end (); ife++) + { + fe += *ife; + fe += ','; + } + //*(fe.end()) = NULL ; + + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + char *argfe = (char *) fe.ascii(); + + if (GDEF) + {if(OTF_drive_gdef(my, &mys) != 0 )OTF_perror("drive_GDEF ");} + + if (curTable == "GPOS") + { + if(OTF_drive_gpos (my, &mys, argsc, argla, argfe))OTF_perror("drive_GPOS"); + OTF_perror("force(drive_GPOS)"); + for( int n = 0; n < mys.used ; n++) + get_position(n); + } + + if (curTable == "GSUB") + { + if (!subAlt) + { + if(OTF_drive_gsub (my, &mys, argsc, argla, argfe))OTF_perror("drive_GSUB"); + } + else + { + if(OTF_drive_gsub_alternate (my, &mys, argsc, argla, argfe))OTF_perror("drive_GSUB_alt"); + + } + } + + + for (int i = 0; i < mys.used; i++) + { + std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode (my , mys.glyphs[i].glyph_id ) << " : " << dec ; + std::cout << '['<<(char)OTF_get_unicode (my , mys.glyphs[i].glyph_id )<<']' ; + } + cout << "\n"; + + + + return mys.used; +} + +int +myotf::procstring() +{ + QString fe; + for (QStringList::iterator ife = curFeatures.begin (); + ife != curFeatures.end (); ife++) + { + fe += *ife; + fe += ','; + } + //*(fe.end()) = NULL ; + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + char *argfe = (char *) fe.ascii(); + + if (curTable == "GPOS") + { + OTF_drive_gpos (my, &mys, argsc, argla, argfe); + for( int n = 0; n < mys.used ; n++) + get_position(n); + } + + if (curTable == "GSUB") + if (!subAlt) + { + OTF_drive_gsub (my, &mys, argsc, argla, argfe); + } + else + { + OTF_drive_gsub_alternate (my, &mys, argsc, argla, argfe); + + } + for (int i = 0; i < mys.used; i++) + { + std::cout << mys.glyphs[i].glyph_id << " : "; + } + cout << "\n"; + + + + return mys.used; +} + + + + + +QStringList myotf::get_tables () +{ + QStringList ret; + + if (GDEF) + ret.insert (ret.end (), "GDEF"); + if (GPOS) + ret.insert (ret.end (), "GPOS"); + if (GSUB) + ret.insert (ret.end (), "GSUB"); + + return ret; +} + +void +myotf::set_table (QString s) +{ + curTable = s; +} + +QStringList myotf::get_scripts () +{ + QStringList ret; + char + aa[5]; + if (curTable == "GSUB") + { + int + ns = my->gsub->ScriptList.ScriptCount; + char * + a = aa; + std:: + cout << "Il y a " << ns << " systèmes d'écriture dans cette fonte.\n"; + for (int i = 0; i < ns; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[i].ScriptTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GPOS") + { + int + ns = my->gpos->ScriptList.ScriptCount; + char * + a = aa; + std:: + cout << "Il y a " << ns << " systèmes d'écriture dans cette fonte.\n"; + for (int i = 0; i < ns; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[i].ScriptTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + return ret; + +} + +void +myotf::set_script (QString s) +{ + char a[5]; + if (curTable == "GPOS") + { + for (int i = 0; i < my->gpos->ScriptList.ScriptCount; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[i].ScriptTag, a); + if (a == s) + curScript = i; + } + } + if (curTable == "GSUB") + { + for (int i = 0; i < my->gsub->ScriptList.ScriptCount; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[i].ScriptTag, a); + if (a == s) + curScript = i; + } + } + curScriptName = s; +} + + +QStringList myotf::get_langs () +{ + QStringList ret; + char + a[5]; + if (curTable == "GPOS") + { + int + nl = my->gpos->ScriptList.Script[curScript].LangSysCount; + cout << "Il y a là " << nl << " langues" << "\n"; + for (int i = 0; i < nl; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GSUB") + { + int + nl = my->gsub->ScriptList.Script[curScript].LangSysCount; + cout << "Il y a là " << nl << " langues" << "\n"; + for (int i = 0; i < nl; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + + return ret; +} + +void +myotf::set_lang (QString s) +{ + if (s == "default") + { + curLangName = "dflt"; + curLang = -1; + return; + } + + char a[5]; + if (curTable == "GPOS") + { + for (int i = 0; i < my->gpos->ScriptList.Script[curScript].LangSysCount; + i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + if (a == s) + curLang = i; + } + } + if (curTable == "GSUB") + { + for (int i = 0; i < my->gsub->ScriptList.Script[curScript].LangSysCount; + i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + if (a == s) + curLang = i; + } + } + curLangName = s; +} + + +QStringList myotf::get_features () +{ + QStringList ret; + char + a[10]; + int + nf, + findex, + i; + OTF_Tag + ftag; + if (curTable == "GPOS") + { + if (curLang >= 0) + nf = + my->gpos->ScriptList.Script[curScript].LangSys[curLang]. + FeatureCount; + else + nf = + my->gpos->ScriptList.Script[curScript].DefaultLangSys.FeatureCount; + cout << "Il y a là " << nf << " fonctionnalités " << "\n"; + for (i = 0; i < nf; i++) + { + if (curLang >= 0) + { + findex = + my->gpos->ScriptList.Script[curScript].LangSys[curLang]. + FeatureIndex[i]; + ftag = my->gpos->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + else + { + findex = + my->gpos->ScriptList.Script[curScript].DefaultLangSys. + FeatureIndex[i]; + ftag = my->gpos->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GSUB") + { + if (curLang >= 0) + nf = + my->gsub->ScriptList.Script[curScript].LangSys[curLang]. + FeatureCount; + else + nf = + my->gsub->ScriptList.Script[curScript].DefaultLangSys.FeatureCount; + + cout << "Il y a là " << nf << " fonctionnalités " << "\n"; + + for (i = 0; i < nf; i++) + { + + if (curLang >= 0) + { + findex = + my->gsub->ScriptList.Script[curScript].LangSys[curLang]. + FeatureIndex[i]; + ftag = my->gsub->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + else + { + findex = + my->gsub->ScriptList.Script[curScript].DefaultLangSys. + FeatureIndex[i]; + ftag = my->gsub->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + return ret; +} + +void +myotf::set_features (QStringList ls) +{ + curFeatures = ls; +} + + +int +myotf::get_position_type (int ind) +{ + return (mys.glyphs[ind].positioning_type); +} + +posglyph +myotf::get_position(int g) +{ + posglyph ret; + int gt = get_position_type(g); + OTF_Glyph og = mys.glyphs[g] ; + if (gt == 1) + { + for( int i= 0x00001 ; i < 0x0081 ; i*=2) + { + if(og.f.f1.format & i ) + { + switch (i) + { + case 0x0001 : ret.Xposition = og.f.f1.value->XPlacement ; + break; + case 0x0002 : ret.Yposition = og.f.f1.value->YPlacement ; + break; + case 0x0004 : ret.Xadvance = og.f.f1.value->XAdvance ; + break; + case 0x0008 : ret.Yadvance = og.f.f1.value->YAdvance ; + break; + default : qDebug( "Don't know how to handle OTF_DeviceTable!"); + break; + } + } + } + } + if (gt == 2) + { + for( int i= 0x0001 ; i < 0x0081 ; i*=2) + { + if(og.f.f2.format & i) + { + switch (i) + { + case 0x0001 : ret.Xposition = og.f.f1.value->XPlacement ; + break; + case 0x0002 : ret.Yposition = og.f.f1.value->YPlacement ; + break; + case 0x0004 : ret.Xadvance = og.f.f1.value->XAdvance ; + break; + case 0x0008 : ret.Yadvance = og.f.f1.value->YAdvance ; + break; + default : qDebug( "Don't know how to handle OTF_DeviceTable!"); + break; + } + } + } + } + return ret; +} + + + + + +// int +// main (int ac, char **av) +// { +// myotf lafonte (av[1]); +// QStringList feat; +// lafonte.set_table (av[3]); +// lafonte.set_script (av[4]); +// lafonte.set_lang (av[5]); +// +// for(int c = 6; c < ac ; c++) +// { +// cout << av[c] << "\n"; +// feat.insert(feat.end(), av[c]); +// } +// // feat.insert(feat.end(), "cpsp"); +// lafonte.set_features (feat); +// // int use; +// lafonte.procstring (av[2]); +// return 0; +// } Index: scribus/fonts/myotf.h =================================================================== RCS file: scribus/fonts/myotf.h diff -N scribus/fonts/myotf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.h 17 Mar 2007 12:53:33 -0000 @@ -0,0 +1,93 @@ +// myotf.h + +#ifndef WRAPLIBOTF +#define WRAPLIBOTF + + +extern "C" +{ +#include <otf.h> +#include <stdlib.h> +} + +#include <iostream> +#include <iomanip> + +#include <qstring.h> +#include <qstringlist.h> + +using namespace std; + +struct posglyph +{ + double Xposition; + double Yposition; + double Xadvance; + double Yadvance; + double xadvance(){return Xadvance;} + double yadvance(){return Yadvance;} + double xposition(){return Xposition;} + double yposition(){return Yposition;} +}; + +class myotf +{ + QString nom; + + OTF *my; + OTF_GlyphString mys; + + + + bool subAlt; + bool glyphAlloc; + + int head, name, cmap, GDEF, GSUB, GPOS; + +public: + OTF_GlyphString * otfString() {return &mys;} + int unicode(int gid){ return OTF_get_unicode(my, gid);} + QString curTable; + int curScript, curLang; + QString curScriptName, curLangName; + QStringList curFeatures; + myotf (QString n); + ~myotf (); +/* + * These members functions apply features currently set + */ + int procstring (QString ); + int procstring (); +/* + * These functions give access to informations contained in the fontfile + */ + QStringList get_tables (); + QStringList get_scripts (); + QStringList get_langs (); + QStringList get_features (); +/* + * These allow to set up the features ( Tab -> Scr -> Lan -> Fea ) + */ + void set_table (QString); + void set_script (QString); + void set_lang (QString); + void set_features (QStringList); + void set_subalt (bool); +/* + * I can't remember what this so important method is expected to achieve ! + */ + int get_position_type (int); + /* + * for the moment, it just does nothing. Because I have no idea + * of which sruct can be the target of this function.Nevertheless + * I'm clearly aware that's the key function, it's the reason why + * i put this apart from procstring(). + * The argument is the number of the glyph + */ + + posglyph get_position(int); + int get_glyph_used(); + +}; + +#endif Index: scribus/fonts/scface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/scface.h,v retrieving revision 1.1.2.10 diff -u -8 -p -r1.1.2.10 scface.h --- scribus/fonts/scface.h 26 Nov 2006 13:15:19 -0000 1.1.2.10 +++ scribus/fonts/scface.h 17 Mar 2007 12:53:34 -0000 @@ -16,16 +16,19 @@ virtual: dispatch to constituents, #include <qstring.h> //#include <qvector.h> #include <qmap.h> //#include <qarray.h> #include <utility> #include "fpointarray.h" +//TEST libotf + +#include "myotf.h" struct GlyphMetrics { double width; double ascent; double descent; }; @@ -166,16 +169,19 @@ public: 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<uint, std::pair<QChar, QString> >& gList) const; + + virtual QString otfSub(QString s) const {return s;} + // 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; }; @@ -351,16 +357,19 @@ public: 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; } + //TEST libotf + QString otfSub (QString s) const { return m->otfSub(s); } + private: friend class SCFonts; ScFace(ScFaceData* md); ScFaceData* m; QString replacedName; QString replacedInDoc; |
|
Hm, it's pretty much decided that Scribus will use HarfBuzz in the future. The OTF table handling functions of HarfBuzz are already used in Qt and Pango, and there's some activity to include shaping code into HB. Still, nice work. About the "Big Loop": have a look at PageItem::layoutGlyphs(). That's where Unicode is converted into glyph ids. It currently uses the GlyphLayout structure from sctextstruct.h, but should use a HarfBuzz buffer directly in the future. |
|
IMHO, the "open type features handler" is not the most important. I mean, whatever it is, features take place between the font and the layout --- FreeType argues of that to not support it --- and you have to change the way you build your layout engine to take it in account. For example, I was relieved when I found PageItem::layoutGlyphs() as I thought I could avoid to write in _the big loop_ but when I qDebugged what is sent to PageItem::layoutGlyphs() it appeared that chstr is just one char long. So it's not suitable to process contextual stuff --- substitution or positionning. I used libotf as a prototype because the wrapper was written for long time ;-) and really easier to use than Harfbuzz. Finally, my aim is just to point out the minimum requirements needed to handle OpenType fonts in Scribus, because I think it would be near the top of TODO list |
2007-03-19 20:43
|
myotf-patch-2.diff (36,277 bytes)
Index: scribus/pageitem.cpp =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.cpp,v retrieving revision 1.121.2.418 diff -u -8 -p -r1.121.2.418 pageitem.cpp --- scribus/pageitem.cpp 12 Mar 2007 15:57:39 -0000 1.121.2.418 +++ scribus/pageitem.cpp 19 Mar 2007 20:40:39 -0000 @@ -1747,16 +1747,170 @@ double PageItem::layoutGlyphs(const Char layout.yadvance = layout.more->yadvance; } else { layout.shrink(); } return retval; } +// the same, but character to render is retrieved from contextStringPointer +double PageItem::layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout) +{ + QString chars; + bool otf = style.font().isOTF(); + if(contextString[0] == 0) // We have a special char that can't be processed by libotf + { + chars = contextString[1].unicode(); + } + else if(otf) + { + + if (contextStringPointer == 0) + { + contextGlyphsString = style.font().otfied(contextString); + //Now, we have 4 possibilities : + // 1/ one glyph for one character ; + // 2/ many glyphs for one character ; + // 3/ one glyph for many characters ; + // 4/ nothing if character was rendered in a previous case 3 call. + // Too much complicated for me, I take the shorter way. + int ls = contextString.length(); + int lg = contextGlyphsString.length(); + contexLengthChange = lg - ls; + } + if (contexLengthChange < 0) // source string is longer then the rendered string + { + contexLengthChange += 1; // waiting + contextStringPointer = -1; + layout.glyph = ScFace::CONTROL_GLYPHS + SpecialChars::ZWSPACE.unicode(); + return 0.0; + } + else if (contexLengthChange > 0) // in that case we just trust the GLyphLayout grow() + { + chars = contextGlyphsString.mid(contextStringPointer,contexLengthChange + len); + contexLengthChange = 0; + } + else if(contexLengthChange == 0) + { + if(contextStringPointer == -1) contextStringPointer = 0; + chars = contextGlyphsString.mid(contextStringPointer,len); + } + //contextStringPointer += 1; + } + else + { + chars = contextString.mid(contextStringPointer,len); + } + qDebug(QString("char is [%1], contextGlyphsString is [%2], contextStringPointer[%3], len [%4]").arg(chars[0].unicode()).arg(contextGlyphsString).arg(contextStringPointer).arg(len)); + double retval = 0.0; + double asce = style.font().ascent(style.fontSize() / 10.0); + int chst = style.effects() & 1919; + if (chars[0] == SpecialChars::ZWSPACE || + chars[0] == SpecialChars::ZWNBSPACE || + chars[0] == SpecialChars::NBSPACE || + chars[0] == SpecialChars::NBHYPHEN || + chars[0] == SpecialChars::SHYPHEN || + chars[0] == SpecialChars::PARSEP || + chars[0] == SpecialChars::COLBREAK || + chars[0] == SpecialChars::LINEBREAK || + chars[0] == SpecialChars::FRAMEBREAK || + chars[0] == SpecialChars::TAB) + { + layout.glyph = ScFace::CONTROL_GLYPHS + chars[0].unicode(); + } + else + { + layout.glyph = style.font().char2CMap(chars[0].unicode()); //otf comment : here we assume that the proper pair is in the c_Map cache + } + + double tracking = 0.0; + if ( (style.effects() & ScStyle_StartOfLine) == 0) + tracking = style.fontSize() * style.tracking() / 10000.0; + + layout.xoffset = tracking; + layout.yoffset = 0; + if (chst != ScStyle_Default) + { + if (chst & ScStyle_Superscript) + { + retval -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.yoffset -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSuperScript / 100.0, 10.0 / style.fontSize()); + } + else if (chst & ScStyle_Subscript) + { + retval += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.yoffset += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSubScript / 100.0, 10.0 / style.fontSize()); + } + else { + layout.scaleV = layout.scaleH = 1.0; + } + layout.scaleH *= style.scaleH() / 1000.0; + layout.scaleV *= style.scaleV() / 1000.0; + if (chst & ScStyle_AllCaps) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + } + if (chst & ScStyle_SmallCaps) + { + + double smallcapsScale = m_Doc->typographicSettings.valueSmallCaps / 100.0; + QChar uc = chars[0].upper(); + if (uc != chars[0]) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + layout.scaleV *= smallcapsScale; + layout.scaleH *= smallcapsScale; + } + } + } + else { + layout.scaleH = style.scaleH() / 1000.0; + layout.scaleV = style.scaleV() / 1000.0; + } + + if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) { + uint replGlyph = style.font().char2CMap(QChar(' ')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode())) { + uint replGlyph = style.font().char2CMap(QChar('-')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph >= ScFace::CONTROL_GLYPHS) { + layout.xadvance = 0; + layout.yadvance = 0; + } + else { + layout.xadvance = style.font().glyphWidth(layout.glyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(layout.glyph, style.fontSize() / 10).ascent * layout.scaleV; + } + if (layout.xadvance > 0) + layout.xadvance += tracking; + + if (chars.length() > 1) { + layout.grow(); + contextStringPointer += 1; + layoutGlyphs(style, chars.length()-1, *layout.more); + layout.xadvance += style.font().glyphKerning(layout.glyph, layout.more->glyph, style.fontSize() / 10) * layout.scaleH; + if (layout.more->yadvance > layout.yadvance) + layout.yadvance = layout.more->yadvance; + } + else { + contextStringPointer += 1; + layout.shrink(); + } + + return retval; +} + void PageItem::drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs) { uint glyph = glyphs.glyph; if ((m_Doc->guidesSettings.showControls) && (glyph == style.font().char2CMap(QChar(' ')) || glyph >= ScFace::CONTROL_GLYPHS)) { bool stroke = false; if (glyph >= ScFace::CONTROL_GLYPHS) Index: scribus/pageitem.h =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.h,v retrieving revision 1.26.2.181 diff -u -8 -p -r1.26.2.181 pageitem.h --- scribus/pageitem.h 6 Mar 2007 21:32:15 -0000 1.26.2.181 +++ scribus/pageitem.h 19 Mar 2007 20:40:41 -0000 @@ -289,16 +289,17 @@ public: /// returns the style at the current charpos const ParagraphStyle& currentStyle() const; /// returns the style at the current charpos ParagraphStyle& changeCurrentStyle(); /// returns the style at the current charpos const CharStyle& currentCharStyle() const; // deprecated: double layoutGlyphs(const CharStyle& style, const QString chars, GlyphLayout& layout); + double layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout); void SetFarbe(QColor *tmp, QString farbe, int shad); void drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs ); void DrawPolyL(QPainter *p, QPointArray pts); QString ExpandToken(uint base); bool AutoName; double gXpos; double gYpos; @@ -1208,16 +1209,22 @@ public: /** Darstellungsart Bild/Titel */ bool PicArt; /** Line width */ double m_lineWidth; double Oldm_lineWidth; + /** Context String */ + QString contextString; + QString contextGlyphsString; + int contextStringPointer; + int contexLengthChange; + signals: //Frame signals void myself(PageItem *); void frameType(int); // not related to Frametype but to m_itemIype :-/ void position(double, double); //X,Y void widthAndHeight(double, double); //W,H void rotation(double); //Degrees rotation void colors(QString, QString, int, int); //lineColor, fillColor, lineShade, fillShade Index: scribus/pageitem_textframe.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/pageitem_textframe.cpp,v retrieving revision 1.1.2.152 diff -u -8 -p -r1.1.2.152 pageitem_textframe.cpp --- scribus/pageitem_textframe.cpp 11 Mar 2007 15:12:07 -0000 1.1.2.152 +++ scribus/pageitem_textframe.cpp 19 Mar 2007 20:40:47 -0000 @@ -214,17 +214,17 @@ static void dumpIt(const ParagraphStyle& .arg(pstyle.lineSpacing()) .arg(pstyle.alignment())); static QString more(" "); if (pstyle.hasParent()) dumpIt(*dynamic_cast<const ParagraphStyle*>(pstyle.parentStyle()), more + indent); } -static const bool legacy = true; +static const bool legacy = false; static void layoutDropCap(GlyphLayout layout, double curX, double curY, double offsetX, double offsetY, double dropCapDrop) { } static void fillInTabLeaders(StoryText & itemText, LineSpec & curLine) @@ -537,17 +537,47 @@ static double opticalRightMargin(const S rightCorr = itemText.charStyle(b).font().charWidth(chr, chs / 10.0); rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); } return rightCorr; } return 0.0; } +// TEST +static void prepareText(StoryText& itemText, int begin, int end) +{ + /* here, it could be possible to send text to a substitution engine */ + /* example (pseudopseudocode): + QString final = itemText.charStyle(i)->font->subtitute(itemText.text(begin , end - begin), itemText.charStyle(i)->font->sub_features_set()); + + for(int i = begin, i <= end ; ++i) + { + if(final.at(i)) itemText.item(i)->ch = final.at(i); + else itemText.remove(i); + } + + + */ + +// if(itemText.charStyle(begin).font().isOTF()) +// { +// QString os = itemText.text(begin, end - begin ); +// QString ns = itemText.charStyle(begin).font().otfSub(os); +// if(os != ns) +// { +// CharStyle back = itemText.charStyle(begin); +// itemText.removeChars(begin , end); +// itemText.insertChars( begin , ns ); +// itemText.setCharStyle(begin , ns.length() , back ); +// } +// } +} +// ENDTEST void PageItem_TextFrame::layout() { if (BackBox != NULL && BackBox->invalid) { // qDebug("textframe: len=%d, going back", itemText.length()); invalid = false; PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); if (!prevInChain) @@ -671,18 +701,93 @@ void PageItem_TextFrame::layout() { desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; } current.startLine(firstInFrame()); outs = false; OFs = 0; MaxChars = 0; + //TEST +// CharStyle control_charstyle; +// int begin_prepare; +// int end_prepare = begin_prepare = firstInFrame(); +// for (int a = firstInFrame(); a < itemText.length(); ++a) +// { +// if(a == begin_prepare) +// { +// control_charstyle = itemText.charStyle(a); +// continue; +// } +// if(control_charstyle != itemText.charStyle(a)) +// { +// end_prepare = a-1; +// prepareText(itemText, begin_prepare, end_prepare); +// begin_prepare = end_prepare = a; +// control_charstyle = itemText.charStyle(a); +// continue; +// } +// if(a == itemText.length() -1) +// { +// prepareText(itemText, begin_prepare, a + 1); +// break; +// } +// ++end_prepare; +// } + // ENDTEST + // BIGLOOP + int contextrest = 0; + int sccontrol; for (int a = firstInFrame(); a < itemText.length(); ++a) { + // here we set the context string + if(contextrest == 0) + { + contextString = ""; + sccontrol = 0; + for(int ctsg = a; ctsg < itemText.length(); ++ctsg) + { + + QString contmp = ExpandToken(ctsg); + if(contmp[0] == SpecialChars::ZWSPACE || + contmp[0] == SpecialChars::ZWNBSPACE || + contmp[0] == SpecialChars::NBSPACE || + contmp[0] == SpecialChars::NBHYPHEN || + contmp[0] == SpecialChars::SHYPHEN || + contmp[0] == SpecialChars::PARSEP || + contmp[0] == SpecialChars::COLBREAK || + contmp[0] == SpecialChars::LINEBREAK || + contmp[0] == SpecialChars::FRAMEBREAK || + contmp[0] == SpecialChars::TAB || + contmp[0] == SpecialChars::BLANK) + { + if(sccontrol > 0) + { + break; + } + else + { + contextString += QChar(0) ; + contextString += contmp[0].unicode(); + break; + } + } + else + { + sccontrol += 1; + contextString += contmp; + } + } + contextrest = (sccontrol == 0 ? 1 : contextString.length());// we send special char one by one + contextStringPointer = 0; + qDebug(QString("contextrest = %1 and context string is \"%2\"").arg(contextrest).arg(contextString)); + } + --contextrest; + + hl = itemText.item(a); if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) style = itemText.paragraphStyle(a); if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); // qDebug(QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); const CharStyle& charStyle = itemText.charStyle(a); @@ -857,17 +962,19 @@ void PageItem_TextFrame::layout() kernVal = 0; } else { kernVal = 0; // chs * charStyle.tracking() / 10000.0; itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); } hl->glyph.yadvance = 0; - oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); + //qDebug(QString("sending [%1] to layoutGlyphs()").arg(chstr)); + oldCurY = layoutGlyphs(*hl, chstr.length(), hl->glyph); + //oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); // find out width of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); else { /* if (a+1 < itemText.length()) { chstr3 = itemText.text(a+1); Index: scribus/fonts/CMakeLists.txt =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/CMakeLists.txt,v retrieving revision 1.1.2.1 diff -u -8 -p -r1.1.2.1 CMakeLists.txt --- scribus/fonts/CMakeLists.txt 23 Jul 2006 12:07:47 -0000 1.1.2.1 +++ scribus/fonts/CMakeLists.txt 19 Mar 2007 20:40:50 -0000 @@ -5,12 +5,24 @@ ${CMAKE_SOURCE_DIR}/scribus SET(SCRIBUS_FONTS_LIB_SOURCES scface.cpp ftface.cpp scface_ps.cpp scface_ttf.cpp scfontmetrics.cpp +myotf.cpp ) +SET(OTF_DIR ${CMAKE_MODULE_PATH}) +FIND_PACKAGE(OTF REQUIRED) +IF(OTF_FOUND) + SET(HAVE_OTF 1) + MESSAGE("LIBOTF Library found") +ELSE(OTF_FOUND) + MESSAGE(FATAL_ERROR "Could not find the libOtf Library") +ENDIF(OTF_FOUND) + +LINK_LIBRARIES ( ${OTF_LIBRARIES}) + SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.9 diff -u -8 -p -r1.1.2.9 ftface.cpp --- scribus/fonts/ftface.cpp 11 Jan 2007 15:29:46 -0000 1.1.2.9 +++ scribus/fonts/ftface.cpp 19 Mar 2007 20:40:51 -0000 @@ -136,36 +136,57 @@ void FtFace::load() const ++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; } + //TEST libotf + if(typeCode == ScFace::OTF) + { + _otf = new myotf(QFile::encodeName(fontFile)); + //here we make otf init "by hand" and it's just intended to work with the MinionPro shipped with adobe reader + otfScript = "latn"; + otfLang = "default"; + otfSubFeatures.append("liga"); + otfSubFeatures.append("dlig"); + otfSubFeatures.append("onum"); + otfPosFeatures.append("kern"); + otfPosFeatures.append("cpsp"); + } } void FtFace::unload() const { if (m_face) { FT_Done_Face( m_face ); m_face = NULL; } // clear caches + if(_otf) delete _otf; 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; + if(m_cMap.contains(ch.unicode())) + { + return m_cMap[ch.unicode()]; + } + else + { + FT_Face face = ftFace(); + uint gl = FT_Get_Char_Index(face, ch.unicode()); + m_cMap.insert(ch.unicode(), gl); + return gl; + } } void FtFace::loadGlyph(uint gl) const { if (m_glyphWidth.contains(gl)) return; @@ -307,9 +328,27 @@ void FtFace::RawData(QByteArray & bb) co // 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())); } */ } +QString FtFace::otfied(QString s) const +{ + if(typeCode == ScFace::OTF) + { + int nbg = _otf->procstring(s,otfScript,otfLang,otfSubFeatures,otfPosFeatures); + QString newstring; + for (int i = 0; i < nbg ; ++i) + { + newstring += QChar(_otf->unicode( _otf->otfString()->glyphs[i].glyph_id )); + m_cMap.insert(_otf->unicode( _otf->otfString()->glyphs[i].glyph_id), _otf->otfString()->glyphs[i].glyph_id); + } + + + qDebug(QString("oldstring is \"%1\" and new string os \"%2\"").arg(s).arg(newstring)); + return newstring; + } + return s; +} Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -8 -p -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 19 Mar 2007 20:40:51 -0000 @@ -107,11 +107,20 @@ protected: mutable double m_height; mutable double m_xHeight; mutable double m_capHeight; mutable double m_maxAdvanceWidth; mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + //TEST libotf + public: + mutable QStringList otfSubFeatures; + mutable QStringList otfPosFeatures; + mutable QString otfScript; + mutable QString otfLang; + QString otfied(QString s) const ; + mutable myotf * _otf; + }; #endif Index: scribus/fonts/myotf.cpp =================================================================== RCS file: scribus/fonts/myotf.cpp diff -N scribus/fonts/myotf.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.cpp 19 Mar 2007 20:40:52 -0000 @@ -0,0 +1,596 @@ +/* un test de libotf mer18jan */ + + +#include "myotf.h" + + + +void +myotf::set_subalt (bool b) +{ + subAlt = b; +} + +int +myotf::get_glyph_used() +{ + return mys.used; +} + +myotf::myotf (QString n) +{ + nom = n; + my = OTF_open ((char*)nom.ascii()); + subAlt = false; + glyphAlloc = false; + if (OTF_get_table (my, "head") == 0) + head = 1; + else + head = 0; + if (OTF_get_table (my, "name") == 0) + name = 1; + else + name = 0; + if (OTF_get_table (my, "cmap") == 0) + cmap = 1; + else + cmap = 0; + if (OTF_get_table (my, "GDEF") == 0) + GDEF = 1; + else + GDEF = 0; + if (OTF_get_table (my, "GSUB") == 0) + GSUB = 1; + else + GSUB = 0; + if (OTF_get_table (my, "GPOS") == 0) + GPOS = 1; + else + GPOS = 0; + // if (GSUB){ OTF_get_scripts (my, 1); OTF_get_features (my, 1);} + // if (GPOS){ OTF_get_scripts (my, 0); OTF_get_features (my, 0);} + +/* + std::cout << "head : " << head << "\n"; + std::cout << "name : " << name << "\n"; + std::cout << "cmap : " << cmap << "\n"; + std::cout << "GDEF : " << GDEF << "\n"; + std::cout << "GSUB : " << GSUB << "\n"; + std::cout << "GPOS : " << GPOS << "\n"; +*/ +} + +myotf::~myotf () +{ + if (glyphAlloc) + free (mys.glyphs); + OTF_close (my); +} + +int +myotf::procstring (QString s) +{ + int n = s.length(); + if (glyphAlloc) + free (mys.glyphs); + mys.size = n; + mys.used = n; + mys.glyphs = (OTF_Glyph *) calloc (n , sizeof (OTF_Glyph)); + glyphAlloc = true; + OTF_error = 0; + for (int i = 0; i < n; i++) + { + mys.glyphs[i].c = s[i].unicode(); + mys.glyphs[i].glyph_id = 0; + } + + if(OTF_drive_cmap (my, &mys))OTF_perror("drive_cmap ") ; + + for (int i = 0; i < mys.used; i++) + { + std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode( my, mys.glyphs[i].glyph_id) << " : " << dec; + } + cout << "\n"; + + QString fe; + for (QStringList::iterator ife = curFeatures.begin (); + ife != curFeatures.end (); ife++) + { + fe += *ife; + fe += ','; + } + //*(fe.end()) = NULL ; + + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + char *argfe = (char *) fe.ascii(); + + if (GDEF) + {if(OTF_drive_gdef(my, &mys) != 0 )OTF_perror("drive_GDEF ");} + + if (curTable == "GPOS") + { + if(OTF_drive_gpos (my, &mys, argsc, argla, argfe))OTF_perror("drive_GPOS"); + OTF_perror("force(drive_GPOS)"); + for( int n = 0; n < mys.used ; n++) + get_position(n); + } + + if (curTable == "GSUB") + { + if (!subAlt) + { + if(OTF_drive_gsub (my, &mys, argsc, argla, argfe))OTF_perror("drive_GSUB"); + } + else + { + if(OTF_drive_gsub_alternate (my, &mys, argsc, argla, argfe))OTF_perror("drive_GSUB_alt"); + + } + } + + + for (int i = 0; i < mys.used; i++) + { + std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode (my , mys.glyphs[i].glyph_id ) << " : " << dec ; + std::cout << '['<<(char)OTF_get_unicode (my , mys.glyphs[i].glyph_id )<<']' ; + } + cout << "\n"; + + + + return mys.used; +} + +int + myotf::procstring (QString s,QString script, QString lang, QStringList gsub, QStringList gpos) +{ + int n = s.length(); + if (glyphAlloc) + free (mys.glyphs); + mys.size = n; + mys.used = n; + mys.glyphs = (OTF_Glyph *) calloc (n , sizeof (OTF_Glyph)); + glyphAlloc = true; + OTF_error = 0; + for (int i = 0; i < n; i++) + { + mys.glyphs[i].c = s[i].unicode(); + mys.glyphs[i].glyph_id = 0; + } + + if(OTF_drive_cmap (my, &mys))OTF_perror("drive_cmap ") ; + +// for (int i = 0; i < mys.used; i++) +// { +// std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode( my, mys.glyphs[i].glyph_id) << " : " << dec; +// } +// cout << "\n"; + + QString gsubfe; + for (QStringList::iterator ife = gsub.begin (); + ife != gsub.end (); ife++) + { + gsubfe += *ife; + gsubfe += ','; + } + QString gposfe; + for (QStringList::iterator ife = gpos.begin (); + ife != gpos.end (); ife++) + { + gposfe += *ife; + gposfe += ','; + } + //*(fe.end()) = NULL ; + + char *argsc = (char *) script.ascii(); + char *argla = (char *) lang.ascii(); + char *arggsubfe = (char *) gsubfe.ascii(); + char *arggposfe = (char *) gposfe.ascii(); + + if (GDEF) + { + if(OTF_drive_gdef(my, &mys) != 0 )OTF_perror("drive_GDEF "); + } + if (GSUB) + { + if(OTF_drive_gsub(my, &mys, argsc, argla, arggsubfe))OTF_perror("drive_GSUB"); + } + if (GPOS) + { + if(OTF_drive_gpos(my, &mys, argsc, argla, arggposfe))OTF_perror("drive_GPOS"); + } + +// for (int i = 0; i < mys.used; i++) +// { +// std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode (my , mys.glyphs[i].glyph_id ) << " : " << dec ; +// std::cout << '['<<(char)OTF_get_unicode (my , mys.glyphs[i].glyph_id )<<']' ; +// } +// cout << "\n"; +// + + + return mys.used; +} + +int +myotf::procstring() +{ + QString fe; + for (QStringList::iterator ife = curFeatures.begin (); + ife != curFeatures.end (); ife++) + { + fe += *ife; + fe += ','; + } + //*(fe.end()) = NULL ; + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + char *argfe = (char *) fe.ascii(); + + if (curTable == "GPOS") + { + OTF_drive_gpos (my, &mys, argsc, argla, argfe); + for( int n = 0; n < mys.used ; n++) + get_position(n); + } + + if (curTable == "GSUB") + if (!subAlt) + { + OTF_drive_gsub (my, &mys, argsc, argla, argfe); + } + else + { + OTF_drive_gsub_alternate (my, &mys, argsc, argla, argfe); + + } + for (int i = 0; i < mys.used; i++) + { + std::cout << mys.glyphs[i].glyph_id << " : "; + } + cout << "\n"; + + + + return mys.used; +} + + + + + +QStringList myotf::get_tables () +{ + QStringList ret; + + if (GDEF) + ret.insert (ret.end (), "GDEF"); + if (GPOS) + ret.insert (ret.end (), "GPOS"); + if (GSUB) + ret.insert (ret.end (), "GSUB"); + + return ret; +} + +void +myotf::set_table (QString s) +{ + curTable = s; +} + +QStringList myotf::get_scripts () +{ + QStringList ret; + char + aa[5]; + if (curTable == "GSUB") + { + int + ns = my->gsub->ScriptList.ScriptCount; + char * + a = aa; + std:: + cout << "Il y a " << ns << " systèmes d'écriture dans cette fonte.\n"; + for (int i = 0; i < ns; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[i].ScriptTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GPOS") + { + int + ns = my->gpos->ScriptList.ScriptCount; + char * + a = aa; + std:: + cout << "Il y a " << ns << " systèmes d'écriture dans cette fonte.\n"; + for (int i = 0; i < ns; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[i].ScriptTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + return ret; + +} + +void +myotf::set_script (QString s) +{ + char a[5]; + if (curTable == "GPOS") + { + for (int i = 0; i < my->gpos->ScriptList.ScriptCount; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[i].ScriptTag, a); + if (a == s) + curScript = i; + } + } + if (curTable == "GSUB") + { + for (int i = 0; i < my->gsub->ScriptList.ScriptCount; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[i].ScriptTag, a); + if (a == s) + curScript = i; + } + } + curScriptName = s; +} + + +QStringList myotf::get_langs () +{ + QStringList ret; + char + a[5]; + if (curTable == "GPOS") + { + int + nl = my->gpos->ScriptList.Script[curScript].LangSysCount; + cout << "Il y a là " << nl << " langues" << "\n"; + for (int i = 0; i < nl; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GSUB") + { + int + nl = my->gsub->ScriptList.Script[curScript].LangSysCount; + cout << "Il y a là " << nl << " langues" << "\n"; + for (int i = 0; i < nl; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + + return ret; +} + +void +myotf::set_lang (QString s) +{ + if (s == "default") + { + curLangName = "dflt"; + curLang = -1; + return; + } + + char a[5]; + if (curTable == "GPOS") + { + for (int i = 0; i < my->gpos->ScriptList.Script[curScript].LangSysCount; + i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + if (a == s) + curLang = i; + } + } + if (curTable == "GSUB") + { + for (int i = 0; i < my->gsub->ScriptList.Script[curScript].LangSysCount; + i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + if (a == s) + curLang = i; + } + } + curLangName = s; +} + + +QStringList myotf::get_features () +{ + QStringList ret; + char + a[10]; + int + nf, + findex, + i; + OTF_Tag + ftag; + if (curTable == "GPOS") + { + if (curLang >= 0) + nf = + my->gpos->ScriptList.Script[curScript].LangSys[curLang]. + FeatureCount; + else + nf = + my->gpos->ScriptList.Script[curScript].DefaultLangSys.FeatureCount; + cout << "Il y a là " << nf << " fonctionnalités " << "\n"; + for (i = 0; i < nf; i++) + { + if (curLang >= 0) + { + findex = + my->gpos->ScriptList.Script[curScript].LangSys[curLang]. + FeatureIndex[i]; + ftag = my->gpos->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + else + { + findex = + my->gpos->ScriptList.Script[curScript].DefaultLangSys. + FeatureIndex[i]; + ftag = my->gpos->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GSUB") + { + if (curLang >= 0) + nf = + my->gsub->ScriptList.Script[curScript].LangSys[curLang]. + FeatureCount; + else + nf = + my->gsub->ScriptList.Script[curScript].DefaultLangSys.FeatureCount; + + cout << "Il y a là " << nf << " fonctionnalités " << "\n"; + + for (i = 0; i < nf; i++) + { + + if (curLang >= 0) + { + findex = + my->gsub->ScriptList.Script[curScript].LangSys[curLang]. + FeatureIndex[i]; + ftag = my->gsub->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + else + { + findex = + my->gsub->ScriptList.Script[curScript].DefaultLangSys. + FeatureIndex[i]; + ftag = my->gsub->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + return ret; +} + +void +myotf::set_features (QStringList ls) +{ + curFeatures = ls; +} + + +int +myotf::get_position_type (int ind) +{ + return (mys.glyphs[ind].positioning_type); +} + +posglyph +myotf::get_position(int g) +{ + posglyph ret; + int gt = get_position_type(g); + OTF_Glyph og = mys.glyphs[g] ; + if (gt == 1) + { + for( int i= 0x00001 ; i < 0x0081 ; i*=2) + { + if(og.f.f1.format & i ) + { + switch (i) + { + case 0x0001 : ret.Xposition = og.f.f1.value->XPlacement ; + break; + case 0x0002 : ret.Yposition = og.f.f1.value->YPlacement ; + break; + case 0x0004 : ret.Xadvance = og.f.f1.value->XAdvance ; + break; + case 0x0008 : ret.Yadvance = og.f.f1.value->YAdvance ; + break; + default : qDebug( "Don't know how to handle OTF_DeviceTable!"); + break; + } + } + } + } + if (gt == 2) + { + for( int i= 0x0001 ; i < 0x0081 ; i*=2) + { + if(og.f.f2.format & i) + { + switch (i) + { + case 0x0001 : ret.Xposition = og.f.f1.value->XPlacement ; + break; + case 0x0002 : ret.Yposition = og.f.f1.value->YPlacement ; + break; + case 0x0004 : ret.Xadvance = og.f.f1.value->XAdvance ; + break; + case 0x0008 : ret.Yadvance = og.f.f1.value->YAdvance ; + break; + default : qDebug( "Don't know how to handle OTF_DeviceTable!"); + break; + } + } + } + } + return ret; +} + + + + + +// int +// main (int ac, char **av) +// { +// myotf lafonte (av[1]); +// QStringList feat; +// lafonte.set_table (av[3]); +// lafonte.set_script (av[4]); +// lafonte.set_lang (av[5]); +// +// for(int c = 6; c < ac ; c++) +// { +// cout << av[c] << "\n"; +// feat.insert(feat.end(), av[c]); +// } +// // feat.insert(feat.end(), "cpsp"); +// lafonte.set_features (feat); +// // int use; +// lafonte.procstring (av[2]); +// return 0; +// } Index: scribus/fonts/myotf.h =================================================================== RCS file: scribus/fonts/myotf.h diff -N scribus/fonts/myotf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.h 19 Mar 2007 20:40:52 -0000 @@ -0,0 +1,94 @@ +// myotf.h + +#ifndef WRAPLIBOTF +#define WRAPLIBOTF + + +extern "C" +{ +#include <otf.h> +#include <stdlib.h> +} + +#include <iostream> +#include <iomanip> + +#include <qstring.h> +#include <qstringlist.h> + +using namespace std; + +struct posglyph +{ + double Xposition; + double Yposition; + double Xadvance; + double Yadvance; + double xadvance(){return Xadvance;} + double yadvance(){return Yadvance;} + double xposition(){return Xposition;} + double yposition(){return Yposition;} +}; + +class myotf +{ + QString nom; + + OTF *my; + OTF_GlyphString mys; + + + + bool subAlt; + bool glyphAlloc; + + int head, name, cmap, GDEF, GSUB, GPOS; + +public: + OTF_GlyphString * otfString() {return &mys;} + int unicode(int gid){ return OTF_get_unicode(my, gid);} + QString curTable; + int curScript, curLang; + QString curScriptName, curLangName; + QStringList curFeatures; + myotf (QString n); + ~myotf (); +/* + * These members functions apply features currently set + */ + int procstring (QString ); + int procstring (); + int procstring (QString s, QString script, QString lang, QStringList gsub, QStringList gpos); +/* + * These functions give access to informations contained in the fontfile + */ + QStringList get_tables (); + QStringList get_scripts (); + QStringList get_langs (); + QStringList get_features (); +/* + * These allow to set up the features ( Tab -> Scr -> Lan -> Fea ) + */ + void set_table (QString); + void set_script (QString); + void set_lang (QString); + void set_features (QStringList); + void set_subalt (bool); +/* + * I can't remember what this so important method is expected to achieve ! + */ + int get_position_type (int); + /* + * for the moment, it just does nothing. Because I have no idea + * of which sruct can be the target of this function.Nevertheless + * I'm clearly aware that's the key function, it's the reason why + * i put this apart from procstring(). + * The argument is the number of the glyph + */ + + posglyph get_position(int); + int get_glyph_used(); + +}; + +#endif Index: scribus/fonts/scface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/scface.h,v retrieving revision 1.1.2.10 diff -u -8 -p -r1.1.2.10 scface.h --- scribus/fonts/scface.h 26 Nov 2006 13:15:19 -0000 1.1.2.10 +++ scribus/fonts/scface.h 19 Mar 2007 20:40:56 -0000 @@ -16,16 +16,19 @@ virtual: dispatch to constituents, #include <qstring.h> //#include <qvector.h> #include <qmap.h> //#include <qarray.h> #include <utility> #include "fpointarray.h" +//TEST libotf + +#include "myotf.h" struct GlyphMetrics { double width; double ascent; double descent; }; @@ -166,16 +169,19 @@ public: 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<uint, std::pair<QChar, QString> >& gList) const; + + virtual QString otfied(QString s) const {return s;} + // 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; }; @@ -351,16 +357,19 @@ public: 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; } + //TEST libotf + QString otfied (QString s) const { return m->otfied(s); } + private: friend class SCFonts; ScFace(ScFaceData* md); ScFaceData* m; QString replacedName; QString replacedInDoc; |
2007-03-20 09:08
|
myotf-patch-3.diff (37,774 bytes)
Index: scribus/pageitem.cpp =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.cpp,v retrieving revision 1.121.2.418 diff -u -8 -p -r1.121.2.418 pageitem.cpp --- scribus/pageitem.cpp 12 Mar 2007 15:57:39 -0000 1.121.2.418 +++ scribus/pageitem.cpp 20 Mar 2007 09:06:47 -0000 @@ -1747,16 +1747,170 @@ double PageItem::layoutGlyphs(const Char layout.yadvance = layout.more->yadvance; } else { layout.shrink(); } return retval; } +// the same, but character to render is retrieved from contextStringPointer +double PageItem::layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout) +{ + QString chars; + bool otf = style.font().isOTF(); + if(contextString[0] == 0) // We have a special char that can't be processed by libotf + { + chars = contextString[1].unicode(); + } + else if(otf) + { + + if (contextStringPointer == 0) + { + contextGlyphsString = style.font().otfied(contextString); + //Now, we have 4 possibilities : + // 1/ one glyph for one character ; + // 2/ many glyphs for one character ; + // 3/ one glyph for many characters ; + // 4/ nothing if character was rendered in a previous case 3 call. + // Too much complicated for me, I take the shorter way. + int ls = contextString.length(); + int lg = contextGlyphsString.length(); + contexLengthChange = lg - ls; + } + if (contexLengthChange < 0) // source string is longer then the rendered string + { + contexLengthChange += 1; // waiting + contextStringPointer = -1; + layout.glyph = ScFace::CONTROL_GLYPHS + SpecialChars::ZWSPACE.unicode(); + return 0.0; + } + else if (contexLengthChange > 0) // in that case we just trust the GLyphLayout grow() + { + chars = contextGlyphsString.mid(contextStringPointer,contexLengthChange + len); + contexLengthChange = 0; + } + else if(contexLengthChange == 0) + { + if(contextStringPointer == -1) contextStringPointer = 0; + chars = contextGlyphsString.mid(contextStringPointer,len); + } + //contextStringPointer += 1; + } + else + { + chars = contextString.mid(contextStringPointer,len); + } + qDebug(QString("char is [%1], contextGlyphsString is [%2], contextStringPointer[%3], len [%4]").arg(chars[0].unicode()).arg(contextGlyphsString).arg(contextStringPointer).arg(len)); + double retval = 0.0; + double asce = style.font().ascent(style.fontSize() / 10.0); + int chst = style.effects() & 1919; + if (chars[0] == SpecialChars::ZWSPACE || + chars[0] == SpecialChars::ZWNBSPACE || + chars[0] == SpecialChars::NBSPACE || + chars[0] == SpecialChars::NBHYPHEN || + chars[0] == SpecialChars::SHYPHEN || + chars[0] == SpecialChars::PARSEP || + chars[0] == SpecialChars::COLBREAK || + chars[0] == SpecialChars::LINEBREAK || + chars[0] == SpecialChars::FRAMEBREAK || + chars[0] == SpecialChars::TAB) + { + layout.glyph = ScFace::CONTROL_GLYPHS + chars[0].unicode(); + } + else + { + layout.glyph = style.font().char2CMap(chars[0].unicode()); //otf comment : here we assume that the proper pair is in the c_Map cache + } + + double tracking = 0.0; + if ( (style.effects() & ScStyle_StartOfLine) == 0) + tracking = style.fontSize() * style.tracking() / 10000.0; + + layout.xoffset = tracking; + layout.yoffset = 0; + if (chst != ScStyle_Default) + { + if (chst & ScStyle_Superscript) + { + retval -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.yoffset -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSuperScript / 100.0, 10.0 / style.fontSize()); + } + else if (chst & ScStyle_Subscript) + { + retval += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.yoffset += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSubScript / 100.0, 10.0 / style.fontSize()); + } + else { + layout.scaleV = layout.scaleH = 1.0; + } + layout.scaleH *= style.scaleH() / 1000.0; + layout.scaleV *= style.scaleV() / 1000.0; + if (chst & ScStyle_AllCaps) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + } + if (chst & ScStyle_SmallCaps) + { + + double smallcapsScale = m_Doc->typographicSettings.valueSmallCaps / 100.0; + QChar uc = chars[0].upper(); + if (uc != chars[0]) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + layout.scaleV *= smallcapsScale; + layout.scaleH *= smallcapsScale; + } + } + } + else { + layout.scaleH = style.scaleH() / 1000.0; + layout.scaleV = style.scaleV() / 1000.0; + } + + if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) { + uint replGlyph = style.font().char2CMap(QChar(' ')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode())) { + uint replGlyph = style.font().char2CMap(QChar('-')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph >= ScFace::CONTROL_GLYPHS) { + layout.xadvance = 0; + layout.yadvance = 0; + } + else { + layout.xadvance = style.font().glyphWidth(layout.glyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(layout.glyph, style.fontSize() / 10).ascent * layout.scaleV; + } + if (layout.xadvance > 0) + layout.xadvance += tracking; + + if (chars.length() > 1) { + layout.grow(); + contextStringPointer += 1; + layoutGlyphs(style, chars.length()-1, *layout.more); + layout.xadvance += style.font().glyphKerning(layout.glyph, layout.more->glyph, style.fontSize() / 10) * layout.scaleH; + if (layout.more->yadvance > layout.yadvance) + layout.yadvance = layout.more->yadvance; + } + else { + contextStringPointer += 1; + layout.shrink(); + } + + return retval; +} + void PageItem::drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs) { uint glyph = glyphs.glyph; if ((m_Doc->guidesSettings.showControls) && (glyph == style.font().char2CMap(QChar(' ')) || glyph >= ScFace::CONTROL_GLYPHS)) { bool stroke = false; if (glyph >= ScFace::CONTROL_GLYPHS) Index: scribus/pageitem.h =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.h,v retrieving revision 1.26.2.181 diff -u -8 -p -r1.26.2.181 pageitem.h --- scribus/pageitem.h 6 Mar 2007 21:32:15 -0000 1.26.2.181 +++ scribus/pageitem.h 20 Mar 2007 09:06:49 -0000 @@ -289,16 +289,17 @@ public: /// returns the style at the current charpos const ParagraphStyle& currentStyle() const; /// returns the style at the current charpos ParagraphStyle& changeCurrentStyle(); /// returns the style at the current charpos const CharStyle& currentCharStyle() const; // deprecated: double layoutGlyphs(const CharStyle& style, const QString chars, GlyphLayout& layout); + double layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout); void SetFarbe(QColor *tmp, QString farbe, int shad); void drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs ); void DrawPolyL(QPainter *p, QPointArray pts); QString ExpandToken(uint base); bool AutoName; double gXpos; double gYpos; @@ -1208,16 +1209,22 @@ public: /** Darstellungsart Bild/Titel */ bool PicArt; /** Line width */ double m_lineWidth; double Oldm_lineWidth; + /** Context String */ + QString contextString; + QString contextGlyphsString; + int contextStringPointer; + int contexLengthChange; + signals: //Frame signals void myself(PageItem *); void frameType(int); // not related to Frametype but to m_itemIype :-/ void position(double, double); //X,Y void widthAndHeight(double, double); //W,H void rotation(double); //Degrees rotation void colors(QString, QString, int, int); //lineColor, fillColor, lineShade, fillShade Index: scribus/pageitem_textframe.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/pageitem_textframe.cpp,v retrieving revision 1.1.2.152 diff -u -8 -p -r1.1.2.152 pageitem_textframe.cpp --- scribus/pageitem_textframe.cpp 11 Mar 2007 15:12:07 -0000 1.1.2.152 +++ scribus/pageitem_textframe.cpp 20 Mar 2007 09:06:55 -0000 @@ -537,17 +537,47 @@ static double opticalRightMargin(const S rightCorr = itemText.charStyle(b).font().charWidth(chr, chs / 10.0); rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); } return rightCorr; } return 0.0; } +// TEST +static void prepareText(StoryText& itemText, int begin, int end) +{ + /* here, it could be possible to send text to a substitution engine */ + /* example (pseudopseudocode): + QString final = itemText.charStyle(i)->font->subtitute(itemText.text(begin , end - begin), itemText.charStyle(i)->font->sub_features_set()); + + for(int i = begin, i <= end ; ++i) + { + if(final.at(i)) itemText.item(i)->ch = final.at(i); + else itemText.remove(i); + } + + + */ + +// if(itemText.charStyle(begin).font().isOTF()) +// { +// QString os = itemText.text(begin, end - begin ); +// QString ns = itemText.charStyle(begin).font().otfSub(os); +// if(os != ns) +// { +// CharStyle back = itemText.charStyle(begin); +// itemText.removeChars(begin , end); +// itemText.insertChars( begin , ns ); +// itemText.setCharStyle(begin , ns.length() , back ); +// } +// } +} +// ENDTEST void PageItem_TextFrame::layout() { if (BackBox != NULL && BackBox->invalid) { // qDebug("textframe: len=%d, going back", itemText.length()); invalid = false; PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); if (!prevInChain) @@ -671,18 +701,93 @@ void PageItem_TextFrame::layout() { desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; } current.startLine(firstInFrame()); outs = false; OFs = 0; MaxChars = 0; + //TEST +// CharStyle control_charstyle; +// int begin_prepare; +// int end_prepare = begin_prepare = firstInFrame(); +// for (int a = firstInFrame(); a < itemText.length(); ++a) +// { +// if(a == begin_prepare) +// { +// control_charstyle = itemText.charStyle(a); +// continue; +// } +// if(control_charstyle != itemText.charStyle(a)) +// { +// end_prepare = a-1; +// prepareText(itemText, begin_prepare, end_prepare); +// begin_prepare = end_prepare = a; +// control_charstyle = itemText.charStyle(a); +// continue; +// } +// if(a == itemText.length() -1) +// { +// prepareText(itemText, begin_prepare, a + 1); +// break; +// } +// ++end_prepare; +// } + // ENDTEST + // BIGLOOP + int contextrest = 0; + int sccontrol; for (int a = firstInFrame(); a < itemText.length(); ++a) { + // here we set the context string + if(contextrest == 0) + { + contextString = ""; + sccontrol = 0; + for(int ctsg = a; ctsg < itemText.length(); ++ctsg) + { + + QString contmp = ExpandToken(ctsg); + if(contmp[0] == SpecialChars::ZWSPACE || + contmp[0] == SpecialChars::ZWNBSPACE || + contmp[0] == SpecialChars::NBSPACE || + contmp[0] == SpecialChars::NBHYPHEN || + contmp[0] == SpecialChars::SHYPHEN || + contmp[0] == SpecialChars::PARSEP || + contmp[0] == SpecialChars::COLBREAK || + contmp[0] == SpecialChars::LINEBREAK || + contmp[0] == SpecialChars::FRAMEBREAK || + contmp[0] == SpecialChars::TAB || + contmp[0] == SpecialChars::BLANK) + { + if(sccontrol > 0) + { + break; + } + else + { + contextString += QChar(0) ; + contextString += contmp[0].unicode(); + break; + } + } + else + { + sccontrol += 1; + contextString += contmp; + } + } + contextrest = (sccontrol == 0 ? 1 : contextString.length());// we send special char one by one + contextStringPointer = 0; + qDebug(QString("contextrest = %1 and context string is \"%2\"").arg(contextrest).arg(contextString)); + } + --contextrest; + + hl = itemText.item(a); if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) style = itemText.paragraphStyle(a); if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); // qDebug(QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); const CharStyle& charStyle = itemText.charStyle(a); @@ -857,17 +962,19 @@ void PageItem_TextFrame::layout() kernVal = 0; } else { kernVal = 0; // chs * charStyle.tracking() / 10000.0; itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); } hl->glyph.yadvance = 0; - oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); + //qDebug(QString("sending [%1] to layoutGlyphs()").arg(chstr)); + oldCurY = layoutGlyphs(*hl, chstr.length(), hl->glyph); + //oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); // find out width of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); else { /* if (a+1 < itemText.length()) { chstr3 = itemText.text(a+1); Index: scribus/fonts/CMakeLists.txt =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/CMakeLists.txt,v retrieving revision 1.1.2.1 diff -u -8 -p -r1.1.2.1 CMakeLists.txt --- scribus/fonts/CMakeLists.txt 23 Jul 2006 12:07:47 -0000 1.1.2.1 +++ scribus/fonts/CMakeLists.txt 20 Mar 2007 09:06:58 -0000 @@ -5,12 +5,24 @@ ${CMAKE_SOURCE_DIR}/scribus SET(SCRIBUS_FONTS_LIB_SOURCES scface.cpp ftface.cpp scface_ps.cpp scface_ttf.cpp scfontmetrics.cpp +myotf.cpp ) +SET(OTF_DIR ${CMAKE_MODULE_PATH}) +FIND_PACKAGE(OTF REQUIRED) +IF(OTF_FOUND) + SET(HAVE_OTF 1) + MESSAGE("LIBOTF Library found") +ELSE(OTF_FOUND) + MESSAGE(FATAL_ERROR "Could not find the libOtf Library") +ENDIF(OTF_FOUND) + +LINK_LIBRARIES ( ${OTF_LIBRARIES}) + SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.9 diff -u -8 -p -r1.1.2.9 ftface.cpp --- scribus/fonts/ftface.cpp 11 Jan 2007 15:29:46 -0000 1.1.2.9 +++ scribus/fonts/ftface.cpp 20 Mar 2007 09:06:59 -0000 @@ -2,16 +2,19 @@ #include "fonts/ftface.h" #include FT_OUTLINE_H #include FT_GLYPH_H #include <qobject.h> #include <qfile.h> +#include <qmessagebox.h> +#include <qinputdialog.h> + #include "scfonts.h" #include "fonts/scfontmetrics.h" // static: FT_Library FtFace::library = NULL; /***** ScFace lifecycle: unchecked -> loaded -> glyphs checked @@ -136,36 +139,104 @@ void FtFace::load() const ++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; } + //TEST libotf + if(typeCode == ScFace::OTF) + { + _otf = new myotf(QFile::encodeName(fontFile)); + bool ok; + QMessageBox::information( 0, "Scribus", + "You choose to use an OpenType Font file.\n" + "You have to set parameters for this font." ); + _otf->set_table("GSUB"); + QStringList choice = _otf->get_scripts(); + if(choice.count() > 1) + { + otfScript = QInputDialog::getItem("Scribus :: otf", "Select the script ", choice, 1, FALSE, &ok ); + _otf->set_script(otfScript); + } + else + { + otfScript = choice[0]; + _otf->set_script(otfScript); + } + choice = _otf->get_langs(); + choice.append("default"); + if(choice.count() > 1) + { + otfLang = QInputDialog::getItem("Scribus :: otf", QString("Select the language for script %1").arg(otfScript), choice, 1, FALSE, &ok ); + _otf->set_lang(otfLang); + } + else + { + otfLang = choice[0]; + _otf->set_lang(otfLang); + } + choice =_otf->get_features(); + QString ft; + while(QMessageBox::question(0,"Scribus","Want to choose features for GSUB ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select feature for lang %1").arg(otfLang), choice, 1, FALSE, &ok ); + if(ok) + otfSubFeatures.append(ft); + } + _otf->set_table("GPOS"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + choice =_otf->get_features(); + while(QMessageBox::question(0,"Scribus","Want to choose features for GPOS ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select feature for lang %1").arg(otfLang), choice, 1, FALSE, &ok ); + if(ok) + otfPosFeatures.append(ft); + } + //here we make otf init "by hand" and it's just intended to work with the MinionPro shipped with adobe reader +// otfScript = "latn"; +// otfLang = "default"; +// otfSubFeatures.append("liga"); +// otfSubFeatures.append("dlig"); +// otfSubFeatures.append("onum"); +// otfPosFeatures.append("kern"); +// otfPosFeatures.append("cpsp"); + + } } void FtFace::unload() const { if (m_face) { FT_Done_Face( m_face ); m_face = NULL; } // clear caches + if(_otf) delete _otf; 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; + if(m_cMap.contains(ch.unicode())) + { + return m_cMap[ch.unicode()]; + } + else + { + FT_Face face = ftFace(); + uint gl = FT_Get_Char_Index(face, ch.unicode()); + m_cMap.insert(ch.unicode(), gl); + return gl; + } } void FtFace::loadGlyph(uint gl) const { if (m_glyphWidth.contains(gl)) return; @@ -307,9 +378,27 @@ void FtFace::RawData(QByteArray & bb) co // 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())); } */ } +QString FtFace::otfied(QString s) const +{ + if(typeCode == ScFace::OTF) + { + int nbg = _otf->procstring(s,otfScript,otfLang,otfSubFeatures,otfPosFeatures); + QString newstring; + for (int i = 0; i < nbg ; ++i) + { + newstring += QChar(_otf->unicode( _otf->otfString()->glyphs[i].glyph_id )); + m_cMap.insert(_otf->unicode( _otf->otfString()->glyphs[i].glyph_id), _otf->otfString()->glyphs[i].glyph_id); + } + + + qDebug(QString("oldstring is \"%1\" and new string os \"%2\"").arg(s).arg(newstring)); + return newstring; + } + return s; +} Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -8 -p -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 20 Mar 2007 09:06:59 -0000 @@ -107,11 +107,20 @@ protected: mutable double m_height; mutable double m_xHeight; mutable double m_capHeight; mutable double m_maxAdvanceWidth; mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + //TEST libotf + public: + mutable QStringList otfSubFeatures; + mutable QStringList otfPosFeatures; + mutable QString otfScript; + mutable QString otfLang; + QString otfied(QString s) const ; + mutable myotf * _otf; + }; #endif Index: scribus/fonts/myotf.cpp =================================================================== RCS file: scribus/fonts/myotf.cpp diff -N scribus/fonts/myotf.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.cpp 20 Mar 2007 09:07:00 -0000 @@ -0,0 +1,596 @@ +/* un test de libotf mer18jan */ + + +#include "myotf.h" + + + +void +myotf::set_subalt (bool b) +{ + subAlt = b; +} + +int +myotf::get_glyph_used() +{ + return mys.used; +} + +myotf::myotf (QString n) +{ + nom = n; + my = OTF_open ((char*)nom.ascii()); + subAlt = false; + glyphAlloc = false; + if (OTF_get_table (my, "head") == 0) + head = 1; + else + head = 0; + if (OTF_get_table (my, "name") == 0) + name = 1; + else + name = 0; + if (OTF_get_table (my, "cmap") == 0) + cmap = 1; + else + cmap = 0; + if (OTF_get_table (my, "GDEF") == 0) + GDEF = 1; + else + GDEF = 0; + if (OTF_get_table (my, "GSUB") == 0) + GSUB = 1; + else + GSUB = 0; + if (OTF_get_table (my, "GPOS") == 0) + GPOS = 1; + else + GPOS = 0; + // if (GSUB){ OTF_get_scripts (my, 1); OTF_get_features (my, 1);} + // if (GPOS){ OTF_get_scripts (my, 0); OTF_get_features (my, 0);} + +/* + std::cout << "head : " << head << "\n"; + std::cout << "name : " << name << "\n"; + std::cout << "cmap : " << cmap << "\n"; + std::cout << "GDEF : " << GDEF << "\n"; + std::cout << "GSUB : " << GSUB << "\n"; + std::cout << "GPOS : " << GPOS << "\n"; +*/ +} + +myotf::~myotf () +{ + if (glyphAlloc) + free (mys.glyphs); + OTF_close (my); +} + +int +myotf::procstring (QString s) +{ + int n = s.length(); + if (glyphAlloc) + free (mys.glyphs); + mys.size = n; + mys.used = n; + mys.glyphs = (OTF_Glyph *) calloc (n , sizeof (OTF_Glyph)); + glyphAlloc = true; + OTF_error = 0; + for (int i = 0; i < n; i++) + { + mys.glyphs[i].c = s[i].unicode(); + mys.glyphs[i].glyph_id = 0; + } + + if(OTF_drive_cmap (my, &mys))OTF_perror("drive_cmap ") ; + + for (int i = 0; i < mys.used; i++) + { + std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode( my, mys.glyphs[i].glyph_id) << " : " << dec; + } + cout << "\n"; + + QString fe; + for (QStringList::iterator ife = curFeatures.begin (); + ife != curFeatures.end (); ife++) + { + fe += *ife; + fe += ','; + } + //*(fe.end()) = NULL ; + + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + char *argfe = (char *) fe.ascii(); + + if (GDEF) + {if(OTF_drive_gdef(my, &mys) != 0 )OTF_perror("drive_GDEF ");} + + if (curTable == "GPOS") + { + if(OTF_drive_gpos (my, &mys, argsc, argla, argfe))OTF_perror("drive_GPOS"); + OTF_perror("force(drive_GPOS)"); + for( int n = 0; n < mys.used ; n++) + get_position(n); + } + + if (curTable == "GSUB") + { + if (!subAlt) + { + if(OTF_drive_gsub (my, &mys, argsc, argla, argfe))OTF_perror("drive_GSUB"); + } + else + { + if(OTF_drive_gsub_alternate (my, &mys, argsc, argla, argfe))OTF_perror("drive_GSUB_alt"); + + } + } + + + for (int i = 0; i < mys.used; i++) + { + std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode (my , mys.glyphs[i].glyph_id ) << " : " << dec ; + std::cout << '['<<(char)OTF_get_unicode (my , mys.glyphs[i].glyph_id )<<']' ; + } + cout << "\n"; + + + + return mys.used; +} + +int + myotf::procstring (QString s,QString script, QString lang, QStringList gsub, QStringList gpos) +{ + int n = s.length(); + if (glyphAlloc) + free (mys.glyphs); + mys.size = n; + mys.used = n; + mys.glyphs = (OTF_Glyph *) calloc (n , sizeof (OTF_Glyph)); + glyphAlloc = true; + OTF_error = 0; + for (int i = 0; i < n; i++) + { + mys.glyphs[i].c = s[i].unicode(); + mys.glyphs[i].glyph_id = 0; + } + + if(OTF_drive_cmap (my, &mys))OTF_perror("drive_cmap ") ; + +// for (int i = 0; i < mys.used; i++) +// { +// std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode( my, mys.glyphs[i].glyph_id) << " : " << dec; +// } +// cout << "\n"; + + QString gsubfe; + for (QStringList::iterator ife = gsub.begin (); + ife != gsub.end (); ife++) + { + gsubfe += *ife; + gsubfe += ','; + } + QString gposfe; + for (QStringList::iterator ife = gpos.begin (); + ife != gpos.end (); ife++) + { + gposfe += *ife; + gposfe += ','; + } + //*(fe.end()) = NULL ; + + char *argsc = (char *) script.ascii(); + char *argla = (char *) lang.ascii(); + char *arggsubfe = (char *) gsubfe.ascii(); + char *arggposfe = (char *) gposfe.ascii(); + + if (GDEF) + { + if(OTF_drive_gdef(my, &mys) != 0 )OTF_perror("drive_GDEF "); + } + if (GSUB) + { + if(OTF_drive_gsub(my, &mys, argsc, argla, arggsubfe))OTF_perror("drive_GSUB"); + } + if (GPOS) + { + if(OTF_drive_gpos(my, &mys, argsc, argla, arggposfe))OTF_perror("drive_GPOS"); + } + +// for (int i = 0; i < mys.used; i++) +// { +// std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode (my , mys.glyphs[i].glyph_id ) << " : " << dec ; +// std::cout << '['<<(char)OTF_get_unicode (my , mys.glyphs[i].glyph_id )<<']' ; +// } +// cout << "\n"; +// + + + return mys.used; +} + +int +myotf::procstring() +{ + QString fe; + for (QStringList::iterator ife = curFeatures.begin (); + ife != curFeatures.end (); ife++) + { + fe += *ife; + fe += ','; + } + //*(fe.end()) = NULL ; + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + char *argfe = (char *) fe.ascii(); + + if (curTable == "GPOS") + { + OTF_drive_gpos (my, &mys, argsc, argla, argfe); + for( int n = 0; n < mys.used ; n++) + get_position(n); + } + + if (curTable == "GSUB") + if (!subAlt) + { + OTF_drive_gsub (my, &mys, argsc, argla, argfe); + } + else + { + OTF_drive_gsub_alternate (my, &mys, argsc, argla, argfe); + + } + for (int i = 0; i < mys.used; i++) + { + std::cout << mys.glyphs[i].glyph_id << " : "; + } + cout << "\n"; + + + + return mys.used; +} + + + + + +QStringList myotf::get_tables () +{ + QStringList ret; + + if (GDEF) + ret.insert (ret.end (), "GDEF"); + if (GPOS) + ret.insert (ret.end (), "GPOS"); + if (GSUB) + ret.insert (ret.end (), "GSUB"); + + return ret; +} + +void +myotf::set_table (QString s) +{ + curTable = s; +} + +QStringList myotf::get_scripts () +{ + QStringList ret; + char + aa[5]; + if (curTable == "GSUB") + { + int + ns = my->gsub->ScriptList.ScriptCount; + char * + a = aa; + std:: + cout << "Il y a " << ns << " systèmes d'écriture dans cette fonte.\n"; + for (int i = 0; i < ns; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[i].ScriptTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GPOS") + { + int + ns = my->gpos->ScriptList.ScriptCount; + char * + a = aa; + std:: + cout << "Il y a " << ns << " systèmes d'écriture dans cette fonte.\n"; + for (int i = 0; i < ns; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[i].ScriptTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + return ret; + +} + +void +myotf::set_script (QString s) +{ + char a[5]; + if (curTable == "GPOS") + { + for (int i = 0; i < my->gpos->ScriptList.ScriptCount; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[i].ScriptTag, a); + if (a == s) + curScript = i; + } + } + if (curTable == "GSUB") + { + for (int i = 0; i < my->gsub->ScriptList.ScriptCount; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[i].ScriptTag, a); + if (a == s) + curScript = i; + } + } + curScriptName = s; +} + + +QStringList myotf::get_langs () +{ + QStringList ret; + char + a[5]; + if (curTable == "GPOS") + { + int + nl = my->gpos->ScriptList.Script[curScript].LangSysCount; + cout << "Il y a là " << nl << " langues" << "\n"; + for (int i = 0; i < nl; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GSUB") + { + int + nl = my->gsub->ScriptList.Script[curScript].LangSysCount; + cout << "Il y a là " << nl << " langues" << "\n"; + for (int i = 0; i < nl; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + + return ret; +} + +void +myotf::set_lang (QString s) +{ + if (s == "default") + { + curLangName = "dflt"; + curLang = -1; + return; + } + + char a[5]; + if (curTable == "GPOS") + { + for (int i = 0; i < my->gpos->ScriptList.Script[curScript].LangSysCount; + i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + if (a == s) + curLang = i; + } + } + if (curTable == "GSUB") + { + for (int i = 0; i < my->gsub->ScriptList.Script[curScript].LangSysCount; + i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + if (a == s) + curLang = i; + } + } + curLangName = s; +} + + +QStringList myotf::get_features () +{ + QStringList ret; + char + a[10]; + int + nf, + findex, + i; + OTF_Tag + ftag; + if (curTable == "GPOS") + { + if (curLang >= 0) + nf = + my->gpos->ScriptList.Script[curScript].LangSys[curLang]. + FeatureCount; + else + nf = + my->gpos->ScriptList.Script[curScript].DefaultLangSys.FeatureCount; + cout << "Il y a là " << nf << " fonctionnalités " << "\n"; + for (i = 0; i < nf; i++) + { + if (curLang >= 0) + { + findex = + my->gpos->ScriptList.Script[curScript].LangSys[curLang]. + FeatureIndex[i]; + ftag = my->gpos->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + else + { + findex = + my->gpos->ScriptList.Script[curScript].DefaultLangSys. + FeatureIndex[i]; + ftag = my->gpos->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GSUB") + { + if (curLang >= 0) + nf = + my->gsub->ScriptList.Script[curScript].LangSys[curLang]. + FeatureCount; + else + nf = + my->gsub->ScriptList.Script[curScript].DefaultLangSys.FeatureCount; + + cout << "Il y a là " << nf << " fonctionnalités " << "\n"; + + for (i = 0; i < nf; i++) + { + + if (curLang >= 0) + { + findex = + my->gsub->ScriptList.Script[curScript].LangSys[curLang]. + FeatureIndex[i]; + ftag = my->gsub->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + else + { + findex = + my->gsub->ScriptList.Script[curScript].DefaultLangSys. + FeatureIndex[i]; + ftag = my->gsub->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + return ret; +} + +void +myotf::set_features (QStringList ls) +{ + curFeatures = ls; +} + + +int +myotf::get_position_type (int ind) +{ + return (mys.glyphs[ind].positioning_type); +} + +posglyph +myotf::get_position(int g) +{ + posglyph ret; + int gt = get_position_type(g); + OTF_Glyph og = mys.glyphs[g] ; + if (gt == 1) + { + for( int i= 0x00001 ; i < 0x0081 ; i*=2) + { + if(og.f.f1.format & i ) + { + switch (i) + { + case 0x0001 : ret.Xposition = og.f.f1.value->XPlacement ; + break; + case 0x0002 : ret.Yposition = og.f.f1.value->YPlacement ; + break; + case 0x0004 : ret.Xadvance = og.f.f1.value->XAdvance ; + break; + case 0x0008 : ret.Yadvance = og.f.f1.value->YAdvance ; + break; + default : qDebug( "Don't know how to handle OTF_DeviceTable!"); + break; + } + } + } + } + if (gt == 2) + { + for( int i= 0x0001 ; i < 0x0081 ; i*=2) + { + if(og.f.f2.format & i) + { + switch (i) + { + case 0x0001 : ret.Xposition = og.f.f1.value->XPlacement ; + break; + case 0x0002 : ret.Yposition = og.f.f1.value->YPlacement ; + break; + case 0x0004 : ret.Xadvance = og.f.f1.value->XAdvance ; + break; + case 0x0008 : ret.Yadvance = og.f.f1.value->YAdvance ; + break; + default : qDebug( "Don't know how to handle OTF_DeviceTable!"); + break; + } + } + } + } + return ret; +} + + + + + +// int +// main (int ac, char **av) +// { +// myotf lafonte (av[1]); +// QStringList feat; +// lafonte.set_table (av[3]); +// lafonte.set_script (av[4]); +// lafonte.set_lang (av[5]); +// +// for(int c = 6; c < ac ; c++) +// { +// cout << av[c] << "\n"; +// feat.insert(feat.end(), av[c]); +// } +// // feat.insert(feat.end(), "cpsp"); +// lafonte.set_features (feat); +// // int use; +// lafonte.procstring (av[2]); +// return 0; +// } Index: scribus/fonts/myotf.h =================================================================== RCS file: scribus/fonts/myotf.h diff -N scribus/fonts/myotf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.h 20 Mar 2007 09:07:00 -0000 @@ -0,0 +1,94 @@ +// myotf.h + +#ifndef WRAPLIBOTF +#define WRAPLIBOTF + + +extern "C" +{ +#include <otf.h> +#include <stdlib.h> +} + +#include <iostream> +#include <iomanip> + +#include <qstring.h> +#include <qstringlist.h> + +using namespace std; + +struct posglyph +{ + double Xposition; + double Yposition; + double Xadvance; + double Yadvance; + double xadvance(){return Xadvance;} + double yadvance(){return Yadvance;} + double xposition(){return Xposition;} + double yposition(){return Yposition;} +}; + +class myotf +{ + QString nom; + + OTF *my; + OTF_GlyphString mys; + + + + bool subAlt; + bool glyphAlloc; + + int head, name, cmap, GDEF, GSUB, GPOS; + +public: + OTF_GlyphString * otfString() {return &mys;} + int unicode(int gid){ return OTF_get_unicode(my, gid);} + QString curTable; + int curScript, curLang; + QString curScriptName, curLangName; + QStringList curFeatures; + myotf (QString n); + ~myotf (); +/* + * These members functions apply features currently set + */ + int procstring (QString ); + int procstring (); + int procstring (QString s, QString script, QString lang, QStringList gsub, QStringList gpos); +/* + * These functions give access to informations contained in the fontfile + */ + QStringList get_tables (); + QStringList get_scripts (); + QStringList get_langs (); + QStringList get_features (); +/* + * These allow to set up the features ( Tab -> Scr -> Lan -> Fea ) + */ + void set_table (QString); + void set_script (QString); + void set_lang (QString); + void set_features (QStringList); + void set_subalt (bool); +/* + * I can't remember what this so important method is expected to achieve ! + */ + int get_position_type (int); + /* + * for the moment, it just does nothing. Because I have no idea + * of which sruct can be the target of this function.Nevertheless + * I'm clearly aware that's the key function, it's the reason why + * i put this apart from procstring(). + * The argument is the number of the glyph + */ + + posglyph get_position(int); + int get_glyph_used(); + +}; + +#endif Index: scribus/fonts/scface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/scface.h,v retrieving revision 1.1.2.10 diff -u -8 -p -r1.1.2.10 scface.h --- scribus/fonts/scface.h 26 Nov 2006 13:15:19 -0000 1.1.2.10 +++ scribus/fonts/scface.h 20 Mar 2007 09:07:01 -0000 @@ -16,16 +16,19 @@ virtual: dispatch to constituents, #include <qstring.h> //#include <qvector.h> #include <qmap.h> //#include <qarray.h> #include <utility> #include "fpointarray.h" +//TEST libotf + +#include "myotf.h" struct GlyphMetrics { double width; double ascent; double descent; }; @@ -166,16 +169,19 @@ public: 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<uint, std::pair<QChar, QString> >& gList) const; + + virtual QString otfied(QString s) const {return s;} + // 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; }; @@ -351,16 +357,19 @@ public: 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; } + //TEST libotf + QString otfied (QString s) const { return m->otfied(s); } + private: friend class SCFonts; ScFace(ScFaceData* md); ScFaceData* m; QString replacedName; QString replacedInDoc; |
2007-03-21 14:42
|
myotf-patch-4.diff (42,558 bytes)
Index: scribus/pageitem.cpp =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.cpp,v retrieving revision 1.121.2.418 diff -u -8 -p -r1.121.2.418 pageitem.cpp --- scribus/pageitem.cpp 12 Mar 2007 15:57:39 -0000 1.121.2.418 +++ scribus/pageitem.cpp 21 Mar 2007 14:29:18 -0000 @@ -1747,16 +1747,178 @@ double PageItem::layoutGlyphs(const Char layout.yadvance = layout.more->yadvance; } else { layout.shrink(); } return retval; } +// the same, but character to render is retrieved from contextStringPointer +double PageItem::layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout) +{ + QString chars; + bool otf = style.font().isOTF(); + if(contextString[0] == 0) // We have a special char that can't be processed by libotf + { + chars = contextString[1].unicode(); + } + else if(otf) + { + + if (contextStringPointer == 0) + { + contextGlyphsString = style.font().otfied(contextString); + //Now, we have 4 possibilities : + // 1/ one glyph for one character ; + // 2/ many glyphs for one character ; + // 3/ one glyph for many characters ; + // 4/ nothing if character was rendered in a previous case 3 call. + // Too much complicated for me, I take the shorter way. + int ls = contextString.length(); + int lg = contextGlyphsString.length(); + contexLengthChange = lg - ls; + } + if (contexLengthChange < 0) // source string is longer then the rendered string + { + contexLengthChange += 1; // waiting + contextStringPointer = -1; + layout.glyph = ScFace::CONTROL_GLYPHS + SpecialChars::ZWSPACE.unicode(); + return 0.0; + } + else if (contexLengthChange > 0) // in that case we just trust the GLyphLayout grow() + { + chars = contextGlyphsString.mid(contextStringPointer,contexLengthChange + len); + contexLengthChange = 0; + } + else if(contexLengthChange == 0) + { + if(contextStringPointer == -1) contextStringPointer = 0; + chars = contextGlyphsString.mid(contextStringPointer,len); + } + //contextStringPointer += 1; + } + else + { + chars = contextString.mid(contextStringPointer,len); + } + qDebug(QString("char is [%1], contextGlyphsString is [%2], contextStringPointer[%3], len [%4]").arg(chars[0].unicode()).arg(contextGlyphsString).arg(contextStringPointer).arg(len)); + double retval = 0.0; + double asce = style.font().ascent(style.fontSize() / 10.0); + int chst = style.effects() & 1919; + if (chars[0] == SpecialChars::ZWSPACE || + chars[0] == SpecialChars::ZWNBSPACE || + chars[0] == SpecialChars::NBSPACE || + chars[0] == SpecialChars::NBHYPHEN || + chars[0] == SpecialChars::SHYPHEN || + chars[0] == SpecialChars::PARSEP || + chars[0] == SpecialChars::COLBREAK || + chars[0] == SpecialChars::LINEBREAK || + chars[0] == SpecialChars::FRAMEBREAK || + chars[0] == SpecialChars::TAB) + { + layout.glyph = ScFace::CONTROL_GLYPHS + chars[0].unicode(); + } + else + { + layout.glyph = style.font().char2CMap(chars[0].unicode()); //otf comment : here we assume that the proper pair is in the c_Map cache + } + + double tracking = 0.0; + if ( (style.effects() & ScStyle_StartOfLine) == 0) + tracking = style.fontSize() * style.tracking() / 10000.0; + + layout.xoffset = tracking; + layout.yoffset = 0; + if (chst != ScStyle_Default) + { + if (chst & ScStyle_Superscript) + { + retval -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.yoffset -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSuperScript / 100.0, 10.0 / style.fontSize()); + } + else if (chst & ScStyle_Subscript) + { + retval += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.yoffset += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSubScript / 100.0, 10.0 / style.fontSize()); + } + else { + layout.scaleV = layout.scaleH = 1.0; + } + layout.scaleH *= style.scaleH() / 1000.0; + layout.scaleV *= style.scaleV() / 1000.0; + if (chst & ScStyle_AllCaps) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + } + if (chst & ScStyle_SmallCaps) + { + + double smallcapsScale = m_Doc->typographicSettings.valueSmallCaps / 100.0; + QChar uc = chars[0].upper(); + if (uc != chars[0]) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + layout.scaleV *= smallcapsScale; + layout.scaleH *= smallcapsScale; + } + } + } + else { + layout.scaleH = style.scaleH() / 1000.0; + layout.scaleV = style.scaleV() / 1000.0; + } + + if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) { + uint replGlyph = style.font().char2CMap(QChar(' ')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode())) { + uint replGlyph = style.font().char2CMap(QChar('-')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph >= ScFace::CONTROL_GLYPHS) { + layout.xadvance = 0; + layout.yadvance = 0; + } + else { + layout.xadvance = style.font().glyphWidth(layout.glyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(layout.glyph, style.fontSize() / 10).ascent * layout.scaleV; + } + if(otf)//Don't wait for ::layout to adjust with pair kerning + { + posglyph pg = style.font().otf()->get_position(contextStringPointer); + qDebug(QString("Adjust[%1] pg.xadv=%2 , pg.yadv=%3").arg(layout.glyph).arg(pg.xadvance()).arg(pg.yadvance())); + layout.xadvance += pg.xadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleH; + layout.yadvance += pg.yadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleV; + + } + if (layout.xadvance > 0) + layout.xadvance += tracking; + + if (chars.length() > 1) { + layout.grow(); + contextStringPointer += 1; + layoutGlyphs(style, chars.length()-1, *layout.more); + layout.xadvance += style.font().glyphKerning(layout.glyph, layout.more->glyph, style.fontSize() / 10) * layout.scaleH; + if (layout.more->yadvance > layout.yadvance) + layout.yadvance = layout.more->yadvance; + } + else { + contextStringPointer += 1; + layout.shrink(); + } + + return retval; +} + void PageItem::drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs) { uint glyph = glyphs.glyph; if ((m_Doc->guidesSettings.showControls) && (glyph == style.font().char2CMap(QChar(' ')) || glyph >= ScFace::CONTROL_GLYPHS)) { bool stroke = false; if (glyph >= ScFace::CONTROL_GLYPHS) Index: scribus/pageitem.h =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.h,v retrieving revision 1.26.2.181 diff -u -8 -p -r1.26.2.181 pageitem.h --- scribus/pageitem.h 6 Mar 2007 21:32:15 -0000 1.26.2.181 +++ scribus/pageitem.h 21 Mar 2007 14:29:20 -0000 @@ -289,16 +289,17 @@ public: /// returns the style at the current charpos const ParagraphStyle& currentStyle() const; /// returns the style at the current charpos ParagraphStyle& changeCurrentStyle(); /// returns the style at the current charpos const CharStyle& currentCharStyle() const; // deprecated: double layoutGlyphs(const CharStyle& style, const QString chars, GlyphLayout& layout); + double layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout); void SetFarbe(QColor *tmp, QString farbe, int shad); void drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs ); void DrawPolyL(QPainter *p, QPointArray pts); QString ExpandToken(uint base); bool AutoName; double gXpos; double gYpos; @@ -1208,16 +1209,22 @@ public: /** Darstellungsart Bild/Titel */ bool PicArt; /** Line width */ double m_lineWidth; double Oldm_lineWidth; + /** Context String */ + QString contextString; + QString contextGlyphsString; + int contextStringPointer; + int contexLengthChange; + signals: //Frame signals void myself(PageItem *); void frameType(int); // not related to Frametype but to m_itemIype :-/ void position(double, double); //X,Y void widthAndHeight(double, double); //W,H void rotation(double); //Degrees rotation void colors(QString, QString, int, int); //lineColor, fillColor, lineShade, fillShade Index: scribus/pageitem_textframe.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/pageitem_textframe.cpp,v retrieving revision 1.1.2.152 diff -u -8 -p -r1.1.2.152 pageitem_textframe.cpp --- scribus/pageitem_textframe.cpp 11 Mar 2007 15:12:07 -0000 1.1.2.152 +++ scribus/pageitem_textframe.cpp 21 Mar 2007 14:29:26 -0000 @@ -537,17 +537,47 @@ static double opticalRightMargin(const S rightCorr = itemText.charStyle(b).font().charWidth(chr, chs / 10.0); rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); } return rightCorr; } return 0.0; } +// TEST +static void prepareText(StoryText& itemText, int begin, int end) +{ + /* here, it could be possible to send text to a substitution engine */ + /* example (pseudopseudocode): + QString final = itemText.charStyle(i)->font->subtitute(itemText.text(begin , end - begin), itemText.charStyle(i)->font->sub_features_set()); + + for(int i = begin, i <= end ; ++i) + { + if(final.at(i)) itemText.item(i)->ch = final.at(i); + else itemText.remove(i); + } + + + */ + +// if(itemText.charStyle(begin).font().isOTF()) +// { +// QString os = itemText.text(begin, end - begin ); +// QString ns = itemText.charStyle(begin).font().otfSub(os); +// if(os != ns) +// { +// CharStyle back = itemText.charStyle(begin); +// itemText.removeChars(begin , end); +// itemText.insertChars( begin , ns ); +// itemText.setCharStyle(begin , ns.length() , back ); +// } +// } +} +// ENDTEST void PageItem_TextFrame::layout() { if (BackBox != NULL && BackBox->invalid) { // qDebug("textframe: len=%d, going back", itemText.length()); invalid = false; PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); if (!prevInChain) @@ -671,18 +701,93 @@ void PageItem_TextFrame::layout() { desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; } current.startLine(firstInFrame()); outs = false; OFs = 0; MaxChars = 0; + //TEST +// CharStyle control_charstyle; +// int begin_prepare; +// int end_prepare = begin_prepare = firstInFrame(); +// for (int a = firstInFrame(); a < itemText.length(); ++a) +// { +// if(a == begin_prepare) +// { +// control_charstyle = itemText.charStyle(a); +// continue; +// } +// if(control_charstyle != itemText.charStyle(a)) +// { +// end_prepare = a-1; +// prepareText(itemText, begin_prepare, end_prepare); +// begin_prepare = end_prepare = a; +// control_charstyle = itemText.charStyle(a); +// continue; +// } +// if(a == itemText.length() -1) +// { +// prepareText(itemText, begin_prepare, a + 1); +// break; +// } +// ++end_prepare; +// } + // ENDTEST + // BIGLOOP + int contextrest = 0; + int sccontrol; for (int a = firstInFrame(); a < itemText.length(); ++a) { + // here we set the context string + if(contextrest == 0) + { + contextString = ""; + sccontrol = 0; + for(int ctsg = a; ctsg < itemText.length(); ++ctsg) + { + + QString contmp = ExpandToken(ctsg); + if(contmp[0] == SpecialChars::ZWSPACE || + contmp[0] == SpecialChars::ZWNBSPACE || + contmp[0] == SpecialChars::NBSPACE || + contmp[0] == SpecialChars::NBHYPHEN || + contmp[0] == SpecialChars::SHYPHEN || + contmp[0] == SpecialChars::PARSEP || + contmp[0] == SpecialChars::COLBREAK || + contmp[0] == SpecialChars::LINEBREAK || + contmp[0] == SpecialChars::FRAMEBREAK || + contmp[0] == SpecialChars::TAB || + contmp[0] == SpecialChars::BLANK) + { + if(sccontrol > 0) + { + break; + } + else + { + contextString += QChar(0) ; + contextString += contmp[0].unicode(); + break; + } + } + else + { + sccontrol += 1; + contextString += contmp; + } + } + contextrest = (sccontrol == 0 ? 1 : contextString.length());// we send special char one by one + contextStringPointer = 0; + qDebug(QString("contextrest = %1 and context string is \"%2\"").arg(contextrest).arg(contextString)); + } + --contextrest; + + hl = itemText.item(a); if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) style = itemText.paragraphStyle(a); if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); // qDebug(QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); const CharStyle& charStyle = itemText.charStyle(a); @@ -857,17 +962,19 @@ void PageItem_TextFrame::layout() kernVal = 0; } else { kernVal = 0; // chs * charStyle.tracking() / 10000.0; itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); } hl->glyph.yadvance = 0; - oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); + //qDebug(QString("sending [%1] to layoutGlyphs()").arg(chstr)); + oldCurY = layoutGlyphs(*hl, chstr.length(), hl->glyph); + //oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); // find out width of char if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); else { /* if (a+1 < itemText.length()) { chstr3 = itemText.text(a+1); @@ -875,20 +982,23 @@ void PageItem_TextFrame::layout() wide = charStyle.font().charWidth(chstr2[0], chs / 10.0, chstr3[0]); } else wide = charStyle.font().charWidth(chstr2[0], chs / 10.0); */ wide = hl->glyph.wide(); if (a+1 < itemText.length()) { - uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); - double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; - wide += kern; - hl->glyph.xadvance += kern; + if( !charStyle.font().isOTF() ) + { + uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); + double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; + wide += kern; + hl->glyph.xadvance += kern; + } } } if (DropCmode) { // drop caps are wider... if ((hl->ch == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); Index: scribus/fonts/CMakeLists.txt =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/CMakeLists.txt,v retrieving revision 1.1.2.1 diff -u -8 -p -r1.1.2.1 CMakeLists.txt --- scribus/fonts/CMakeLists.txt 23 Jul 2006 12:07:47 -0000 1.1.2.1 +++ scribus/fonts/CMakeLists.txt 21 Mar 2007 14:29:29 -0000 @@ -5,12 +5,24 @@ ${CMAKE_SOURCE_DIR}/scribus SET(SCRIBUS_FONTS_LIB_SOURCES scface.cpp ftface.cpp scface_ps.cpp scface_ttf.cpp scfontmetrics.cpp +myotf.cpp ) +SET(OTF_DIR ${CMAKE_MODULE_PATH}) +FIND_PACKAGE(OTF REQUIRED) +IF(OTF_FOUND) + SET(HAVE_OTF 1) + MESSAGE("LIBOTF Library found") +ELSE(OTF_FOUND) + MESSAGE(FATAL_ERROR "Could not find the libOtf Library") +ENDIF(OTF_FOUND) + +LINK_LIBRARIES ( ${OTF_LIBRARIES}) + SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.9 diff -u -8 -p -r1.1.2.9 ftface.cpp --- scribus/fonts/ftface.cpp 11 Jan 2007 15:29:46 -0000 1.1.2.9 +++ scribus/fonts/ftface.cpp 21 Mar 2007 14:29:30 -0000 @@ -2,16 +2,19 @@ #include "fonts/ftface.h" #include FT_OUTLINE_H #include FT_GLYPH_H #include <qobject.h> #include <qfile.h> +#include <qmessagebox.h> +#include <qinputdialog.h> + #include "scfonts.h" #include "fonts/scfontmetrics.h" // static: FT_Library FtFace::library = NULL; /***** ScFace lifecycle: unchecked -> loaded -> glyphs checked @@ -136,36 +139,105 @@ void FtFace::load() const ++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; } + //TEST libotf + if(typeCode == ScFace::OTF) + { + _otf = new myotf(QFile::encodeName(fontFile)); + bool ok; + QMessageBox::information( 0, "Scribus", + QString("You choose to use an OpenType Font file \"%1\".\n You have to set parameters for this font.").arg(scName) ); + _otf->set_table("GSUB"); + QStringList choice = _otf->get_scripts(); + if(choice.count() > 1) + { + otfScript = QInputDialog::getItem("Scribus :: otf", "Select the script ", choice, 0, FALSE, &ok ); + _otf->set_script(otfScript); + } + else + { + otfScript = choice[0]; + _otf->set_script(otfScript); + } + choice = _otf->get_langs(); + choice.append("dflt"); + if(choice.count() > 1) + { + otfLang = QInputDialog::getItem("Scribus :: otf", QString("Select the language for script %1").arg(otfScript), choice, 0, FALSE, &ok ); + _otf->set_lang(otfLang); + } + else + { + otfLang = choice[0]; + _otf->set_lang(otfLang); + } + choice =_otf->get_features(); + QString ft; + ok = TRUE; +// while(QMessageBox::question(0,"Scribus","Want to choose features for GSUB ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + while(ok && !choice.isEmpty()) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select GSUB feature for lang %1").arg(otfLang), choice, 0, FALSE, &ok ); + if(ok) + { + otfSubFeatures.append(ft); + choice.remove(ft); + } + } + _otf->set_table("GPOS"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + choice =_otf->get_features(); + ok = TRUE; +// while(QMessageBox::question(0,"Scribus","Want to choose features for GPOS ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + while(ok && !choice.isEmpty()) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select GPOS feature for lang %1").arg(otfLang), choice, 0, FALSE, &ok ); + if(ok) + { + otfPosFeatures.append(ft); + choice.remove(ft); + } + } + qDebug("otf filled"); + } } void FtFace::unload() const { if (m_face) { FT_Done_Face( m_face ); m_face = NULL; } // clear caches + if(_otf) delete _otf; 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; + if(m_cMap.contains(ch.unicode())) + { + return m_cMap[ch.unicode()]; + } + else + { + FT_Face face = ftFace(); + uint gl = FT_Get_Char_Index(face, ch.unicode()); + m_cMap.insert(ch.unicode(), gl); + return gl; + } } void FtFace::loadGlyph(uint gl) const { if (m_glyphWidth.contains(gl)) return; @@ -307,9 +379,32 @@ void FtFace::RawData(QByteArray & bb) co // 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())); } */ } +QString FtFace::otfied(QString s) const +{ + qDebug("otfied"); + if(status != ScFace::LOADED) + { + qDebug("Face is not loaded"); + } + else if(typeCode == ScFace::OTF) + { + int nbg = _otf->procstring(s,otfScript,otfLang,otfSubFeatures,otfPosFeatures); + QString newstring; + for (int i = 0; i < nbg ; ++i) + { + newstring += QChar(_otf->unicode( _otf->otfString()->glyphs[i].glyph_id )); + m_cMap.insert(_otf->unicode( _otf->otfString()->glyphs[i].glyph_id), _otf->otfString()->glyphs[i].glyph_id); + } + + + qDebug(QString("oldstring is \"%1\" and new string os \"%2\"").arg(s).arg(newstring)); + return newstring; + } + return s; +} Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -8 -p -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 21 Mar 2007 14:29:30 -0000 @@ -96,22 +96,31 @@ protected: mutable QString Descender; mutable QString ItalicAngle; mutable QString StdVW; QString FontEnc; mutable QString FontBBox; mutable int m_encoding; - mutable double m_uniEM; +// mutable double m_uniEM; mutable double m_ascent; mutable double m_descent; mutable double m_height; mutable double m_xHeight; mutable double m_capHeight; mutable double m_maxAdvanceWidth; mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + //TEST libotf + public: + mutable QStringList otfSubFeatures; + mutable QStringList otfPosFeatures; + mutable QString otfScript; + mutable QString otfLang; + QString otfied(QString s) const ; + + }; #endif Index: scribus/fonts/myotf.cpp =================================================================== RCS file: scribus/fonts/myotf.cpp diff -N scribus/fonts/myotf.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.cpp 21 Mar 2007 14:29:31 -0000 @@ -0,0 +1,633 @@ +/* un test de libotf mer18jan */ + + +#include "myotf.h" + + + +void +myotf::set_subalt (bool b) +{ + subAlt = b; +} + +int +myotf::get_glyph_used() +{ + return mys.used; +} + +myotf::myotf (QString n) +{ + nom = n; + my = OTF_open ((char*)nom.ascii()); + subAlt = false; + glyphAlloc = false; + if (OTF_get_table (my, "head") == 0) + head = 1; + else + head = 0; + if (OTF_get_table (my, "name") == 0) + name = 1; + else + name = 0; + if (OTF_get_table (my, "cmap") == 0) + cmap = 1; + else + cmap = 0; + if (OTF_get_table (my, "GDEF") == 0) + GDEF = 1; + else + GDEF = 0; + if (OTF_get_table (my, "GSUB") == 0) + GSUB = 1; + else + GSUB = 0; + if (OTF_get_table (my, "GPOS") == 0) + GPOS = 1; + else + GPOS = 0; + // if (GSUB){ OTF_get_scripts (my, 1); OTF_get_features (my, 1);} + // if (GPOS){ OTF_get_scripts (my, 0); OTF_get_features (my, 0);} + +/* + std::cout << "head : " << head << "\n"; + std::cout << "name : " << name << "\n"; + std::cout << "cmap : " << cmap << "\n"; + std::cout << "GDEF : " << GDEF << "\n"; + std::cout << "GSUB : " << GSUB << "\n"; + std::cout << "GPOS : " << GPOS << "\n"; +*/ +} + +myotf::~myotf () +{ + if (glyphAlloc) + free (mys.glyphs); + OTF_close (my); +} + +int +myotf::procstring (QString s) +{ + int n = s.length(); + if (glyphAlloc) + free (mys.glyphs); + mys.size = n; + mys.used = n; + mys.glyphs = (OTF_Glyph *) calloc (n , sizeof (OTF_Glyph)); + glyphAlloc = true; + OTF_error = 0; + for (int i = 0; i < n; i++) + { + mys.glyphs[i].c = s[i].unicode(); + mys.glyphs[i].glyph_id = 0; + } + + if(OTF_drive_cmap (my, &mys))OTF_perror("drive_cmap ") ; + + for (int i = 0; i < mys.used; i++) + { + std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode( my, mys.glyphs[i].glyph_id) << " : " << dec; + } + cout << "\n"; + + QString fe; + for (QStringList::iterator ife = curFeatures.begin (); + ife != curFeatures.end (); ife++) + { + fe += *ife; + fe += ','; + } + //*(fe.end()) = NULL ; + + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + char *argfe = (char *) fe.ascii(); + + if (GDEF) + {if(OTF_drive_gdef(my, &mys) != 0 )OTF_perror("drive_GDEF ");} + + if (curTable == "GPOS") + { + if(OTF_drive_gpos (my, &mys, argsc, argla, argfe))OTF_perror("drive_GPOS"); + OTF_perror("force(drive_GPOS)"); + for( int n = 0; n < mys.used ; n++) + get_position(n); + } + + if (curTable == "GSUB") + { + if (!subAlt) + { + if(OTF_drive_gsub (my, &mys, argsc, argla, argfe))OTF_perror("drive_GSUB"); + } + else + { + if(OTF_drive_gsub_alternate (my, &mys, argsc, argla, argfe))OTF_perror("drive_GSUB_alt"); + + } + } + + + for (int i = 0; i < mys.used; i++) + { + std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode (my , mys.glyphs[i].glyph_id ) << " : " << dec ; + std::cout << '['<<(char)OTF_get_unicode (my , mys.glyphs[i].glyph_id )<<']' ; + } + cout << "\n"; + + + + return mys.used; +} + +/// the actual function +int myotf::procstring (QString s,QString script, QString lang, QStringList gsub, QStringList gpos) +{ + qDebug("procstring"); + int n = s.length(); + if (glyphAlloc) + free (mys.glyphs); + mys.size = n; + mys.used = n; + mys.glyphs = (OTF_Glyph *) calloc (n , sizeof (OTF_Glyph)); + glyphAlloc = true; + OTF_error = 0; + for (int i = 0; i < n; i++) + { + mys.glyphs[i].c = s[i].unicode(); + mys.glyphs[i].glyph_id = 0; + } + + if(OTF_drive_cmap (my, &mys))OTF_perror("drive_cmap ") ; + +// for (int i = 0; i < mys.used; i++) +// { +// std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode( my, mys.glyphs[i].glyph_id) << " : " << dec; +// } +// cout << "\n"; + set_table("GSUB"); + set_script(script); + set_lang(lang); + + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + + qDebug(QString("Script [%1] , Lang [%2]").arg(curScriptName).arg(curLangName)); + + QString gsubfe; + for (QStringList::iterator ife = gsub.begin (); + ife != gsub.end (); ife++) + { + OTF_Tag chft = OTF_tag((char *) (*ife).ascii()); + + if(OTF_check_features(my, 1, + OTF_tag(argsc),OTF_tag(argla), + &chft, 1)) + { + qDebug(QString("feature [%1]").arg(*ife)); + gsubfe += *ife; + gsubfe += ','; + } + } + QString gposfe; + for (QStringList::iterator ife = gpos.begin (); + ife != gpos.end (); ife++) + { + OTF_Tag chft = OTF_tag((char *) (*ife).ascii()); + if(OTF_check_features(my, 0, + OTF_tag(argsc),OTF_tag(argla), + &chft, 1)) + { + qDebug(QString("feature [%1]").arg(*ife)); + gposfe += *ife; + gposfe += ','; + } + } + //*(fe.end()) = NULL ; + + + char *arggsubfe = (char *) gsubfe.ascii(); + char *arggposfe = (char *) gposfe.ascii(); + + + if (GDEF) + { + qDebug("GDEF"); + if(OTF_drive_gdef(my, &mys) != 0 )OTF_perror("drive_GDEF "); + } + if (GSUB && !gsub.isEmpty()) + { + qDebug("GSUB"); + if(OTF_drive_gsub(my, &mys, argsc, argla, arggsubfe))OTF_perror("drive_GSUB"); + } + if (GPOS && !gpos.isEmpty()) + { + qDebug("GPOS"); + if(OTF_drive_gpos(my, &mys, argsc, argla, arggposfe))OTF_perror("drive_GPOS"); + } + +// for (int i = 0; i < mys.used; i++) +// { +// std::cout << hex << setw(4) << setfill('0') << OTF_get_unicode (my , mys.glyphs[i].glyph_id ) << " : " << dec ; +// std::cout << '['<<(char)OTF_get_unicode (my , mys.glyphs[i].glyph_id )<<']' ; +// } +// cout << "\n"; +// + + + return mys.used; +} + +int +myotf::procstring() +{ + QString fe; + for (QStringList::iterator ife = curFeatures.begin (); + ife != curFeatures.end (); ife++) + { + fe += *ife; + fe += ','; + } + //*(fe.end()) = NULL ; + char *argsc = (char *) curScriptName.ascii(); + char *argla = (char *) curLangName.ascii(); + char *argfe = (char *) fe.ascii(); + + if (curTable == "GPOS") + { + OTF_drive_gpos (my, &mys, argsc, argla, argfe); + for( int n = 0; n < mys.used ; n++) + get_position(n); + } + + if (curTable == "GSUB") + if (!subAlt) + { + OTF_drive_gsub (my, &mys, argsc, argla, argfe); + } + else + { + OTF_drive_gsub_alternate (my, &mys, argsc, argla, argfe); + + } + for (int i = 0; i < mys.used; i++) + { + std::cout << mys.glyphs[i].glyph_id << " : "; + } + cout << "\n"; + + + + return mys.used; +} + + + + + +QStringList myotf::get_tables () +{ + QStringList ret; + + if (GDEF) + ret.insert (ret.end (), "GDEF"); + if (GPOS) + ret.insert (ret.end (), "GPOS"); + if (GSUB) + ret.insert (ret.end (), "GSUB"); + + return ret; +} + +void +myotf::set_table (QString s) +{ + curTable = s; +} + +QStringList myotf::get_scripts () +{ + QStringList ret; + char + aa[5]; + if (curTable == "GSUB") + { + int + ns = my->gsub->ScriptList.ScriptCount; + char * + a = aa; + std:: + cout << "Il y a " << ns << " systèmes d'écriture dans cette fonte.\n"; + for (int i = 0; i < ns; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[i].ScriptTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GPOS") + { + int + ns = my->gpos->ScriptList.ScriptCount; + char * + a = aa; + std:: + cout << "Il y a " << ns << " systèmes d'écriture dans cette fonte.\n"; + for (int i = 0; i < ns; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[i].ScriptTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + return ret; + +} + +void +myotf::set_script (QString s) +{ + char a[5]; + if (curTable == "GPOS") + { + for (int i = 0; i < my->gpos->ScriptList.ScriptCount; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[i].ScriptTag, a); + if (a == s) + curScript = i; + } + } + if (curTable == "GSUB") + { + for (int i = 0; i < my->gsub->ScriptList.ScriptCount; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[i].ScriptTag, a); + if (a == s) + curScript = i; + } + } + curScriptName = s; +} + + +QStringList myotf::get_langs () +{ + QStringList ret; + char + a[5]; + if (curTable == "GPOS") + { + int + nl = my->gpos->ScriptList.Script[curScript].LangSysCount; + cout << "Il y a là " << nl << " langues" << "\n"; + for (int i = 0; i < nl; i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GSUB") + { + int + nl = my->gsub->ScriptList.Script[curScript].LangSysCount; + cout << "Il y a là " << nl << " langues" << "\n"; + for (int i = 0; i < nl; i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + + return ret; +} + +void +myotf::set_lang (QString s) +{ + if (s == "default" || s == "dflt" || s.isEmpty()) + { + curLangName = "dflt"; + curLang = -1; + return; + } + + char a[5]; + if (curTable == "GPOS") + { + for (int i = 0; i < my->gpos->ScriptList.Script[curScript].LangSysCount; + i++) + { + OTF_tag_name (my->gpos->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + if (a == s) + curLang = i; + } + } + if (curTable == "GSUB") + { + for (int i = 0; i < my->gsub->ScriptList.Script[curScript].LangSysCount; + i++) + { + OTF_tag_name (my->gsub->ScriptList.Script[curScript]. + LangSysRecord[i].LangSysTag, a); + if (a == s) + curLang = i; + } + } + curLangName = s; +} + + +QStringList myotf::get_features () +{ + QStringList ret; + char + a[10]; + int + nf, + findex, + i; + OTF_Tag + ftag; + if (curTable == "GPOS") + { + if (curLang >= 0) + nf = + my->gpos->ScriptList.Script[curScript].LangSys[curLang]. + FeatureCount; + else + nf = + my->gpos->ScriptList.Script[curScript].DefaultLangSys.FeatureCount; + cout << "Il y a là " << nf << " fonctionnalités " << "\n"; + for (i = 0; i < nf; i++) + { + if (curLang >= 0) + { + findex = + my->gpos->ScriptList.Script[curScript].LangSys[curLang]. + FeatureIndex[i]; + ftag = my->gpos->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + else + { + findex = + my->gpos->ScriptList.Script[curScript].DefaultLangSys. + FeatureIndex[i]; + ftag = my->gpos->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + if (curTable == "GSUB") + { + if (curLang >= 0) + nf = + my->gsub->ScriptList.Script[curScript].LangSys[curLang]. + FeatureCount; + else + nf = + my->gsub->ScriptList.Script[curScript].DefaultLangSys.FeatureCount; + + cout << "Il y a là " << nf << " fonctionnalités " << "\n"; + + for (i = 0; i < nf; i++) + { + + if (curLang >= 0) + { + findex = + my->gsub->ScriptList.Script[curScript].LangSys[curLang]. + FeatureIndex[i]; + ftag = my->gsub->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + else + { + findex = + my->gsub->ScriptList.Script[curScript].DefaultLangSys. + FeatureIndex[i]; + ftag = my->gsub->FeatureList.Feature[findex].FeatureTag; + OTF_tag_name (ftag, a); + } + std::cout << a; + std::cout << "\n"; + ret.insert (ret.end (), a); + } + } + return ret; +} + +void +myotf::set_features (QStringList ls) +{ + curFeatures = ls; +} + + +int +myotf::get_position_type (int ind) +{ + if(glyphAlloc) + { + qDebug(QString("get_position_type (%1)").arg(ind)); + return (mys.glyphs[ind].positioning_type); + } + else + { + qDebug("! GlyphString is not allocated !"); + } + return 0; +} + +posglyph +myotf::get_position(int g) +{ + posglyph ret; + //qDebug(QString("get_position(%1) from [%2]").arg(g).arg((int) this)); + int gt = get_position_type(g); + OTF_Glyph og = mys.glyphs[g] ; + if (gt == 1) + { + for( int i= 0x00001 ; i < 0x0081 ; i*=2) + { + if(og.f.f1.format & i ) + { + switch (i) + { + case 0x0001 : ret.Xposition = og.f.f1.value->XPlacement ; + break; + case 0x0002 : ret.Yposition = og.f.f1.value->YPlacement ; + break; + case 0x0004 : ret.Xadvance = og.f.f1.value->XAdvance ; + break; + case 0x0008 : ret.Yadvance = og.f.f1.value->YAdvance ; + break; + default : qDebug( "Don't know how to handle OTF_DeviceTable!"); + break; + } + } + } + } + if (gt == 2) + { + for( int i= 0x0001 ; i < 0x0081 ; i*=2) + { + if(og.f.f2.format & i) + { + switch (i) + { + case 0x0001 : ret.Xposition = og.f.f1.value->XPlacement ; + break; + case 0x0002 : ret.Yposition = og.f.f1.value->YPlacement ; + break; + case 0x0004 : ret.Xadvance = og.f.f1.value->XAdvance ; + break; + case 0x0008 : ret.Yadvance = og.f.f1.value->YAdvance ; + break; + default : qDebug( "Don't know how to handle OTF_DeviceTable!"); + break; + } + } + } + } + return ret; +} + + + + + +// int +// main (int ac, char **av) +// { +// myotf lafonte (av[1]); +// QStringList feat; +// lafonte.set_table (av[3]); +// lafonte.set_script (av[4]); +// lafonte.set_lang (av[5]); +// +// for(int c = 6; c < ac ; c++) +// { +// cout << av[c] << "\n"; +// feat.insert(feat.end(), av[c]); +// } +// // feat.insert(feat.end(), "cpsp"); +// lafonte.set_features (feat); +// // int use; +// lafonte.procstring (av[2]); +// return 0; +// } Index: scribus/fonts/myotf.h =================================================================== RCS file: scribus/fonts/myotf.h diff -N scribus/fonts/myotf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.h 21 Mar 2007 14:29:31 -0000 @@ -0,0 +1,94 @@ +// myotf.h + +#ifndef WRAPLIBOTF +#define WRAPLIBOTF + + +extern "C" +{ +#include <otf.h> +#include <stdlib.h> +} + +#include <iostream> +#include <iomanip> + +#include <qstring.h> +#include <qstringlist.h> + +using namespace std; + +struct posglyph +{ + double Xposition; + double Yposition; + double Xadvance; + double Yadvance; + double xadvance(){return Xadvance;} + double yadvance(){return Yadvance;} + double xposition(){return Xposition;} + double yposition(){return Yposition;} +}; + +class myotf +{ + QString nom; + + OTF *my; + OTF_GlyphString mys; + + + + bool subAlt; + bool glyphAlloc; + + int head, name, cmap, GDEF, GSUB, GPOS; + +public: + OTF_GlyphString * otfString() {return &mys;} + int unicode(int gid){ return OTF_get_unicode(my, gid);} + QString curTable; + int curScript, curLang; + QString curScriptName, curLangName; + QStringList curFeatures; + myotf (QString n); + ~myotf (); +/* + * These members functions apply features currently set + */ + int procstring (QString ); + int procstring (); + int procstring (QString s, QString script, QString lang, QStringList gsub, QStringList gpos); +/* + * These functions give access to informations contained in the fontfile + */ + QStringList get_tables (); + QStringList get_scripts (); + QStringList get_langs (); + QStringList get_features (); +/* + * These allow to set up the features ( Tab -> Scr -> Lan -> Fea ) + */ + void set_table (QString); + void set_script (QString); + void set_lang (QString); + void set_features (QStringList); + void set_subalt (bool); +/* + * I can't remember what this so important method is expected to achieve ! + */ + int get_position_type (int); + /* + * for the moment, it just does nothing. Because I have no idea + * of which sruct can be the target of this function.Nevertheless + * I'm clearly aware that's the key function, it's the reason why + * i put this apart from procstring(). + * The argument is the number of the glyph + */ + + posglyph get_position(int); + int get_glyph_used(); + +}; + +#endif Index: scribus/fonts/scface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/scface.h,v retrieving revision 1.1.2.10 diff -u -8 -p -r1.1.2.10 scface.h --- scribus/fonts/scface.h 26 Nov 2006 13:15:19 -0000 1.1.2.10 +++ scribus/fonts/scface.h 21 Mar 2007 14:29:32 -0000 @@ -16,16 +16,19 @@ virtual: dispatch to constituents, #include <qstring.h> //#include <qvector.h> #include <qmap.h> //#include <qarray.h> #include <utility> #include "fpointarray.h" +//TEST libotf + +#include "myotf.h" struct GlyphMetrics { double width; double ascent; double descent; }; @@ -109,16 +112,21 @@ public: bool usable; bool embedPs; bool subset; bool isStroked; bool isFixedPitch; bool hasNames; uint maxGlyph; + mutable double m_uniEM; + protected : + mutable myotf * _otf; + public: + myotf * otf() const { return _otf;} ScFaceData(); virtual ~ScFaceData() { }; protected: friend class ScFace; Status cachedStatus; @@ -145,16 +153,17 @@ public: m_cMap.clear(); status = ScFace::UNKNOWN; } virtual void loadGlyph(uint /*gl*/) const {} // dummy implementations + virtual double uniEM() const {return m_uniEM;} virtual double ascent(double sz) const { return sz; } virtual QString ascentAsString() const { return "0" ; } virtual QString descentAsString() const { return "0"; } virtual QString capHeightAsString() const { return "0"; } virtual QString FontBBoxAsString() const { return "0 0 0 0"; } virtual QString ItalicAngleAsString() const { return "0"; } virtual double descent(double /*sz*/) const { return 0.0; } virtual double xHeight(double sz) const { return sz; } @@ -166,16 +175,19 @@ public: 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<uint, std::pair<QChar, QString> >& gList) const; + + virtual QString otfied(QString s) const {return s;} + // 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; }; @@ -285,16 +297,17 @@ public: /// 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 unitsEM () const {return m->uniEM();} double ascent(double sz=1.0) const { return m->ascent(sz); } QString ascentAsString() const { return m->ascentAsString() ; } QString descentAsString() const { return m->descentAsString() ; } QString capHeightAsString() const { return m->capHeightAsString() ; } QString FontBBoxAsString() const { return m->FontBBoxAsString() ; } QString ItalicAngleAsString() const { return m->ItalicAngleAsString() ; } double descent(double sz=1.0) const { return m->descent(sz); } double xHeight(double sz=1.0) const { return m->xHeight(sz); } @@ -351,16 +364,19 @@ public: 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; } + //TEST libotf + QString otfied (QString s) const { return m->otfied(s); } + myotf * otf() const { return m->otf();} private: friend class SCFonts; ScFace(ScFaceData* md); ScFaceData* m; QString replacedName; QString replacedInDoc; |
|
-myotf-patch-4.diff- ---Allow user to set features when an OTF file is loaded. ---Build a context string that allow pageItem::layoutGlyphs to achieve contextual transformations. ---Often segfault :) |
2007-04-06 19:16
|
harfbuzz-patch-0.diff (40,337 bytes)
Index: scribus/pageitem.cpp =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.cpp,v retrieving revision 1.121.2.419 diff -u -8 -p -r1.121.2.419 pageitem.cpp --- scribus/pageitem.cpp 25 Mar 2007 22:34:31 -0000 1.121.2.419 +++ scribus/pageitem.cpp 6 Apr 2007 19:15:00 -0000 @@ -1747,16 +1747,179 @@ double PageItem::layoutGlyphs(const Char layout.yadvance = layout.more->yadvance; } else { layout.shrink(); } return retval; } +// the same, but character to render is retrieved from contextStringPointer +double PageItem::layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout) +{ + QString chars; + bool otf = style.font().isOTF(); + if(contextString[0] == 0) // We have a special char that can't be processed by libotf + { + chars = contextString[1].unicode(); + } + else if(otf) + { + + if (contextStringPointer == 0) + { + contextGlyphsString = style.font().otfied(contextString); + //Now, we have 4 possibilities : + // 1/ one glyph for one character ; + // 2/ many glyphs for one character ; + // 3/ one glyph for many characters ; + // 4/ nothing if character was rendered in a previous case 3 call. + // Too much complicated for me, I take the shorter way. + int ls = contextString.length(); + int lg = contextGlyphsString.length(); + contexLengthChange = lg - ls; + } + if (contexLengthChange < 0) // source string is longer then the rendered string + { + contexLengthChange += 1; // waiting + contextStringPointer = -1; + layout.glyph = ScFace::CONTROL_GLYPHS + SpecialChars::ZWSPACE.unicode(); + return 0.0; + } + else if (contexLengthChange > 0) // in that case we just trust the GLyphLayout grow() + { + chars = contextGlyphsString.mid(contextStringPointer,contexLengthChange + len); + contexLengthChange = 0; + } + else if(contexLengthChange == 0) + { + if(contextStringPointer == -1) contextStringPointer = 0; + chars = contextGlyphsString.mid(contextStringPointer,len); + } + //contextStringPointer += 1; + } + else + { + chars = contextString.mid(contextStringPointer,len); + } + qDebug(QString("char is [%1], contextGlyphsString is [%2], contextStringPointer[%3], len [%4]").arg(chars[0].unicode()).arg(contextGlyphsString).arg(contextStringPointer).arg(len)); + double retval = 0.0; + double asce = style.font().ascent(style.fontSize() / 10.0); + int chst = style.effects() & 1919; + if (chars[0] == SpecialChars::ZWSPACE || + chars[0] == SpecialChars::ZWNBSPACE || + chars[0] == SpecialChars::NBSPACE || + chars[0] == SpecialChars::NBHYPHEN || + chars[0] == SpecialChars::SHYPHEN || + chars[0] == SpecialChars::PARSEP || + chars[0] == SpecialChars::COLBREAK || + chars[0] == SpecialChars::LINEBREAK || + chars[0] == SpecialChars::FRAMEBREAK || + chars[0] == SpecialChars::TAB) + { + layout.glyph = ScFace::CONTROL_GLYPHS + chars[0].unicode(); + } + else + { + layout.glyph = style.font().char2CMap(chars[0].unicode()); //otf comment : here we assume that the proper pair is in the c_Map cache + } + + double tracking = 0.0; + if ( (style.effects() & ScStyle_StartOfLine) == 0) + tracking = style.fontSize() * style.tracking() / 10000.0; + + layout.xoffset = tracking; + layout.yoffset = 0; + if (chst != ScStyle_Default) + { + if (chst & ScStyle_Superscript) + { + retval -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.yoffset -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSuperScript / 100.0, 10.0 / style.fontSize()); + } + else if (chst & ScStyle_Subscript) + { + retval += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.yoffset += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSubScript / 100.0, 10.0 / style.fontSize()); + } + else { + layout.scaleV = layout.scaleH = 1.0; + } + layout.scaleH *= style.scaleH() / 1000.0; + layout.scaleV *= style.scaleV() / 1000.0; + if (chst & ScStyle_AllCaps) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + } + if (chst & ScStyle_SmallCaps) + { + + double smallcapsScale = m_Doc->typographicSettings.valueSmallCaps / 100.0; + QChar uc = chars[0].upper(); + if (uc != chars[0]) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + layout.scaleV *= smallcapsScale; + layout.scaleH *= smallcapsScale; + } + } + } + else { + layout.scaleH = style.scaleH() / 1000.0; + layout.scaleV = style.scaleV() / 1000.0; + } + + if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) { + uint replGlyph = style.font().char2CMap(QChar(' ')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode())) { + uint replGlyph = style.font().char2CMap(QChar('-')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph >= ScFace::CONTROL_GLYPHS) { + layout.xadvance = 0; + layout.yadvance = 0; + } + else { + layout.xadvance = style.font().glyphWidth(layout.glyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(layout.glyph, style.fontSize() / 10).ascent * layout.scaleV; + } + if(otf)//Don't wait for ::layout to adjust with pair kerning + { + posglyph pg = style.font().otf()->get_position(contextStringPointer); + qDebug(QString("Adjust[%1] pg.xadv=%2 , pg.yadv=%3").arg(layout.glyph).arg(pg.xadvance()).arg(pg.yadvance())); + layout.xadvance = pg.xadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleH; + layout.yadvance = pg.yadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleV; + + + } + if (layout.xadvance > 0) + layout.xadvance += tracking; + + if (chars.length() > 1) { + layout.grow(); + contextStringPointer += 1; + layoutGlyphs(style, chars.length()-1, *layout.more); + layout.xadvance += style.font().glyphKerning(layout.glyph, layout.more->glyph, style.fontSize() / 10) * layout.scaleH; + if (layout.more->yadvance > layout.yadvance) + layout.yadvance = layout.more->yadvance; + } + else { + contextStringPointer += 1; + layout.shrink(); + } + + return retval; +} + void PageItem::drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs) { uint glyph = glyphs.glyph; if ((m_Doc->guidesSettings.showControls) && (glyph == style.font().char2CMap(QChar(' ')) || glyph >= ScFace::CONTROL_GLYPHS)) { bool stroke = false; if (glyph >= ScFace::CONTROL_GLYPHS) Index: scribus/pageitem.h =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.h,v retrieving revision 1.26.2.183 diff -u -8 -p -r1.26.2.183 pageitem.h --- scribus/pageitem.h 4 Apr 2007 21:46:32 -0000 1.26.2.183 +++ scribus/pageitem.h 6 Apr 2007 19:15:03 -0000 @@ -289,16 +289,17 @@ public: /// returns the style at the current charpos const ParagraphStyle& currentStyle() const; /// returns the style at the current charpos ParagraphStyle& changeCurrentStyle(); /// returns the style at the current charpos const CharStyle& currentCharStyle() const; // deprecated: double layoutGlyphs(const CharStyle& style, const QString chars, GlyphLayout& layout); + double layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout); void SetFarbe(QColor *tmp, QString farbe, int shad); void drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs ); void DrawPolyL(QPainter *p, QPointArray pts); QString ExpandToken(uint base); bool AutoName; double gXpos; double gYpos; @@ -1208,16 +1209,22 @@ public: /** Darstellungsart Bild/Titel */ bool PicArt; /** Line width */ double m_lineWidth; double Oldm_lineWidth; + /** Context String */ + QString contextString; + QString contextGlyphsString; + int contextStringPointer; + int contexLengthChange; + signals: //Frame signals void myself(PageItem *); void frameType(int); // not related to Frametype but to m_itemIype :-/ void position(double, double); //X,Y void widthAndHeight(double, double); //W,H void rotation(double); //Degrees rotation void colors(QString, QString, int, int); //lineColor, fillColor, lineShade, fillShade Index: scribus/pageitem_textframe.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/pageitem_textframe.cpp,v retrieving revision 1.1.2.159 diff -u -8 -p -r1.1.2.159 pageitem_textframe.cpp --- scribus/pageitem_textframe.cpp 5 Apr 2007 16:27:20 -0000 1.1.2.159 +++ scribus/pageitem_textframe.cpp 6 Apr 2007 19:15:08 -0000 @@ -565,19 +565,16 @@ static double opticalRightMargin(const S rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); } return rightCorr; } return 0.0; } - - - void PageItem_TextFrame::layout() { if (BackBox != NULL && BackBox->invalid) { // qDebug("textframe: len=%d, going back", itemText.length()); invalid = false; PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); if (!prevInChain) @@ -699,19 +696,71 @@ void PageItem_TextFrame::layout() else // empty itemText: { desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; } current.startLine(firstInFrame()); outs = false; OFs = 0; - MaxChars = 0; + MaxChars = 0; + // BIGLOOP + int contextrest = 0; + int sccontrol; for (int a = firstInFrame(); a < itemText.length(); ++a) { + // here we set the context string + if(contextrest == 0) + { + contextString = ""; + sccontrol = 0; + for(int ctsg = a; ctsg < itemText.length(); ++ctsg) + { + + QString contmp = ExpandToken(ctsg); + if(current.breakIndex == a) + { + break; + } + else if(contmp[0] == SpecialChars::ZWSPACE || + contmp[0] == SpecialChars::ZWNBSPACE || + contmp[0] == SpecialChars::NBSPACE || + contmp[0] == SpecialChars::NBHYPHEN || + contmp[0] == SpecialChars::SHYPHEN || + contmp[0] == SpecialChars::PARSEP || + contmp[0] == SpecialChars::COLBREAK || + contmp[0] == SpecialChars::LINEBREAK || + contmp[0] == SpecialChars::FRAMEBREAK || + contmp[0] == SpecialChars::TAB || + contmp[0] == SpecialChars::BLANK) + { + if(sccontrol > 0) + { + break; + } + else + { + contextString += QChar(0) ; + contextString += contmp[0].unicode(); + break; + } + } + else + { + sccontrol += 1; + contextString += contmp; + } + } + contextrest = (sccontrol == 0 ? 1 : contextString.length());// we send special char one by one + contextStringPointer = 0; + qDebug(QString("contextrest = %1 and context string is \"%2\"").arg(contextrest).arg(contextString)); + } + --contextrest; + + hl = itemText.item(a); if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) style = itemText.paragraphStyle(a); if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); // qDebug(QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); const CharStyle& charStyle = itemText.charStyle(a); @@ -862,30 +911,35 @@ void PageItem_TextFrame::layout() kernVal = 0; } else { kernVal = 0; // chs * charStyle.tracking() / 10000.0; itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); } hl->glyph.yadvance = 0; - oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); + //qDebug(QString("sending [%1] to layoutGlyphs()").arg(chstr)); + oldCurY = layoutGlyphs(*hl, chstr.length(), hl->glyph); + //oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); // find out width of char if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); else { wide = hl->glyph.wide(); // apply kerning if (a+1 < itemText.length()) { - uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); - double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; - wide += kern; - hl->glyph.xadvance += kern; + if( !charStyle.font().isOTF() ) + { + uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); + double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; + wide += kern; + hl->glyph.xadvance += kern; + } } } if (DropCmode) { // drop caps are wider... if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1352,16 +1406,17 @@ void PageItem_TextFrame::layout() tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); cm = QRegion(pf2.xForm(tcli)); cl = cl.subtract(cm); // current.yPos = maxDY; } // end of line if ( SpecialChars::isBreak(hl->ch[0], Cols > 1) || (outs)) { + contextrest = 0; tabs.active = false; tabs.status = TabNONE; if (SpecialChars::isBreak(hl->ch[0], Cols > 1)) { // find end of line current.breakLine(itemText, a); EndX = current.endOfLine(cl, pf2, asce, desc, style.rightMargin()); current.finishLine(EndX); Index: scribus/fonts/CMakeLists.txt =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/CMakeLists.txt,v retrieving revision 1.1.2.1 diff -u -8 -p -r1.1.2.1 CMakeLists.txt --- scribus/fonts/CMakeLists.txt 23 Jul 2006 12:07:47 -0000 1.1.2.1 +++ scribus/fonts/CMakeLists.txt 6 Apr 2007 19:15:12 -0000 @@ -5,12 +5,15 @@ ${CMAKE_SOURCE_DIR}/scribus SET(SCRIBUS_FONTS_LIB_SOURCES scface.cpp ftface.cpp scface_ps.cpp scface_ttf.cpp scfontmetrics.cpp +myotf.cpp ) + + SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.9 diff -u -8 -p -r1.1.2.9 ftface.cpp --- scribus/fonts/ftface.cpp 11 Jan 2007 15:29:46 -0000 1.1.2.9 +++ scribus/fonts/ftface.cpp 6 Apr 2007 19:15:12 -0000 @@ -2,16 +2,19 @@ #include "fonts/ftface.h" #include FT_OUTLINE_H #include FT_GLYPH_H #include <qobject.h> #include <qfile.h> +#include <qmessagebox.h> +#include <qinputdialog.h> + #include "scfonts.h" #include "fonts/scfontmetrics.h" // static: FT_Library FtFace::library = NULL; /***** ScFace lifecycle: unchecked -> loaded -> glyphs checked @@ -136,36 +139,116 @@ void FtFace::load() const ++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; } + //TEST libotf + if(typeCode == ScFace::OTF) + { + _otf = new myotf(QFile::encodeName(fontFile)); + bool ok; + QMessageBox::information( 0, "Scribus", + QString("You choose to use an OpenType Font file \"%1\".\n You have to set parameters for this font.").arg(scName) ); + + _otf->get_tables().contains("GSUB") ? _otf->set_table("GSUB") : _otf->set_table("GPOS"); + QStringList choice = _otf->get_scripts(); + if(choice.count() > 1) + { + otfScript = QInputDialog::getItem("Scribus :: otf", "Select the script ", choice, 0, FALSE, &ok ); + _otf->set_script(otfScript); + } + else + { + otfScript = choice[0]; + _otf->set_script(otfScript); + } + choice = _otf->get_langs(); + choice.append("dflt"); + if(choice.count() > 1) + { + otfLang = QInputDialog::getItem("Scribus :: otf", QString("Select the language for script %1").arg(otfScript), choice, 0, FALSE, &ok ); + _otf->set_lang(otfLang); + } + else + { + otfLang = choice[0]; + _otf->set_lang(otfLang); + } + if(_otf->get_tables().contains("GSUB")) + { + _otf->set_table("GSUB"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + choice =_otf->get_features(); + QString ft; + ok = TRUE; + // while(QMessageBox::question(0,"Scribus","Want to choose features for GSUB ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + while(ok && !choice.isEmpty()) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select GSUB feature for lang %1").arg(otfLang), choice, 0, FALSE, &ok ); + if(ok) + { + otfSubFeatures.append(ft); + choice.remove(ft); + } + } + } + if(_otf->get_tables().contains("GPOS")) + { + _otf->set_table("GPOS"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + choice =_otf->get_features(); + QString ft; + ok = TRUE; + // while(QMessageBox::question(0,"Scribus","Want to choose features for GPOS ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + while(ok && !choice.isEmpty()) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select GPOS feature for lang %1").arg(otfLang), choice, 0, FALSE, &ok ); + if(ok) + { + otfPosFeatures.append(ft); + choice.remove(ft); + } + } + } + qDebug("otf filled"); + } } void FtFace::unload() const { if (m_face) { FT_Done_Face( m_face ); m_face = NULL; } // clear caches + if(_otf) delete _otf; 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; + if(m_cMap.contains(ch.unicode())) + { + return m_cMap[ch.unicode()]; + } + else + { + FT_Face face = ftFace(); + uint gl = FT_Get_Char_Index(face, ch.unicode()); + m_cMap.insert(ch.unicode(), gl); + return gl; + } } void FtFace::loadGlyph(uint gl) const { if (m_glyphWidth.contains(gl)) return; @@ -307,9 +390,34 @@ void FtFace::RawData(QByteArray & bb) co // 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())); } */ } +QString FtFace::otfied(QString s) const +{ + qDebug("otfied"); + if(status != ScFace::LOADED) + { + qDebug("Face is not loaded"); + } + else if(typeCode == ScFace::OTF) + { + int nbg = _otf->procstring(s,otfScript,otfLang,otfSubFeatures,otfPosFeatures); + // Actually, newstring should be a QValueList<uint> as it's a glyphstring + QString newstring; + for (int i = 0; i < nbg ; ++i) + { + int gi= _otf->get_glyph(i); + newstring += QChar(gi); + m_cMap.insert(gi,gi); + } + + + qDebug(QString("oldstring is \"%1\" and new string is \"%2\"").arg(s).arg(newstring)); + return newstring; + } + return s; +} Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -8 -p -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 6 Apr 2007 19:15:13 -0000 @@ -96,22 +96,31 @@ protected: mutable QString Descender; mutable QString ItalicAngle; mutable QString StdVW; QString FontEnc; mutable QString FontBBox; mutable int m_encoding; - mutable double m_uniEM; +// mutable double m_uniEM; mutable double m_ascent; mutable double m_descent; mutable double m_height; mutable double m_xHeight; mutable double m_capHeight; mutable double m_maxAdvanceWidth; mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + //TEST libotf + public: + mutable QStringList otfSubFeatures; + mutable QStringList otfPosFeatures; + mutable QString otfScript; + mutable QString otfLang; + QString otfied(QString s) const ; + + }; #endif Index: scribus/fonts/myotf.cpp =================================================================== RCS file: scribus/fonts/myotf.cpp diff -N scribus/fonts/myotf.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.cpp 6 Apr 2007 19:15:13 -0000 @@ -0,0 +1,514 @@ +/* un test de libotf mer18jan qui se transforme en test de harfbuzz mer4avr*/ + + +#include "myotf.h" + +///Required by this great lib that do not provide all symbols +#include <harfbuzz-external.h> +//#include <Qt/private/qunicodetables_p.h> + +HB_LineBreakClass HB_GetLineBreakClass(HB_UChar32 ch) +{ +// #if QT_VERSION >= 0x040300 +// return (HB_LineBreakClass)QUnicodeTables::lineBreakClass(ch); +// #else +// #error "This test currently requires Qt >= 4.3" +// #endif + return (HB_LineBreakClass) 0; +} + +void HB_GetUnicodeCharProperties(HB_UChar32 ch, HB_CharCategory *category, int *combiningClass) +{ + *category = (HB_CharCategory)QChar::Category(ch); + *combiningClass = QChar::CombiningClass(ch); +} + +HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch) +{ + return (HB_CharCategory)QChar::Category(ch); +} + +int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch) +{ + return QChar::CombiningClass(ch); +} + +HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) +{ + return QChar(ch).mirroredChar(); +} +/// + +QString +OTF_tag_name (HB_UInt tag) +{ + QString name; + name[0] = (char) (tag >> 24); + name[1] = (char) ((tag >> 16) & 0xFF); + name[2] = (char) ((tag >> 8) & 0xFF); + name[3] = (char) (tag & 0xFF); +// qDebug(QString("OTF_tag_name (%1) -> %2").arg(tag).arg(name)); + return name; +} + +HB_UInt +OTF_name_tag (QString s) +{ + QChar sometimestagnameisthreecharslong = + s.length () > 3 ? s[3].unicode () : ' '; + HB_UInt ret = FT_MAKE_TAG (s[0].unicode (), s[1].unicode (), s[2].unicode (), + sometimestagnameisthreecharslong.unicode ()); +// qDebug(QString("OTF_name_tag (%1) -> %2").arg(s).arg(ret)); + return ret; +} + +//#define DFLT 0xFFFF + +void +myotf::set_subalt (bool b) +{ + subAlt = b; +} + +int myotf::get_glyph( int index) +{ + return _buffer->in_string[index].gindex; +} +int +myotf::get_glyph_used () +{ + // return mys.used; + return _buffer->in_length; +} + +myotf::myotf (QString n) +{ + nom = n; + if (FT_Init_FreeType (&_ftlib)) + qDebug ("oh merde"); + if (FT_New_Face (_ftlib, nom, 0, &_face)) + qDebug ("oh putaing"); + + hbFont.klass = NULL; /* Hope it will work without more code */ + hbFont.userData = 0; + hbFont.faceData = _face; + hbFont.x_ppem = _face->size->metrics.x_ppem; + hbFont.y_ppem = _face->size->metrics.y_ppem; + hbFont.x_scale = _face->size->metrics.x_scale; + hbFont.y_scale = _face->size->metrics.y_scale; + + subAlt = false; + glyphAlloc = false; + FT_ULong length = 0; + + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, NULL, &length)) + { + qDebug(QString("length of GDEF table is %1").arg(length)); + if(length > 0) + { + _memgdef.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, + (FT_Byte *) _memgdef.data (), &length); + gdefstream = new (HB_StreamRec); + gdefstream->base = (HB_Byte *) _memgdef.data (); + gdefstream->size = _memgdef.size (); + gdefstream->pos = 0; + + + HB_New_GDEF_Table (&_gdef); + if (!HB_Load_GDEF_Table (gdefstream, &_gdef)) + GDEF = 1; + else + GDEF = 0; + } + + else + GDEF = 0; + } + else + GDEF = 0; + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, NULL, &length)) + { + qDebug(QString("length of GSUB table is %1").arg(length)); + if(length > 0) + { + _memgsub.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, + (FT_Byte *) _memgsub.data (), &length); + gsubstream = new (HB_StreamRec); + gsubstream->base = (HB_Byte *) _memgsub.data (); + gsubstream->size = _memgsub.size (); + gsubstream->pos = 0; + + if (GDEF ? !HB_Load_GSUB_Table (gsubstream, &_gsub, _gdef, gdefstream) : + !HB_Load_GSUB_Table (gsubstream, &_gsub, NULL, NULL)) + GSUB = 1; + else + GSUB = 0; + } + else + GSUB = 0; + } + else + GSUB = 0; + // What are thes f... properties ? +// if(GSUB) +// { +// for(int i = 0; i < _gsub->LookupList.LookupCount ; i++) +// qDebug(QString("property[%1] = %2").arg(i).arg(_gsub->LookupList.Properties[i])); +// } + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, NULL, &length)) + { + qDebug(QString("length of GPOS table is %1").arg(length)); + if(length > 0) + { + _memgpos.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, + (FT_Byte *) _memgpos.data (), &length); + gposstream = new (HB_StreamRec); + gposstream->base = (HB_Byte *) _memgpos.data (); + gposstream->size = _memgpos.size (); + gposstream->pos = 0; + + if (GDEF ? !HB_Load_GPOS_Table (gposstream, &_gpos, _gdef, gdefstream) : + !HB_Load_GPOS_Table (gposstream, &_gpos, NULL, NULL)) + GPOS = 1; + else + GPOS = 0; + } + else + GPOS = 0; + } + else + GPOS = 0; + if (hb_buffer_new (&_buffer)) + qDebug ("unable to get _buffer"); +} + +myotf::~myotf () +{ + + if (_buffer) + hb_buffer_free (_buffer); + if (GDEF) + HB_Done_GDEF_Table (_gdef); + if (GSUB) + HB_Done_GSUB_Table (_gsub); + if (GPOS) + HB_Done_GPOS_Table (_gpos); + if (_face) + FT_Done_Face (_face); + if (_ftlib) + FT_Done_FreeType (_ftlib); +} + + +/// the actual function +int +myotf::procstring (QString s, QString script, QString lang, QStringList gsub, + QStringList gpos) +{ + qDebug (QString("procstring(%1, %2, %3, ...)").arg(s).arg(script).arg(lang)); + hb_buffer_clear( _buffer ); + int n = s.length (); + HB_Error error; + for (int i = 0; i < n; i++) + { + + error = hb_buffer_add_glyph (_buffer, + FT_Get_Char_Index (_face, s[i].unicode()), + 0, + 0); + qDebug(QString("adding glyph [%1] gives glyph [%2] properties [%3] cluster [%4]").arg(FT_Get_Char_Index (_face, s[i].unicode())).arg(_buffer->in_string[i].gindex).arg(_buffer->in_string[i].properties).arg(_buffer->in_string[i].cluster)); + + } + + qDebug(QString("in_string is %1 long").arg(_buffer->in_length)); + + if (gsub.count ()) + { + HB_GSUB_Clear_Features (_gsub); + set_table ("GSUB"); + set_script (script); + set_lang (lang); + + for (QStringList::iterator ife = gsub.begin (); ife != gsub.end (); + ife++) + { + HB_UShort fidx; + error = HB_GSUB_Select_Feature (_gsub, + OTF_name_tag (*ife), + curScript, curLang, &fidx); + if(!error) + { + HB_GSUB_Add_Feature (_gsub, fidx, 1); + qDebug(QString("GSUB [%2] feature.lookupcount = %1").arg(_gsub->FeatureList.FeatureRecord[fidx].Feature.LookupListCount).arg(*ife)); + } + else + qDebug(QString("adding gsub feature [%1] failed : %2").arg(*ife).arg(error)); + } + + error = HB_GSUB_Apply_String (_gsub, _buffer); + if(error)qDebug(QString("applying gsub features to string \"%1\" returned %2").arg(s).arg(error)); + + } + if (gpos.count ()) + { + HB_GPOS_Clear_Features (_gpos); + set_table ("GPOS"); + set_script (script); + set_lang (lang); + + for (QStringList::iterator ife = gpos.begin (); ife != gpos.end (); + ife++) + { + HB_UShort fidx; + error = HB_GPOS_Select_Feature (_gpos, + OTF_name_tag (*ife), + curScript, curLang, &fidx); + if(!error) + { + HB_GPOS_Add_Feature (_gpos, fidx, 1); + qDebug(QString("GPOS [%2] feature.lookupcount = %1").arg(_gpos->FeatureList.FeatureRecord[fidx].Feature.LookupListCount).arg(*ife)); + } + else + qDebug(QString("adding gsub feature [%1] failed : %2").arg(*ife).arg(error)); + } + error = HB_GPOS_Apply_String (&hbFont, _gpos, FT_LOAD_NO_SCALE, _buffer, + /*while dvi is true font klass is not used */ true, + /*r2l */ true); + if(error)qDebug(QString("applying gpos features to string \"%1\" returned %2").arg(s).arg(error)); + + } + + + return _buffer->in_length; +} + + + + + + +QStringList +myotf::get_tables () +{ + QStringList ret; + + // if (GDEF) + // ret.insert (ret.end (), "GDEF"); + if (GPOS) + ret.insert (ret.end (), "GPOS"); + if (GSUB) + ret.insert (ret.end (), "GSUB"); + + return ret; +} + +void +myotf::set_table (QString s) +{ + curTable = s; +} + +QStringList +myotf::get_scripts () +{ + qDebug("myotf::get_scripts ()"); + QStringList ret; + + if (curTable == "GSUB") + { + HB_UInt *taglist; + if (HB_GSUB_Query_Scripts (_gsub, &taglist)) + qDebug ("error HB_GSUB_Query_Scripts"); + while (*taglist) + { + qDebug(QString("script [%1]").arg(OTF_tag_name (*taglist))); + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + if (HB_GPOS_Query_Scripts (_gpos, &taglist)) + qDebug ("error HB_GPOS_Query_Scripts"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + } + return ret; + +} + +void +myotf::set_script (QString s) +{ + + curScriptName = s; + if (curTable == "GSUB") + { + if (HB_GSUB_Select_Script + (_gsub, OTF_name_tag (curScriptName), &curScript)) + qDebug (QString("Unable to set script index for %1").arg( curScriptName)); + } + if (curTable == "GPOS") + { + if (HB_GPOS_Select_Script + (_gpos, OTF_name_tag (curScriptName), &curScript)) + qDebug ("Unable to set script index"); + } +} + + +QStringList +myotf::get_langs () +{ + QStringList ret; + + if (curTable == "GSUB") + { + + HB_UInt *taglist; + if (HB_GSUB_Query_Languages (_gsub, curScript, &taglist)) + qDebug ("error HB_GSUB_Query_Langs"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + if (HB_GPOS_Query_Languages (_gpos, curScript, &taglist)) + qDebug ("error HB_GPOS_Query_Langs"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + + return ret; +} + +void +myotf::set_lang (QString s) +{ + if (s == "default" || s == "dflt" || s.isEmpty ()) + { + curLangName = "dflt"; + curLang = HB_DEFAULT_LANGUAGE; + return; + } + + curLangName = s; + if (curTable == "GSUB") + { + if (!HB_GSUB_Select_Language (_gsub, + OTF_name_tag (curLangName), + curScript, + &curLang, + &curLangReq)) + qDebug ("Unable to set lang index"); + } + if (curTable == "GPOS") + { + if (!HB_GPOS_Select_Language + (_gpos, OTF_name_tag (curLangName),curScript, &curLang, &curLangReq)) + qDebug ("Unable to set lang index"); + } + +} + + +QStringList +myotf::get_features (bool required ) +{ + QStringList ret; + + if (curTable == "GSUB") + { + + HB_UInt *taglist; + required ? HB_GSUB_Query_Features (_gsub, curScript, curLangReq, + &taglist) : + HB_GSUB_Query_Features (_gsub, curScript, curLang, &taglist); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + required ? HB_GPOS_Query_Features (_gpos, curScript, curLangReq, + &taglist) : + HB_GPOS_Query_Features (_gpos, curScript, curLang, &taglist); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + return ret; +} + +void +myotf::set_features (QStringList ls) +{ + curFeatures = ls; +} + +void dump_pos(HB_PositionRec p) +{ + qDebug(QString("xpos = %1 | ypos = %2 | xadv = %3 | yadv = %4 | %5 | back = %6 ").arg(p.x_pos).arg(p.y_pos).arg(p.x_advance).arg(p.y_advance).arg(p.new_advance ? "NEW" : "NOT_NEW").arg(p.back)); +} + +posglyph myotf::get_position (int g) +{ + posglyph + ret; + if (g > _buffer->in_length) + return ret; + + dump_pos(_buffer->positions[g]); + if (_buffer->positions[g].new_advance) + { + ret.Xadvance = (double) _buffer->positions[g].x_advance; + ret.Yadvance = (double) _buffer->positions[g].y_advance; + } + else + { + FT_GlyphSlot + slot = _face->glyph; + if (!FT_Load_Glyph + (_face, _buffer->in_string[g].gindex, FT_LOAD_NO_SCALE)) + { + ret.Xadvance = + (double) (_buffer->positions[g].x_advance + slot->advance.x); + ret.Yadvance = + (double) (_buffer->positions[g].y_advance + slot->advance.y); + } + + } + + + return ret; +} Index: scribus/fonts/myotf.h =================================================================== RCS file: scribus/fonts/myotf.h diff -N scribus/fonts/myotf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.h 6 Apr 2007 19:15:13 -0000 @@ -0,0 +1,110 @@ +// myotf.h + +#ifndef WRAPLIBOTF +#define WRAPLIBOTF + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TABLES_H + +extern "C" +{ +// #include <otf.h> +// #include <stdlib.h> +#include "harfbuzz.h" +} + +#include <iostream> +#include <iomanip> + +#include <qstring.h> +#include <qstringlist.h> + +using namespace std; + +struct posglyph +{ + double Xposition; + double Yposition; + double Xadvance; + double Yadvance; + double xadvance(){return Xadvance;} + double yadvance(){return Yadvance;} + double xposition(){return Xposition;} + double yposition(){return Yposition;} +}; + +class myotf +{ + QString nom; + + //OTF *my; + FT_Library _ftlib; + FT_Face _face; + HB_FontRec hbFont; + QByteArray _memgdef,_memgsub,_memgpos; + HB_StreamRec* gdefstream; + HB_StreamRec* gsubstream; + HB_StreamRec* gposstream; + HB_GDEF _gdef; + HB_GSUB _gsub; + HB_GPOS _gpos; + + //OTF_GlyphString mys; + HB_Buffer _buffer; + + + bool subAlt; + bool glyphAlloc; + + int head, name, cmap, GDEF, GSUB, GPOS; + +public: +// OTF_GlyphString * otfString() {return &mys;} +// int unicode(int gid){ return OTF_get_unicode(my, gid);} + int get_glyph( int index);//{return _buffer->out_string[index].gindex;} + QString curTable; + HB_UShort curScript, curLang, curLangReq; + QString curScriptName, curLangName; + QStringList curFeatures; + myotf (QString n); + ~myotf (); +/* + * These members functions apply features currently set + */ + int procstring (QString ); + int procstring (); + int procstring (QString s, QString script, QString lang, QStringList gsub, QStringList gpos); +/* + * These functions give access to informations contained in the fontfile + */ + QStringList get_tables (); + QStringList get_scripts (); + QStringList get_langs (); + QStringList get_features (bool required=false); +/* + * These allow to set up the features ( Tab -> Scr -> Lan -> Fea ) + */ + void set_table (QString); + void set_script (QString); + void set_lang (QString); + void set_features (QStringList); + void set_subalt (bool); +/* + * I can't remember what this so important method is expected to achieve ! + */ + int get_position_type (int); + /* + * for the moment, it just does nothing. Because I have no idea + * of which sruct can be the target of this function.Nevertheless + * I'm clearly aware that's the key function, it's the reason why + * i put this apart from procstring(). + * The argument is the number of the glyph + */ + + posglyph get_position(int); + int get_glyph_used(); + +}; + +#endif Index: scribus/fonts/scface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/scface.h,v retrieving revision 1.1.2.11 diff -u -8 -p -r1.1.2.11 scface.h --- scribus/fonts/scface.h 25 Mar 2007 22:34:32 -0000 1.1.2.11 +++ scribus/fonts/scface.h 6 Apr 2007 19:15:14 -0000 @@ -16,16 +16,19 @@ virtual: dispatch to constituents, #include <qstring.h> //#include <qvector.h> #include <qmap.h> //#include <qarray.h> #include <utility> #include "fpointarray.h" +//TEST libotf + +#include "myotf.h" struct GlyphMetrics { double width; double ascent; double descent; }; @@ -109,16 +112,21 @@ public: bool usable; bool embedPs; bool subset; bool isStroked; bool isFixedPitch; bool hasNames; uint maxGlyph; + mutable double m_uniEM; + protected : + mutable myotf * _otf; + public: + myotf * otf() const { return _otf;} ScFaceData(); virtual ~ScFaceData() { }; protected: friend class ScFace; Status cachedStatus; @@ -145,16 +153,17 @@ public: m_cMap.clear(); status = ScFace::UNKNOWN; } virtual void loadGlyph(uint /*gl*/) const {} // dummy implementations + virtual double uniEM() const {return m_uniEM;} virtual double ascent(double sz) const { return sz; } virtual QString ascentAsString() const { return "0" ; } virtual QString descentAsString() const { return "0"; } virtual QString capHeightAsString() const { return "0"; } virtual QString FontBBoxAsString() const { return "0 0 0 0"; } virtual QString ItalicAngleAsString() const { return "0"; } virtual double descent(double /*sz*/) const { return 0.0; } virtual double xHeight(double sz) const { return sz; } @@ -166,16 +175,19 @@ public: 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<uint, std::pair<QChar, QString> >& gList) const; + + virtual QString otfied(QString s) const {return s;} + // 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; }; @@ -293,16 +305,17 @@ public: /// 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 unitsEM () const {return m->uniEM();} double ascent(double sz=1.0) const { return m->ascent(sz); } QString ascentAsString() const { return m->ascentAsString() ; } QString descentAsString() const { return m->descentAsString() ; } QString capHeightAsString() const { return m->capHeightAsString() ; } QString FontBBoxAsString() const { return m->FontBBoxAsString() ; } QString ItalicAngleAsString() const { return m->ItalicAngleAsString() ; } double descent(double sz=1.0) const { return m->descent(sz); } double xHeight(double sz=1.0) const { return m->xHeight(sz); } @@ -359,16 +372,19 @@ public: 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; } + //TEST libotf + QString otfied (QString s) const { return m->otfied(s); } + myotf * otf() const { return m->otf();} private: friend class SCFonts; ScFace(ScFaceData* md); ScFaceData* m; QString replacedName; QString replacedInDoc; |
2007-04-07 10:04
|
harfbuzz-patch-1.diff (40,558 bytes)
Index: scribus/pageitem.cpp =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.cpp,v retrieving revision 1.121.2.419 diff -u -8 -p -r1.121.2.419 pageitem.cpp --- scribus/pageitem.cpp 25 Mar 2007 22:34:31 -0000 1.121.2.419 +++ scribus/pageitem.cpp 7 Apr 2007 10:03:24 -0000 @@ -1747,16 +1747,179 @@ double PageItem::layoutGlyphs(const Char layout.yadvance = layout.more->yadvance; } else { layout.shrink(); } return retval; } +// the same, but character to render is retrieved from contextStringPointer +double PageItem::layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout) +{ + QString chars; + bool otf = style.font().isOTF(); + if(contextString[0] == 0) // We have a special char that can't be processed by libotf + { + chars = contextString[1].unicode(); + } + else if(otf) + { + + if (contextStringPointer == 0) + { + contextGlyphsString = style.font().otfied(contextString); + //Now, we have 4 possibilities : + // 1/ one glyph for one character ; + // 2/ many glyphs for one character ; + // 3/ one glyph for many characters ; + // 4/ nothing if character was rendered in a previous case 3 call. + // Too much complicated for me, I take the shorter way. + int ls = contextString.length(); + int lg = contextGlyphsString.length(); + contexLengthChange = lg - ls; + } + if (contexLengthChange < 0) // source string is longer then the rendered string + { + contexLengthChange += 1; // waiting + contextStringPointer = -1; + layout.glyph = ScFace::CONTROL_GLYPHS + SpecialChars::ZWSPACE.unicode(); + return 0.0; + } + else if (contexLengthChange > 0) // in that case we just trust the GLyphLayout grow() + { + chars = contextGlyphsString.mid(contextStringPointer,contexLengthChange + len); + contexLengthChange = 0; + } + else if(contexLengthChange == 0) + { + if(contextStringPointer == -1) contextStringPointer = 0; + chars = contextGlyphsString.mid(contextStringPointer,len); + } + //contextStringPointer += 1; + } + else + { + chars = contextString.mid(contextStringPointer,len); + } + qDebug(QString("char is [%1], contextGlyphsString is [%2], contextStringPointer[%3], len [%4]").arg(chars[0].unicode()).arg(contextGlyphsString).arg(contextStringPointer).arg(len)); + double retval = 0.0; + double asce = style.font().ascent(style.fontSize() / 10.0); + int chst = style.effects() & 1919; + if (chars[0] == SpecialChars::ZWSPACE || + chars[0] == SpecialChars::ZWNBSPACE || + chars[0] == SpecialChars::NBSPACE || + chars[0] == SpecialChars::NBHYPHEN || + chars[0] == SpecialChars::SHYPHEN || + chars[0] == SpecialChars::PARSEP || + chars[0] == SpecialChars::COLBREAK || + chars[0] == SpecialChars::LINEBREAK || + chars[0] == SpecialChars::FRAMEBREAK || + chars[0] == SpecialChars::TAB) + { + layout.glyph = ScFace::CONTROL_GLYPHS + chars[0].unicode(); + } + else + { + layout.glyph = style.font().char2CMap(chars[0].unicode()); //otf comment : here we assume that the proper pair is in the c_Map cache + } + + double tracking = 0.0; + if ( (style.effects() & ScStyle_StartOfLine) == 0) + tracking = style.fontSize() * style.tracking() / 10000.0; + + layout.xoffset = tracking; + layout.yoffset = 0; + if (chst != ScStyle_Default) + { + if (chst & ScStyle_Superscript) + { + retval -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.yoffset -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSuperScript / 100.0, 10.0 / style.fontSize()); + } + else if (chst & ScStyle_Subscript) + { + retval += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.yoffset += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSubScript / 100.0, 10.0 / style.fontSize()); + } + else { + layout.scaleV = layout.scaleH = 1.0; + } + layout.scaleH *= style.scaleH() / 1000.0; + layout.scaleV *= style.scaleV() / 1000.0; + if (chst & ScStyle_AllCaps) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + } + if (chst & ScStyle_SmallCaps) + { + + double smallcapsScale = m_Doc->typographicSettings.valueSmallCaps / 100.0; + QChar uc = chars[0].upper(); + if (uc != chars[0]) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + layout.scaleV *= smallcapsScale; + layout.scaleH *= smallcapsScale; + } + } + } + else { + layout.scaleH = style.scaleH() / 1000.0; + layout.scaleV = style.scaleV() / 1000.0; + } + + if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) { + uint replGlyph = style.font().char2CMap(QChar(' ')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode())) { + uint replGlyph = style.font().char2CMap(QChar('-')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph >= ScFace::CONTROL_GLYPHS) { + layout.xadvance = 0; + layout.yadvance = 0; + } + else { + layout.xadvance = style.font().glyphWidth(layout.glyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(layout.glyph, style.fontSize() / 10).ascent * layout.scaleV; + } + if(otf)//Don't wait for ::layout to adjust with pair kerning + { + posglyph pg = style.font().otf()->get_position(contextStringPointer); + qDebug(QString("Adjust[%1] pg.xadv=%2 , pg.yadv=%3").arg(layout.glyph).arg(pg.xadvance()).arg(pg.yadvance())); + layout.xadvance = pg.xadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleH; + layout.yadvance = pg.yadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleV; + + + } + if (layout.xadvance > 0) + layout.xadvance += tracking; + + if (chars.length() > 1) { + layout.grow(); + contextStringPointer += 1; + layoutGlyphs(style, chars.length()-1, *layout.more); + layout.xadvance += style.font().glyphKerning(layout.glyph, layout.more->glyph, style.fontSize() / 10) * layout.scaleH; + if (layout.more->yadvance > layout.yadvance) + layout.yadvance = layout.more->yadvance; + } + else { + contextStringPointer += 1; + layout.shrink(); + } + + return retval; +} + void PageItem::drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs) { uint glyph = glyphs.glyph; if ((m_Doc->guidesSettings.showControls) && (glyph == style.font().char2CMap(QChar(' ')) || glyph >= ScFace::CONTROL_GLYPHS)) { bool stroke = false; if (glyph >= ScFace::CONTROL_GLYPHS) Index: scribus/pageitem.h =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.h,v retrieving revision 1.26.2.183 diff -u -8 -p -r1.26.2.183 pageitem.h --- scribus/pageitem.h 4 Apr 2007 21:46:32 -0000 1.26.2.183 +++ scribus/pageitem.h 7 Apr 2007 10:03:29 -0000 @@ -289,16 +289,17 @@ public: /// returns the style at the current charpos const ParagraphStyle& currentStyle() const; /// returns the style at the current charpos ParagraphStyle& changeCurrentStyle(); /// returns the style at the current charpos const CharStyle& currentCharStyle() const; // deprecated: double layoutGlyphs(const CharStyle& style, const QString chars, GlyphLayout& layout); + double layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout); void SetFarbe(QColor *tmp, QString farbe, int shad); void drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs ); void DrawPolyL(QPainter *p, QPointArray pts); QString ExpandToken(uint base); bool AutoName; double gXpos; double gYpos; @@ -1208,16 +1209,22 @@ public: /** Darstellungsart Bild/Titel */ bool PicArt; /** Line width */ double m_lineWidth; double Oldm_lineWidth; + /** Context String */ + QString contextString; + QString contextGlyphsString; + int contextStringPointer; + int contexLengthChange; + signals: //Frame signals void myself(PageItem *); void frameType(int); // not related to Frametype but to m_itemIype :-/ void position(double, double); //X,Y void widthAndHeight(double, double); //W,H void rotation(double); //Degrees rotation void colors(QString, QString, int, int); //lineColor, fillColor, lineShade, fillShade Index: scribus/pageitem_textframe.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/pageitem_textframe.cpp,v retrieving revision 1.1.2.159 diff -u -8 -p -r1.1.2.159 pageitem_textframe.cpp --- scribus/pageitem_textframe.cpp 5 Apr 2007 16:27:20 -0000 1.1.2.159 +++ scribus/pageitem_textframe.cpp 7 Apr 2007 10:03:33 -0000 @@ -565,19 +565,16 @@ static double opticalRightMargin(const S rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); } return rightCorr; } return 0.0; } - - - void PageItem_TextFrame::layout() { if (BackBox != NULL && BackBox->invalid) { // qDebug("textframe: len=%d, going back", itemText.length()); invalid = false; PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); if (!prevInChain) @@ -699,19 +696,71 @@ void PageItem_TextFrame::layout() else // empty itemText: { desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; } current.startLine(firstInFrame()); outs = false; OFs = 0; - MaxChars = 0; + MaxChars = 0; + // BIGLOOP + int contextrest = 0; + int sccontrol; for (int a = firstInFrame(); a < itemText.length(); ++a) { + // here we set the context string + if(contextrest == 0) + { + contextString = ""; + sccontrol = 0; + for(int ctsg = a; ctsg < itemText.length(); ++ctsg) + { + + QString contmp = ExpandToken(ctsg); + if(current.breakIndex == a) + { + break; + } + else if(contmp[0] == SpecialChars::ZWSPACE || + contmp[0] == SpecialChars::ZWNBSPACE || + contmp[0] == SpecialChars::NBSPACE || + contmp[0] == SpecialChars::NBHYPHEN || + contmp[0] == SpecialChars::SHYPHEN || + contmp[0] == SpecialChars::PARSEP || + contmp[0] == SpecialChars::COLBREAK || + contmp[0] == SpecialChars::LINEBREAK || + contmp[0] == SpecialChars::FRAMEBREAK || + contmp[0] == SpecialChars::TAB || + contmp[0] == SpecialChars::BLANK) + { + if(sccontrol > 0) + { + break; + } + else + { + contextString += QChar(0) ; + contextString += contmp[0].unicode(); + break; + } + } + else + { + sccontrol += 1; + contextString += contmp; + } + } + contextrest = (sccontrol == 0 ? 1 : contextString.length());// we send special char one by one + contextStringPointer = 0; + qDebug(QString("contextrest = %1 and context string is \"%2\"").arg(contextrest).arg(contextString)); + } + --contextrest; + + hl = itemText.item(a); if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) style = itemText.paragraphStyle(a); if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); // qDebug(QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); const CharStyle& charStyle = itemText.charStyle(a); @@ -862,30 +911,35 @@ void PageItem_TextFrame::layout() kernVal = 0; } else { kernVal = 0; // chs * charStyle.tracking() / 10000.0; itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); } hl->glyph.yadvance = 0; - oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); + //qDebug(QString("sending [%1] to layoutGlyphs()").arg(chstr)); + oldCurY = layoutGlyphs(*hl, chstr.length(), hl->glyph); + //oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); // find out width of char if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); else { wide = hl->glyph.wide(); // apply kerning if (a+1 < itemText.length()) { - uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); - double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; - wide += kern; - hl->glyph.xadvance += kern; + if( !charStyle.font().isOTF() ) + { + uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); + double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; + wide += kern; + hl->glyph.xadvance += kern; + } } } if (DropCmode) { // drop caps are wider... if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1352,16 +1406,17 @@ void PageItem_TextFrame::layout() tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); cm = QRegion(pf2.xForm(tcli)); cl = cl.subtract(cm); // current.yPos = maxDY; } // end of line if ( SpecialChars::isBreak(hl->ch[0], Cols > 1) || (outs)) { + contextrest = 0; tabs.active = false; tabs.status = TabNONE; if (SpecialChars::isBreak(hl->ch[0], Cols > 1)) { // find end of line current.breakLine(itemText, a); EndX = current.endOfLine(cl, pf2, asce, desc, style.rightMargin()); current.finishLine(EndX); Index: scribus/fonts/CMakeLists.txt =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/CMakeLists.txt,v retrieving revision 1.1.2.1 diff -u -8 -p -r1.1.2.1 CMakeLists.txt --- scribus/fonts/CMakeLists.txt 23 Jul 2006 12:07:47 -0000 1.1.2.1 +++ scribus/fonts/CMakeLists.txt 7 Apr 2007 10:03:36 -0000 @@ -5,12 +5,15 @@ ${CMAKE_SOURCE_DIR}/scribus SET(SCRIBUS_FONTS_LIB_SOURCES scface.cpp ftface.cpp scface_ps.cpp scface_ttf.cpp scfontmetrics.cpp +myotf.cpp ) + + SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.9 diff -u -8 -p -r1.1.2.9 ftface.cpp --- scribus/fonts/ftface.cpp 11 Jan 2007 15:29:46 -0000 1.1.2.9 +++ scribus/fonts/ftface.cpp 7 Apr 2007 10:03:37 -0000 @@ -2,16 +2,19 @@ #include "fonts/ftface.h" #include FT_OUTLINE_H #include FT_GLYPH_H #include <qobject.h> #include <qfile.h> +#include <qmessagebox.h> +#include <qinputdialog.h> + #include "scfonts.h" #include "fonts/scfontmetrics.h" // static: FT_Library FtFace::library = NULL; /***** ScFace lifecycle: unchecked -> loaded -> glyphs checked @@ -136,36 +139,116 @@ void FtFace::load() const ++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; } + //TEST libotf + if(typeCode == ScFace::OTF) + { + _otf = new myotf(QFile::encodeName(fontFile)); + bool ok; + QMessageBox::information( 0, "Scribus", + QString("You choose to use an OpenType Font file \"%1\".\n You have to set parameters for this font.").arg(scName) ); + + _otf->get_tables().contains("GSUB") ? _otf->set_table("GSUB") : _otf->set_table("GPOS"); + QStringList choice = _otf->get_scripts(); + if(choice.count() > 1) + { + otfScript = QInputDialog::getItem("Scribus :: otf", "Select the script ", choice, 0, FALSE, &ok ); + _otf->set_script(otfScript); + } + else + { + otfScript = choice[0]; + _otf->set_script(otfScript); + } + choice = _otf->get_langs(); + choice.append("dflt"); + if(choice.count() > 1) + { + otfLang = QInputDialog::getItem("Scribus :: otf", QString("Select the language for script %1").arg(otfScript), choice, 0, FALSE, &ok ); + _otf->set_lang(otfLang); + } + else + { + otfLang = choice[0]; + _otf->set_lang(otfLang); + } + if(_otf->get_tables().contains("GSUB")) + { + _otf->set_table("GSUB"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + choice =_otf->get_features(); + QString ft; + ok = TRUE; + // while(QMessageBox::question(0,"Scribus","Want to choose features for GSUB ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + while(ok && !choice.isEmpty()) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select GSUB feature for lang %1").arg(otfLang), choice, 0, FALSE, &ok ); + if(ok) + { + otfSubFeatures.append(ft); + choice.remove(ft); + } + } + } + if(_otf->get_tables().contains("GPOS")) + { + _otf->set_table("GPOS"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + choice =_otf->get_features(); + QString ft; + ok = TRUE; + // while(QMessageBox::question(0,"Scribus","Want to choose features for GPOS ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + while(ok && !choice.isEmpty()) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select GPOS feature for lang %1").arg(otfLang), choice, 0, FALSE, &ok ); + if(ok) + { + otfPosFeatures.append(ft); + choice.remove(ft); + } + } + } + qDebug("otf filled"); + } } void FtFace::unload() const { if (m_face) { FT_Done_Face( m_face ); m_face = NULL; } // clear caches + if(_otf) delete _otf; 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; + if(m_cMap.contains(ch.unicode())) + { + return m_cMap[ch.unicode()]; + } + else + { + FT_Face face = ftFace(); + uint gl = FT_Get_Char_Index(face, ch.unicode()); + m_cMap.insert(ch.unicode(), gl); + return gl; + } } void FtFace::loadGlyph(uint gl) const { if (m_glyphWidth.contains(gl)) return; @@ -307,9 +390,34 @@ void FtFace::RawData(QByteArray & bb) co // 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())); } */ } +QString FtFace::otfied(QString s) const +{ + qDebug("otfied"); + if(status != ScFace::LOADED) + { + qDebug("Face is not loaded"); + } + else if(typeCode == ScFace::OTF) + { + int nbg = _otf->procstring(s,otfScript,otfLang,otfSubFeatures,otfPosFeatures); + // Actually, newstring should be a QValueList<uint> as it's a glyphstring + QString newstring; + for (int i = 0; i < nbg ; ++i) + { + int gi= _otf->get_glyph(i); + newstring += QChar(gi); + m_cMap.insert(gi,gi); + } + + + qDebug(QString("oldstring is \"%1\" and new string is \"%2\"").arg(s).arg(newstring)); + return newstring; + } + return s; +} Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -8 -p -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 7 Apr 2007 10:03:37 -0000 @@ -96,22 +96,31 @@ protected: mutable QString Descender; mutable QString ItalicAngle; mutable QString StdVW; QString FontEnc; mutable QString FontBBox; mutable int m_encoding; - mutable double m_uniEM; +// mutable double m_uniEM; mutable double m_ascent; mutable double m_descent; mutable double m_height; mutable double m_xHeight; mutable double m_capHeight; mutable double m_maxAdvanceWidth; mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + //TEST libotf + public: + mutable QStringList otfSubFeatures; + mutable QStringList otfPosFeatures; + mutable QString otfScript; + mutable QString otfLang; + QString otfied(QString s) const ; + + }; #endif Index: scribus/fonts/myotf.cpp =================================================================== RCS file: scribus/fonts/myotf.cpp diff -N scribus/fonts/myotf.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.cpp 7 Apr 2007 10:03:38 -0000 @@ -0,0 +1,515 @@ +/* un test de libotf mer18jan qui se transforme en test de harfbuzz mer4avr*/ + + +#include "myotf.h" + +///Required by this great lib that do not provide all symbols +#include <harfbuzz-external.h> +//#include <Qt/private/qunicodetables_p.h> + +HB_LineBreakClass HB_GetLineBreakClass(HB_UChar32 ch) +{ +// #if QT_VERSION >= 0x040300 +// return (HB_LineBreakClass)QUnicodeTables::lineBreakClass(ch); +// #else +// #error "This test currently requires Qt >= 4.3" +// #endif + return (HB_LineBreakClass) 0; +} + +void HB_GetUnicodeCharProperties(HB_UChar32 ch, HB_CharCategory *category, int *combiningClass) +{ + *category = (HB_CharCategory)QChar::Category(ch); + *combiningClass = QChar::CombiningClass(ch); +} + +HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch) +{ + return (HB_CharCategory)QChar::Category(ch); +} + +int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch) +{ + return QChar::CombiningClass(ch); +} + +HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) +{ + return QChar(ch).mirroredChar(); +} +/// + +QString +OTF_tag_name (HB_UInt tag) +{ + QString name; + name[0] = (char) (tag >> 24); + name[1] = (char) ((tag >> 16) & 0xFF); + name[2] = (char) ((tag >> 8) & 0xFF); + name[3] = (char) (tag & 0xFF); +// qDebug(QString("OTF_tag_name (%1) -> %2").arg(tag).arg(name)); + return name; +} + +HB_UInt +OTF_name_tag (QString s) +{ + QChar sometimestagnameisthreecharslong = + s.length () > 3 ? s[3].unicode () : ' '; + HB_UInt ret = FT_MAKE_TAG (s[0].unicode (), s[1].unicode (), s[2].unicode (), + sometimestagnameisthreecharslong.unicode ()); +// qDebug(QString("OTF_name_tag (%1) -> %2").arg(s).arg(ret)); + return ret; +} + +//#define DFLT 0xFFFF + +void +myotf::set_subalt (bool b) +{ + subAlt = b; +} + +int myotf::get_glyph( int index) +{ + return _buffer->in_string[index].gindex; +} +int +myotf::get_glyph_used () +{ + // return mys.used; + return _buffer->in_length; +} + +myotf::myotf (QString n) +{ + nom = n; + if (FT_Init_FreeType (&_ftlib)) + qDebug ("oh merde"); + if (FT_New_Face (_ftlib, nom, 0, &_face)) + qDebug ("oh putaing"); + + hbFont.klass = NULL; /* Hope it will work without more code */ + hbFont.userData = 0; + hbFont.faceData = _face; + hbFont.x_ppem = _face->size->metrics.x_ppem; + hbFont.y_ppem = _face->size->metrics.y_ppem; + hbFont.x_scale = 0x10000;//_face->size->metrics.x_scale; + hbFont.y_scale = 0x10000;//_face->size->metrics.y_scale; + + subAlt = false; + glyphAlloc = false; + FT_ULong length = 0; + + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, NULL, &length)) + { + qDebug(QString("length of GDEF table is %1").arg(length)); + if(length > 0) + { + _memgdef.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, + (FT_Byte *) _memgdef.data (), &length); + gdefstream = new (HB_StreamRec); + gdefstream->base = (HB_Byte *) _memgdef.data (); + gdefstream->size = _memgdef.size (); + gdefstream->pos = 0; + + + HB_New_GDEF_Table (&_gdef); + if (!HB_Load_GDEF_Table (gdefstream, &_gdef)) + GDEF = 1; + else + GDEF = 0; + } + + else + GDEF = 0; + } + else + GDEF = 0; + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, NULL, &length)) + { + qDebug(QString("length of GSUB table is %1").arg(length)); + if(length > 32)//Some font files seem to have a fake table that is just 32 words long and make harbuzz confused + { + _memgsub.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, + (FT_Byte *) _memgsub.data (), &length); + gsubstream = new (HB_StreamRec); + gsubstream->base = (HB_Byte *) _memgsub.data (); + gsubstream->size = _memgsub.size (); + gsubstream->pos = 0; + + if (GDEF ? !HB_Load_GSUB_Table (gsubstream, &_gsub, _gdef, gdefstream) : + !HB_Load_GSUB_Table (gsubstream, &_gsub, NULL, NULL)) + GSUB = 1; + else + GSUB = 0; + } + else + GSUB = 0; + } + else + GSUB = 0; + // What are thes f... properties ? +// if(GSUB) +// { +// for(int i = 0; i < _gsub->LookupList.LookupCount ; i++) +// qDebug(QString("property[%1] = %2").arg(i).arg(_gsub->LookupList.Properties[i])); +// } + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, NULL, &length)) + { + qDebug(QString("length of GPOS table is %1").arg(length)); + if(length > 32) + { + _memgpos.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, + (FT_Byte *) _memgpos.data (), &length); + gposstream = new (HB_StreamRec); + gposstream->base = (HB_Byte *) _memgpos.data (); + gposstream->size = _memgpos.size (); + gposstream->pos = 0; + + if (GDEF ? !HB_Load_GPOS_Table (gposstream, &_gpos, _gdef, gdefstream) : + !HB_Load_GPOS_Table (gposstream, &_gpos, NULL, NULL)) + GPOS = 1; + else + GPOS = 0; + } + else + GPOS = 0; + } + else + GPOS = 0; + if (hb_buffer_new (&_buffer)) + qDebug ("unable to get _buffer"); +} + +myotf::~myotf () +{ + + if (_buffer) + hb_buffer_free (_buffer); + if (GDEF) + HB_Done_GDEF_Table (_gdef); + if (GSUB) + HB_Done_GSUB_Table (_gsub); + if (GPOS) + HB_Done_GPOS_Table (_gpos); + if (_face) + FT_Done_Face (_face); + if (_ftlib) + FT_Done_FreeType (_ftlib); +} + + +/// the actual function +int +myotf::procstring (QString s, QString script, QString lang, QStringList gsub, + QStringList gpos) +{ + qDebug (QString("procstring(%1, %2, %3, ...)").arg(s).arg(script).arg(lang)); + hb_buffer_clear( _buffer ); + int n = s.length (); + HB_Error error; + for (int i = 0; i < n; i++) + { + + error = hb_buffer_add_glyph (_buffer, + FT_Get_Char_Index (_face, s[i].unicode()), + 0, + 0); + qDebug(QString("adding glyph [%1] gives glyph [%2] properties [%3] cluster [%4]").arg(FT_Get_Char_Index (_face, s[i].unicode())).arg(_buffer->in_string[i].gindex).arg(_buffer->in_string[i].properties).arg(_buffer->in_string[i].cluster)); + + } + + qDebug(QString("in_string is %1 long").arg(_buffer->in_length)); + + if (gsub.count ()) + { + HB_GSUB_Clear_Features (_gsub); + set_table ("GSUB"); + set_script (script); + set_lang (lang); + + for (QStringList::iterator ife = gsub.begin (); ife != gsub.end (); + ife++) + { + HB_UShort fidx; + error = HB_GSUB_Select_Feature (_gsub, + OTF_name_tag (*ife), + curScript, curLang, &fidx); + if(!error) + { + HB_GSUB_Add_Feature (_gsub, fidx, 1); + qDebug(QString("GSUB [%2] feature.lookupcount = %1").arg(_gsub->FeatureList.FeatureRecord[fidx].Feature.LookupListCount).arg(*ife)); + } + else + qDebug(QString("adding gsub feature [%1] failed : %2").arg(*ife).arg(error)); + } + + error = HB_GSUB_Apply_String (_gsub, _buffer); + if(error)qDebug(QString("applying gsub features to string \"%1\" returned %2").arg(s).arg(error)); + + } + if (gpos.count ()) + { + HB_GPOS_Clear_Features (_gpos); + set_table ("GPOS"); + set_script (script); + set_lang (lang); + + for (QStringList::iterator ife = gpos.begin (); ife != gpos.end (); + ife++) + { + HB_UShort fidx; + error = HB_GPOS_Select_Feature (_gpos, + OTF_name_tag (*ife), + curScript, curLang, &fidx); + if(!error) + { + HB_GPOS_Add_Feature (_gpos, fidx, 1); + qDebug(QString("GPOS [%2] feature.lookupcount = %1").arg(_gpos->FeatureList.FeatureRecord[fidx].Feature.LookupListCount).arg(*ife)); + } + else + qDebug(QString("adding gsub feature [%1] failed : %2").arg(*ife).arg(error)); + } + if(_buffer->in_length > 0) memset(_buffer->positions, 0, _buffer->in_length*sizeof(HB_PositionRec)); + error = HB_GPOS_Apply_String (&hbFont, _gpos, FT_LOAD_NO_SCALE, _buffer, + /*while dvi is true font klass is not used */ true, + /*r2l */ true); + if(error)qDebug(QString("applying gpos features to string \"%1\" returned %2").arg(s).arg(error)); + + } + + + return _buffer->in_length; +} + + + + + + +QStringList +myotf::get_tables () +{ + QStringList ret; + + // if (GDEF) + // ret.insert (ret.end (), "GDEF"); + if (GPOS) + ret.insert (ret.end (), "GPOS"); + if (GSUB) + ret.insert (ret.end (), "GSUB"); + + return ret; +} + +void +myotf::set_table (QString s) +{ + curTable = s; +} + +QStringList +myotf::get_scripts () +{ + qDebug("myotf::get_scripts ()"); + QStringList ret; + + if (curTable == "GSUB") + { + HB_UInt *taglist; + if (HB_GSUB_Query_Scripts (_gsub, &taglist)) + qDebug ("error HB_GSUB_Query_Scripts"); + while (*taglist) + { + qDebug(QString("script [%1]").arg(OTF_tag_name (*taglist))); + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + if (HB_GPOS_Query_Scripts (_gpos, &taglist)) + qDebug ("error HB_GPOS_Query_Scripts"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + } + return ret; + +} + +void +myotf::set_script (QString s) +{ + + curScriptName = s; + if (curTable == "GSUB") + { + if (HB_GSUB_Select_Script + (_gsub, OTF_name_tag (curScriptName), &curScript)) + qDebug (QString("Unable to set script index for %1").arg( curScriptName)); + } + if (curTable == "GPOS") + { + if (HB_GPOS_Select_Script + (_gpos, OTF_name_tag (curScriptName), &curScript)) + qDebug ("Unable to set script index"); + } +} + + +QStringList +myotf::get_langs () +{ + QStringList ret; + + if (curTable == "GSUB") + { + + HB_UInt *taglist; + if (HB_GSUB_Query_Languages (_gsub, curScript, &taglist)) + qDebug ("error HB_GSUB_Query_Langs"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + if (HB_GPOS_Query_Languages (_gpos, curScript, &taglist)) + qDebug ("error HB_GPOS_Query_Langs"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + + return ret; +} + +void +myotf::set_lang (QString s) +{ + if (s == "default" || s == "dflt" || s.isEmpty ()) + { + curLangName = "dflt"; + curLang = HB_DEFAULT_LANGUAGE; + return; + } + + curLangName = s; + if (curTable == "GSUB") + { + if (!HB_GSUB_Select_Language (_gsub, + OTF_name_tag (curLangName), + curScript, + &curLang, + &curLangReq)) + qDebug ("Unable to set lang index"); + } + if (curTable == "GPOS") + { + if (!HB_GPOS_Select_Language + (_gpos, OTF_name_tag (curLangName),curScript, &curLang, &curLangReq)) + qDebug ("Unable to set lang index"); + } + +} + + +QStringList +myotf::get_features (bool required ) +{ + QStringList ret; + + if (curTable == "GSUB") + { + + HB_UInt *taglist; + required ? HB_GSUB_Query_Features (_gsub, curScript, curLangReq, + &taglist) : + HB_GSUB_Query_Features (_gsub, curScript, curLang, &taglist); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + required ? HB_GPOS_Query_Features (_gpos, curScript, curLangReq, + &taglist) : + HB_GPOS_Query_Features (_gpos, curScript, curLang, &taglist); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + return ret; +} + +void +myotf::set_features (QStringList ls) +{ + curFeatures = ls; +} + +void dump_pos(HB_PositionRec p) +{ + qDebug(QString("xpos = %1 | ypos = %2 | xadv = %3 | yadv = %4 | %5 | back = %6 ").arg(p.x_pos).arg(p.y_pos).arg(p.x_advance).arg(p.y_advance).arg(p.new_advance ? "NEW" : "NOT_NEW").arg(p.back)); +} + +posglyph myotf::get_position (int g) +{ + posglyph + ret; + if (g > _buffer->in_length) + return ret; + + dump_pos(_buffer->positions[g]); + if (_buffer->positions[g].new_advance) + { + ret.Xadvance = (double) _buffer->positions[g].x_advance; + ret.Yadvance = (double) _buffer->positions[g].y_advance; + } + else + { + FT_GlyphSlot + slot = _face->glyph; + if (!FT_Load_Glyph + (_face, _buffer->in_string[g].gindex, FT_LOAD_NO_SCALE)) + { + ret.Xadvance = + (double) (_buffer->positions[g].x_advance + slot->advance.x); + ret.Yadvance = + (double) (_buffer->positions[g].y_advance + slot->advance.y); + } + + } + + + return ret; +} Index: scribus/fonts/myotf.h =================================================================== RCS file: scribus/fonts/myotf.h diff -N scribus/fonts/myotf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.h 7 Apr 2007 10:03:38 -0000 @@ -0,0 +1,110 @@ +// myotf.h + +#ifndef WRAPLIBOTF +#define WRAPLIBOTF + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TABLES_H + +extern "C" +{ +// #include <otf.h> +// #include <stdlib.h> +#include "harfbuzz.h" +} + +#include <iostream> +#include <iomanip> + +#include <qstring.h> +#include <qstringlist.h> + +using namespace std; + +struct posglyph +{ + double Xposition; + double Yposition; + double Xadvance; + double Yadvance; + double xadvance(){return Xadvance;} + double yadvance(){return Yadvance;} + double xposition(){return Xposition;} + double yposition(){return Yposition;} +}; + +class myotf +{ + QString nom; + + //OTF *my; + FT_Library _ftlib; + FT_Face _face; + HB_FontRec hbFont; + QByteArray _memgdef,_memgsub,_memgpos; + HB_StreamRec* gdefstream; + HB_StreamRec* gsubstream; + HB_StreamRec* gposstream; + HB_GDEF _gdef; + HB_GSUB _gsub; + HB_GPOS _gpos; + + //OTF_GlyphString mys; + HB_Buffer _buffer; + + + bool subAlt; + bool glyphAlloc; + + int head, name, cmap, GDEF, GSUB, GPOS; + +public: +// OTF_GlyphString * otfString() {return &mys;} +// int unicode(int gid){ return OTF_get_unicode(my, gid);} + int get_glyph( int index);//{return _buffer->out_string[index].gindex;} + QString curTable; + HB_UShort curScript, curLang, curLangReq; + QString curScriptName, curLangName; + QStringList curFeatures; + myotf (QString n); + ~myotf (); +/* + * These members functions apply features currently set + */ + int procstring (QString ); + int procstring (); + int procstring (QString s, QString script, QString lang, QStringList gsub, QStringList gpos); +/* + * These functions give access to informations contained in the fontfile + */ + QStringList get_tables (); + QStringList get_scripts (); + QStringList get_langs (); + QStringList get_features (bool required=false); +/* + * These allow to set up the features ( Tab -> Scr -> Lan -> Fea ) + */ + void set_table (QString); + void set_script (QString); + void set_lang (QString); + void set_features (QStringList); + void set_subalt (bool); +/* + * I can't remember what this so important method is expected to achieve ! + */ + int get_position_type (int); + /* + * for the moment, it just does nothing. Because I have no idea + * of which sruct can be the target of this function.Nevertheless + * I'm clearly aware that's the key function, it's the reason why + * i put this apart from procstring(). + * The argument is the number of the glyph + */ + + posglyph get_position(int); + int get_glyph_used(); + +}; + +#endif Index: scribus/fonts/scface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/scface.h,v retrieving revision 1.1.2.11 diff -u -8 -p -r1.1.2.11 scface.h --- scribus/fonts/scface.h 25 Mar 2007 22:34:32 -0000 1.1.2.11 +++ scribus/fonts/scface.h 7 Apr 2007 10:03:39 -0000 @@ -16,16 +16,19 @@ virtual: dispatch to constituents, #include <qstring.h> //#include <qvector.h> #include <qmap.h> //#include <qarray.h> #include <utility> #include "fpointarray.h" +//TEST libotf + +#include "myotf.h" struct GlyphMetrics { double width; double ascent; double descent; }; @@ -109,16 +112,21 @@ public: bool usable; bool embedPs; bool subset; bool isStroked; bool isFixedPitch; bool hasNames; uint maxGlyph; + mutable double m_uniEM; + protected : + mutable myotf * _otf; + public: + myotf * otf() const { return _otf;} ScFaceData(); virtual ~ScFaceData() { }; protected: friend class ScFace; Status cachedStatus; @@ -145,16 +153,17 @@ public: m_cMap.clear(); status = ScFace::UNKNOWN; } virtual void loadGlyph(uint /*gl*/) const {} // dummy implementations + virtual double uniEM() const {return m_uniEM;} virtual double ascent(double sz) const { return sz; } virtual QString ascentAsString() const { return "0" ; } virtual QString descentAsString() const { return "0"; } virtual QString capHeightAsString() const { return "0"; } virtual QString FontBBoxAsString() const { return "0 0 0 0"; } virtual QString ItalicAngleAsString() const { return "0"; } virtual double descent(double /*sz*/) const { return 0.0; } virtual double xHeight(double sz) const { return sz; } @@ -166,16 +175,19 @@ public: 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<uint, std::pair<QChar, QString> >& gList) const; + + virtual QString otfied(QString s) const {return s;} + // 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; }; @@ -293,16 +305,17 @@ public: /// 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 unitsEM () const {return m->uniEM();} double ascent(double sz=1.0) const { return m->ascent(sz); } QString ascentAsString() const { return m->ascentAsString() ; } QString descentAsString() const { return m->descentAsString() ; } QString capHeightAsString() const { return m->capHeightAsString() ; } QString FontBBoxAsString() const { return m->FontBBoxAsString() ; } QString ItalicAngleAsString() const { return m->ItalicAngleAsString() ; } double descent(double sz=1.0) const { return m->descent(sz); } double xHeight(double sz=1.0) const { return m->xHeight(sz); } @@ -359,16 +372,19 @@ public: 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; } + //TEST libotf + QString otfied (QString s) const { return m->otfied(s); } + myotf * otf() const { return m->otf();} private: friend class SCFonts; ScFace(ScFaceData* md); ScFaceData* m; QString replacedName; QString replacedInDoc; |
|
harfbuzz-patch-1.diff GPOS features are now applied correctly. |
2007-04-07 19:00
|
harfbuzz-patch-2.diff (42,860 bytes)
? scribus/fonts/OLD-myotf.cpp ? scribus/fonts/OLD-myotf.h Index: scribus/pageitem.cpp =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.cpp,v retrieving revision 1.121.2.419 diff -u -8 -p -r1.121.2.419 pageitem.cpp --- scribus/pageitem.cpp 25 Mar 2007 22:34:31 -0000 1.121.2.419 +++ scribus/pageitem.cpp 7 Apr 2007 18:59:37 -0000 @@ -1747,16 +1747,179 @@ double PageItem::layoutGlyphs(const Char layout.yadvance = layout.more->yadvance; } else { layout.shrink(); } return retval; } +// the same, but character to render is retrieved from contextStringPointer +double PageItem::layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout) +{ + QString chars; + bool otf = style.font().isOTF(); + if(contextString[0] == 0) // We have a special char that can't be processed by libotf + { + chars = contextString[1].unicode(); + } + else if(otf) + { + + if (contextStringPointer == 0) + { + contextGlyphsString = style.font().otfied(contextString); + //Now, we have 4 possibilities : + // 1/ one glyph for one character ; + // 2/ many glyphs for one character ; + // 3/ one glyph for many characters ; + // 4/ nothing if character was rendered in a previous case 3 call. + // Too much complicated for me, I take the shorter way. + int ls = contextString.length(); + int lg = contextGlyphsString.length(); + contexLengthChange = lg - ls; + } + if (contexLengthChange < 0) // source string is longer then the rendered string + { + contexLengthChange += 1; // waiting + contextStringPointer = -1; + layout.glyph = ScFace::CONTROL_GLYPHS + SpecialChars::ZWSPACE.unicode(); + return 0.0; + } + else if (contexLengthChange > 0) // in that case we just trust the GLyphLayout grow() + { + chars = contextGlyphsString.mid(contextStringPointer,contexLengthChange + len); + contexLengthChange = 0; + } + else if(contexLengthChange == 0) + { + if(contextStringPointer == -1) contextStringPointer = 0; + chars = contextGlyphsString.mid(contextStringPointer,len); + } + //contextStringPointer += 1; + } + else + { + chars = contextString.mid(contextStringPointer,len); + } + qDebug(QString("char is [%1], contextGlyphsString is [%2], contextStringPointer[%3], len [%4]").arg(chars[0].unicode()).arg(contextGlyphsString).arg(contextStringPointer).arg(len)); + double retval = 0.0; + double asce = style.font().ascent(style.fontSize() / 10.0); + int chst = style.effects() & 1919; + if (chars[0] == SpecialChars::ZWSPACE || + chars[0] == SpecialChars::ZWNBSPACE || + chars[0] == SpecialChars::NBSPACE || + chars[0] == SpecialChars::NBHYPHEN || + chars[0] == SpecialChars::SHYPHEN || + chars[0] == SpecialChars::PARSEP || + chars[0] == SpecialChars::COLBREAK || + chars[0] == SpecialChars::LINEBREAK || + chars[0] == SpecialChars::FRAMEBREAK || + chars[0] == SpecialChars::TAB) + { + layout.glyph = ScFace::CONTROL_GLYPHS + chars[0].unicode(); + } + else + { + layout.glyph = style.font().char2CMap(chars[0].unicode()); //otf comment : here we assume that the proper pair is in the c_Map cache + } + + double tracking = 0.0; + if ( (style.effects() & ScStyle_StartOfLine) == 0) + tracking = style.fontSize() * style.tracking() / 10000.0; + + layout.xoffset = tracking; + layout.yoffset = 0; + if (chst != ScStyle_Default) + { + if (chst & ScStyle_Superscript) + { + retval -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.yoffset -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSuperScript / 100.0, 10.0 / style.fontSize()); + } + else if (chst & ScStyle_Subscript) + { + retval += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.yoffset += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSubScript / 100.0, 10.0 / style.fontSize()); + } + else { + layout.scaleV = layout.scaleH = 1.0; + } + layout.scaleH *= style.scaleH() / 1000.0; + layout.scaleV *= style.scaleV() / 1000.0; + if (chst & ScStyle_AllCaps) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + } + if (chst & ScStyle_SmallCaps) + { + + double smallcapsScale = m_Doc->typographicSettings.valueSmallCaps / 100.0; + QChar uc = chars[0].upper(); + if (uc != chars[0]) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + layout.scaleV *= smallcapsScale; + layout.scaleH *= smallcapsScale; + } + } + } + else { + layout.scaleH = style.scaleH() / 1000.0; + layout.scaleV = style.scaleV() / 1000.0; + } + + if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) { + uint replGlyph = style.font().char2CMap(QChar(' ')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode())) { + uint replGlyph = style.font().char2CMap(QChar('-')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph >= ScFace::CONTROL_GLYPHS) { + layout.xadvance = 0; + layout.yadvance = 0; + } + else { + layout.xadvance = style.font().glyphWidth(layout.glyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(layout.glyph, style.fontSize() / 10).ascent * layout.scaleV; + } + if(otf)//Don't wait for ::layout to adjust with pair kerning + { + posglyph pg = style.font().otf()->get_position(contextStringPointer); + qDebug(QString("Adjust[%1] pg.xadv=%2 , pg.yadv=%3").arg(layout.glyph).arg(pg.xadvance()).arg(pg.yadvance())); + layout.xadvance = pg.xadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleH; + layout.yadvance = pg.yadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleV; + + + } + if (layout.xadvance > 0) + layout.xadvance += tracking; + + if (chars.length() > 1) { + layout.grow(); + contextStringPointer += 1; + layoutGlyphs(style, chars.length()-1, *layout.more); + layout.xadvance += style.font().glyphKerning(layout.glyph, layout.more->glyph, style.fontSize() / 10) * layout.scaleH; + if (layout.more->yadvance > layout.yadvance) + layout.yadvance = layout.more->yadvance; + } + else { + contextStringPointer += 1; + layout.shrink(); + } + + return retval; +} + void PageItem::drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs) { uint glyph = glyphs.glyph; if ((m_Doc->guidesSettings.showControls) && (glyph == style.font().char2CMap(QChar(' ')) || glyph >= ScFace::CONTROL_GLYPHS)) { bool stroke = false; if (glyph >= ScFace::CONTROL_GLYPHS) Index: scribus/pageitem.h =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.h,v retrieving revision 1.26.2.183 diff -u -8 -p -r1.26.2.183 pageitem.h --- scribus/pageitem.h 4 Apr 2007 21:46:32 -0000 1.26.2.183 +++ scribus/pageitem.h 7 Apr 2007 18:59:40 -0000 @@ -289,16 +289,17 @@ public: /// returns the style at the current charpos const ParagraphStyle& currentStyle() const; /// returns the style at the current charpos ParagraphStyle& changeCurrentStyle(); /// returns the style at the current charpos const CharStyle& currentCharStyle() const; // deprecated: double layoutGlyphs(const CharStyle& style, const QString chars, GlyphLayout& layout); + double layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout); void SetFarbe(QColor *tmp, QString farbe, int shad); void drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs ); void DrawPolyL(QPainter *p, QPointArray pts); QString ExpandToken(uint base); bool AutoName; double gXpos; double gYpos; @@ -1208,16 +1209,22 @@ public: /** Darstellungsart Bild/Titel */ bool PicArt; /** Line width */ double m_lineWidth; double Oldm_lineWidth; + /** Context String */ + QString contextString; + QString contextGlyphsString; + int contextStringPointer; + int contexLengthChange; + signals: //Frame signals void myself(PageItem *); void frameType(int); // not related to Frametype but to m_itemIype :-/ void position(double, double); //X,Y void widthAndHeight(double, double); //W,H void rotation(double); //Degrees rotation void colors(QString, QString, int, int); //lineColor, fillColor, lineShade, fillShade Index: scribus/pageitem_textframe.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/pageitem_textframe.cpp,v retrieving revision 1.1.2.159 diff -u -8 -p -r1.1.2.159 pageitem_textframe.cpp --- scribus/pageitem_textframe.cpp 5 Apr 2007 16:27:20 -0000 1.1.2.159 +++ scribus/pageitem_textframe.cpp 7 Apr 2007 18:59:46 -0000 @@ -565,19 +565,16 @@ static double opticalRightMargin(const S rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); } return rightCorr; } return 0.0; } - - - void PageItem_TextFrame::layout() { if (BackBox != NULL && BackBox->invalid) { // qDebug("textframe: len=%d, going back", itemText.length()); invalid = false; PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); if (!prevInChain) @@ -699,19 +696,71 @@ void PageItem_TextFrame::layout() else // empty itemText: { desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; } current.startLine(firstInFrame()); outs = false; OFs = 0; - MaxChars = 0; + MaxChars = 0; + // BIGLOOP + int contextrest = 0; + int sccontrol; for (int a = firstInFrame(); a < itemText.length(); ++a) { + // here we set the context string + if(contextrest == 0) + { + contextString = ""; + sccontrol = 0; + for(int ctsg = a; ctsg < itemText.length(); ++ctsg) + { + + QString contmp = ExpandToken(ctsg); + if(current.breakIndex == a) + { + break; + } + else if(contmp[0] == SpecialChars::ZWSPACE || + contmp[0] == SpecialChars::ZWNBSPACE || + contmp[0] == SpecialChars::NBSPACE || + contmp[0] == SpecialChars::NBHYPHEN || + contmp[0] == SpecialChars::SHYPHEN || + contmp[0] == SpecialChars::PARSEP || + contmp[0] == SpecialChars::COLBREAK || + contmp[0] == SpecialChars::LINEBREAK || + contmp[0] == SpecialChars::FRAMEBREAK || + contmp[0] == SpecialChars::TAB || + contmp[0] == SpecialChars::BLANK) + { + if(sccontrol > 0) + { + break; + } + else + { + contextString += QChar(0) ; + contextString += contmp[0].unicode(); + break; + } + } + else + { + sccontrol += 1; + contextString += contmp; + } + } + contextrest = (sccontrol == 0 ? 1 : contextString.length());// we send special char one by one + contextStringPointer = 0; + qDebug(QString("contextrest = %1 and context string is \"%2\"").arg(contextrest).arg(contextString)); + } + --contextrest; + + hl = itemText.item(a); if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) style = itemText.paragraphStyle(a); if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); // qDebug(QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); const CharStyle& charStyle = itemText.charStyle(a); @@ -862,30 +911,35 @@ void PageItem_TextFrame::layout() kernVal = 0; } else { kernVal = 0; // chs * charStyle.tracking() / 10000.0; itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); } hl->glyph.yadvance = 0; - oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); + //qDebug(QString("sending [%1] to layoutGlyphs()").arg(chstr)); + oldCurY = layoutGlyphs(*hl, chstr.length(), hl->glyph); + //oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); // find out width of char if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); else { wide = hl->glyph.wide(); // apply kerning if (a+1 < itemText.length()) { - uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); - double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; - wide += kern; - hl->glyph.xadvance += kern; + if( !charStyle.font().isOTF() ) + { + uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); + double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; + wide += kern; + hl->glyph.xadvance += kern; + } } } if (DropCmode) { // drop caps are wider... if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1352,16 +1406,17 @@ void PageItem_TextFrame::layout() tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); cm = QRegion(pf2.xForm(tcli)); cl = cl.subtract(cm); // current.yPos = maxDY; } // end of line if ( SpecialChars::isBreak(hl->ch[0], Cols > 1) || (outs)) { + contextrest = 0; tabs.active = false; tabs.status = TabNONE; if (SpecialChars::isBreak(hl->ch[0], Cols > 1)) { // find end of line current.breakLine(itemText, a); EndX = current.endOfLine(cl, pf2, asce, desc, style.rightMargin()); current.finishLine(EndX); Index: scribus/scribusdoc.cpp =================================================================== RCS file: /cvs/Scribus/scribus/scribusdoc.cpp,v retrieving revision 1.25.2.448 diff -u -8 -p -r1.25.2.448 scribusdoc.cpp --- scribus/scribusdoc.cpp 4 Apr 2007 21:08:56 -0000 1.25.2.448 +++ scribus/scribusdoc.cpp 7 Apr 2007 19:00:01 -0000 @@ -2765,22 +2765,28 @@ void ScribusDoc::checkItemForFonts(PageI newText=getSectionPageNumberForPageIndex(a); for (uint nti=0;nti<newText.length();++nti) if (pageNumberText.find(newText[nti])==-1) pageNumberText+=newText[nti]; } } } //Now scan and add any glyphs used in page numbers + if(it->itemText.charStyle(e).font().isOTF()) + pageNumberText = it->itemText.charStyle(e).font().otfied(pageNumberText); for (uint pnti=0;pnti<pageNumberText.length(); ++pnti) { uint chr = pageNumberText[pnti].unicode(); if (it->itemText.charStyle(e).font().canRender(chr)) { - uint gl = it->itemText.charStyle(e).font().char2CMap(pageNumberText[pnti]); + uint gl; + if(it->itemText.charStyle(e).font().isOTF()) + gl = pageNumberText[pnti].unicode() ; + else + gl = it->itemText.charStyle(e).font().char2CMap(pageNumberText[pnti]); FPointArray gly(it->itemText.charStyle(e).font().glyphOutline(gl)); Really[it->itemText.charStyle(e).font().replacementName()].insert(gl, gly); } } continue; } if (it->itemText.charStyle(e).effects() & ScStyle_SmartHyphenVisible) { @@ -2792,17 +2798,18 @@ void ScribusDoc::checkItemForFonts(PageI { chstr = it->itemText.text(e, 1); if (chstr.upper() != it->itemText.text(e, 1)) chstr = chstr.upper(); chr = chstr[0].unicode(); } if (it->itemText.charStyle(e).font().canRender(chr)) { - uint gl = it->itemText.charStyle(e).font().char2CMap(chr); + //uint gl = it->itemText.charStyle(e).font().char2CMap(chr); + uint gl = it->itemText.item(e)->glyph.glyph; gly = it->itemText.charStyle(e).font().glyphOutline(gl); Really[it->itemText.charStyle(e).font().replacementName()].insert(gl, gly); } } } } void ScribusDoc::getUsedProfiles(ProfilesL& usedProfiles) Index: scribus/fonts/CMakeLists.txt =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/CMakeLists.txt,v retrieving revision 1.1.2.1 diff -u -8 -p -r1.1.2.1 CMakeLists.txt --- scribus/fonts/CMakeLists.txt 23 Jul 2006 12:07:47 -0000 1.1.2.1 +++ scribus/fonts/CMakeLists.txt 7 Apr 2007 19:00:04 -0000 @@ -5,12 +5,15 @@ ${CMAKE_SOURCE_DIR}/scribus SET(SCRIBUS_FONTS_LIB_SOURCES scface.cpp ftface.cpp scface_ps.cpp scface_ttf.cpp scfontmetrics.cpp +myotf.cpp ) + + SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.9 diff -u -8 -p -r1.1.2.9 ftface.cpp --- scribus/fonts/ftface.cpp 11 Jan 2007 15:29:46 -0000 1.1.2.9 +++ scribus/fonts/ftface.cpp 7 Apr 2007 19:00:05 -0000 @@ -2,16 +2,19 @@ #include "fonts/ftface.h" #include FT_OUTLINE_H #include FT_GLYPH_H #include <qobject.h> #include <qfile.h> +#include <qmessagebox.h> +#include <qinputdialog.h> + #include "scfonts.h" #include "fonts/scfontmetrics.h" // static: FT_Library FtFace::library = NULL; /***** ScFace lifecycle: unchecked -> loaded -> glyphs checked @@ -136,36 +139,116 @@ void FtFace::load() const ++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; } + //TEST libotf + if(typeCode == ScFace::OTF) + { + _otf = new myotf(QFile::encodeName(fontFile)); + bool ok; + QMessageBox::information( 0, "Scribus", + QString("You choose to use an OpenType Font file \"%1\".\n You have to set parameters for this font.").arg(scName) ); + + _otf->get_tables().contains("GSUB") ? _otf->set_table("GSUB") : _otf->set_table("GPOS"); + QStringList choice = _otf->get_scripts(); + if(choice.count() > 1) + { + otfScript = QInputDialog::getItem("Scribus :: otf", "Select the script ", choice, 0, FALSE, &ok ); + _otf->set_script(otfScript); + } + else + { + otfScript = choice[0]; + _otf->set_script(otfScript); + } + choice = _otf->get_langs(); + choice.append("dflt"); + if(choice.count() > 1) + { + otfLang = QInputDialog::getItem("Scribus :: otf", QString("Select the language for script %1").arg(otfScript), choice, 0, FALSE, &ok ); + _otf->set_lang(otfLang); + } + else + { + otfLang = choice[0]; + _otf->set_lang(otfLang); + } + if(_otf->get_tables().contains("GSUB")) + { + _otf->set_table("GSUB"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + choice =_otf->get_features(); + QString ft; + ok = TRUE; + // while(QMessageBox::question(0,"Scribus","Want to choose features for GSUB ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + while(ok && !choice.isEmpty()) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select GSUB feature for lang %1").arg(otfLang), choice, 0, FALSE, &ok ); + if(ok) + { + otfSubFeatures.append(ft); + choice.remove(ft); + } + } + } + if(_otf->get_tables().contains("GPOS")) + { + _otf->set_table("GPOS"); + _otf->set_script(otfScript); + _otf->set_lang(otfLang); + choice =_otf->get_features(); + QString ft; + ok = TRUE; + // while(QMessageBox::question(0,"Scribus","Want to choose features for GPOS ?",QMessageBox::Ok,QMessageBox::No,QMessageBox::NoButton) == QMessageBox::Ok) + while(ok && !choice.isEmpty()) + { + ft = QInputDialog::getItem("Scribus :: otf", QString("Select GPOS feature for lang %1").arg(otfLang), choice, 0, FALSE, &ok ); + if(ok) + { + otfPosFeatures.append(ft); + choice.remove(ft); + } + } + } + qDebug("otf filled"); + } } void FtFace::unload() const { if (m_face) { FT_Done_Face( m_face ); m_face = NULL; } // clear caches + if(_otf) delete _otf; 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; + if(m_cMap.contains(ch.unicode())) + { + return m_cMap[ch.unicode()]; + } + else + { + FT_Face face = ftFace(); + uint gl = FT_Get_Char_Index(face, ch.unicode()); + m_cMap.insert(ch.unicode(), gl); + return gl; + } } void FtFace::loadGlyph(uint gl) const { if (m_glyphWidth.contains(gl)) return; @@ -307,9 +390,34 @@ void FtFace::RawData(QByteArray & bb) co // 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())); } */ } +QString FtFace::otfied(QString s) const +{ + qDebug("otfied"); + if(status != ScFace::LOADED) + { + qDebug("Face is not loaded"); + } + else if(typeCode == ScFace::OTF) + { + int nbg = _otf->procstring(s,otfScript,otfLang,otfSubFeatures,otfPosFeatures); + // Actually, newstring should be a QValueList<uint> as it's a glyphstring + QString newstring; + for (int i = 0; i < nbg ; ++i) + { + int gi= _otf->get_glyph(i); + newstring += QChar(gi); + m_cMap.insert(gi,gi); + } + + + qDebug(QString("oldstring is \"%1\" and new string is \"%2\"").arg(s).arg(newstring)); + return newstring; + } + return s; +} Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -8 -p -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 7 Apr 2007 19:00:05 -0000 @@ -96,22 +96,31 @@ protected: mutable QString Descender; mutable QString ItalicAngle; mutable QString StdVW; QString FontEnc; mutable QString FontBBox; mutable int m_encoding; - mutable double m_uniEM; +// mutable double m_uniEM; mutable double m_ascent; mutable double m_descent; mutable double m_height; mutable double m_xHeight; mutable double m_capHeight; mutable double m_maxAdvanceWidth; mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + //TEST libotf + public: + mutable QStringList otfSubFeatures; + mutable QStringList otfPosFeatures; + mutable QString otfScript; + mutable QString otfLang; + QString otfied(QString s) const ; + + }; #endif Index: scribus/fonts/myotf.cpp =================================================================== RCS file: scribus/fonts/myotf.cpp diff -N scribus/fonts/myotf.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.cpp 7 Apr 2007 19:00:06 -0000 @@ -0,0 +1,515 @@ +/* un test de libotf mer18jan qui se transforme en test de harfbuzz mer4avr*/ + + +#include "myotf.h" + +///Required by this great lib that do not provide all symbols +#include <harfbuzz-external.h> +//#include <Qt/private/qunicodetables_p.h> + +HB_LineBreakClass HB_GetLineBreakClass(HB_UChar32 ch) +{ +// #if QT_VERSION >= 0x040300 +// return (HB_LineBreakClass)QUnicodeTables::lineBreakClass(ch); +// #else +// #error "This test currently requires Qt >= 4.3" +// #endif + return (HB_LineBreakClass) 0; +} + +void HB_GetUnicodeCharProperties(HB_UChar32 ch, HB_CharCategory *category, int *combiningClass) +{ + *category = (HB_CharCategory)QChar::Category(ch); + *combiningClass = QChar::CombiningClass(ch); +} + +HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch) +{ + return (HB_CharCategory)QChar::Category(ch); +} + +int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch) +{ + return QChar::CombiningClass(ch); +} + +HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) +{ + return QChar(ch).mirroredChar(); +} +/// + +QString +OTF_tag_name (HB_UInt tag) +{ + QString name; + name[0] = (char) (tag >> 24); + name[1] = (char) ((tag >> 16) & 0xFF); + name[2] = (char) ((tag >> 8) & 0xFF); + name[3] = (char) (tag & 0xFF); +// qDebug(QString("OTF_tag_name (%1) -> %2").arg(tag).arg(name)); + return name; +} + +HB_UInt +OTF_name_tag (QString s) +{ + QChar sometimestagnameisthreecharslong = + s.length () > 3 ? s[3].unicode () : ' '; + HB_UInt ret = FT_MAKE_TAG (s[0].unicode (), s[1].unicode (), s[2].unicode (), + sometimestagnameisthreecharslong.unicode ()); +// qDebug(QString("OTF_name_tag (%1) -> %2").arg(s).arg(ret)); + return ret; +} + +//#define DFLT 0xFFFF + +void +myotf::set_subalt (bool b) +{ + subAlt = b; +} + +int myotf::get_glyph( int index) +{ + return _buffer->in_string[index].gindex; +} +int +myotf::get_glyph_used () +{ + // return mys.used; + return _buffer->in_length; +} + +myotf::myotf (QString n) +{ + nom = n; + if (FT_Init_FreeType (&_ftlib)) + qDebug ("oh merde"); + if (FT_New_Face (_ftlib, nom, 0, &_face)) + qDebug ("oh putaing"); + + hbFont.klass = NULL; /* Hope it will work without more code */ + hbFont.userData = 0; + hbFont.faceData = _face; + hbFont.x_ppem = _face->size->metrics.x_ppem; + hbFont.y_ppem = _face->size->metrics.y_ppem; + hbFont.x_scale = 0x10000;//_face->size->metrics.x_scale; + hbFont.y_scale = 0x10000;//_face->size->metrics.y_scale; + + subAlt = false; + glyphAlloc = false; + FT_ULong length = 0; + + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, NULL, &length)) + { + qDebug(QString("length of GDEF table is %1").arg(length)); + if(length > 0) + { + _memgdef.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, + (FT_Byte *) _memgdef.data (), &length); + gdefstream = new (HB_StreamRec); + gdefstream->base = (HB_Byte *) _memgdef.data (); + gdefstream->size = _memgdef.size (); + gdefstream->pos = 0; + + + HB_New_GDEF_Table (&_gdef); + if (!HB_Load_GDEF_Table (gdefstream, &_gdef)) + GDEF = 1; + else + GDEF = 0; + } + + else + GDEF = 0; + } + else + GDEF = 0; + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, NULL, &length)) + { + qDebug(QString("length of GSUB table is %1").arg(length)); + if(length > 32)//Some font files seem to have a fake table that is just 32 words long and make harbuzz confused + { + _memgsub.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, + (FT_Byte *) _memgsub.data (), &length); + gsubstream = new (HB_StreamRec); + gsubstream->base = (HB_Byte *) _memgsub.data (); + gsubstream->size = _memgsub.size (); + gsubstream->pos = 0; + + if (GDEF ? !HB_Load_GSUB_Table (gsubstream, &_gsub, _gdef, gdefstream) : + !HB_Load_GSUB_Table (gsubstream, &_gsub, NULL, NULL)) + GSUB = 1; + else + GSUB = 0; + } + else + GSUB = 0; + } + else + GSUB = 0; + // What are thes f... properties ? +// if(GSUB) +// { +// for(int i = 0; i < _gsub->LookupList.LookupCount ; i++) +// qDebug(QString("property[%1] = %2").arg(i).arg(_gsub->LookupList.Properties[i])); +// } + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, NULL, &length)) + { + qDebug(QString("length of GPOS table is %1").arg(length)); + if(length > 32) + { + _memgpos.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, + (FT_Byte *) _memgpos.data (), &length); + gposstream = new (HB_StreamRec); + gposstream->base = (HB_Byte *) _memgpos.data (); + gposstream->size = _memgpos.size (); + gposstream->pos = 0; + + if (GDEF ? !HB_Load_GPOS_Table (gposstream, &_gpos, _gdef, gdefstream) : + !HB_Load_GPOS_Table (gposstream, &_gpos, NULL, NULL)) + GPOS = 1; + else + GPOS = 0; + } + else + GPOS = 0; + } + else + GPOS = 0; + if (hb_buffer_new (&_buffer)) + qDebug ("unable to get _buffer"); +} + +myotf::~myotf () +{ + + if (_buffer) + hb_buffer_free (_buffer); + if (GDEF) + HB_Done_GDEF_Table (_gdef); + if (GSUB) + HB_Done_GSUB_Table (_gsub); + if (GPOS) + HB_Done_GPOS_Table (_gpos); + if (_face) + FT_Done_Face (_face); + if (_ftlib) + FT_Done_FreeType (_ftlib); +} + + +/// the actual function +int +myotf::procstring (QString s, QString script, QString lang, QStringList gsub, + QStringList gpos) +{ + qDebug (QString("procstring(%1, %2, %3, ...)").arg(s).arg(script).arg(lang)); + hb_buffer_clear( _buffer ); + int n = s.length (); + HB_Error error; + for (int i = 0; i < n; i++) + { + + error = hb_buffer_add_glyph (_buffer, + FT_Get_Char_Index (_face, s[i].unicode()), + 0, + 0); + qDebug(QString("adding glyph [%1] gives glyph [%2] properties [%3] cluster [%4]").arg(FT_Get_Char_Index (_face, s[i].unicode())).arg(_buffer->in_string[i].gindex).arg(_buffer->in_string[i].properties).arg(_buffer->in_string[i].cluster)); + + } + + qDebug(QString("in_string is %1 long").arg(_buffer->in_length)); + + if (gsub.count ()) + { + HB_GSUB_Clear_Features (_gsub); + set_table ("GSUB"); + set_script (script); + set_lang (lang); + + for (QStringList::iterator ife = gsub.begin (); ife != gsub.end (); + ife++) + { + HB_UShort fidx; + error = HB_GSUB_Select_Feature (_gsub, + OTF_name_tag (*ife), + curScript, curLang, &fidx); + if(!error) + { + HB_GSUB_Add_Feature (_gsub, fidx, 1); + qDebug(QString("GSUB [%2] feature.lookupcount = %1").arg(_gsub->FeatureList.FeatureRecord[fidx].Feature.LookupListCount).arg(*ife)); + } + else + qDebug(QString("adding gsub feature [%1] failed : %2").arg(*ife).arg(error)); + } + + error = HB_GSUB_Apply_String (_gsub, _buffer); + if(error)qDebug(QString("applying gsub features to string \"%1\" returned %2").arg(s).arg(error)); + + } + if (gpos.count ()) + { + HB_GPOS_Clear_Features (_gpos); + set_table ("GPOS"); + set_script (script); + set_lang (lang); + + for (QStringList::iterator ife = gpos.begin (); ife != gpos.end (); + ife++) + { + HB_UShort fidx; + error = HB_GPOS_Select_Feature (_gpos, + OTF_name_tag (*ife), + curScript, curLang, &fidx); + if(!error) + { + HB_GPOS_Add_Feature (_gpos, fidx, 1); + qDebug(QString("GPOS [%2] feature.lookupcount = %1").arg(_gpos->FeatureList.FeatureRecord[fidx].Feature.LookupListCount).arg(*ife)); + } + else + qDebug(QString("adding gsub feature [%1] failed : %2").arg(*ife).arg(error)); + } + if(_buffer->in_length > 0) memset(_buffer->positions, 0, _buffer->in_length*sizeof(HB_PositionRec)); + error = HB_GPOS_Apply_String (&hbFont, _gpos, FT_LOAD_NO_SCALE, _buffer, + /*while dvi is true font klass is not used */ true, + /*r2l */ true); + if(error)qDebug(QString("applying gpos features to string \"%1\" returned %2").arg(s).arg(error)); + + } + + + return _buffer->in_length; +} + + + + + + +QStringList +myotf::get_tables () +{ + QStringList ret; + + // if (GDEF) + // ret.insert (ret.end (), "GDEF"); + if (GPOS) + ret.insert (ret.end (), "GPOS"); + if (GSUB) + ret.insert (ret.end (), "GSUB"); + + return ret; +} + +void +myotf::set_table (QString s) +{ + curTable = s; +} + +QStringList +myotf::get_scripts () +{ + qDebug("myotf::get_scripts ()"); + QStringList ret; + + if (curTable == "GSUB") + { + HB_UInt *taglist; + if (HB_GSUB_Query_Scripts (_gsub, &taglist)) + qDebug ("error HB_GSUB_Query_Scripts"); + while (*taglist) + { + qDebug(QString("script [%1]").arg(OTF_tag_name (*taglist))); + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + if (HB_GPOS_Query_Scripts (_gpos, &taglist)) + qDebug ("error HB_GPOS_Query_Scripts"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + } + return ret; + +} + +void +myotf::set_script (QString s) +{ + + curScriptName = s; + if (curTable == "GSUB") + { + if (HB_GSUB_Select_Script + (_gsub, OTF_name_tag (curScriptName), &curScript)) + qDebug (QString("Unable to set script index for %1").arg( curScriptName)); + } + if (curTable == "GPOS") + { + if (HB_GPOS_Select_Script + (_gpos, OTF_name_tag (curScriptName), &curScript)) + qDebug ("Unable to set script index"); + } +} + + +QStringList +myotf::get_langs () +{ + QStringList ret; + + if (curTable == "GSUB") + { + + HB_UInt *taglist; + if (HB_GSUB_Query_Languages (_gsub, curScript, &taglist)) + qDebug ("error HB_GSUB_Query_Langs"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + if (HB_GPOS_Query_Languages (_gpos, curScript, &taglist)) + qDebug ("error HB_GPOS_Query_Langs"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + + return ret; +} + +void +myotf::set_lang (QString s) +{ + if (s == "default" || s == "dflt" || s.isEmpty ()) + { + curLangName = "dflt"; + curLang = HB_DEFAULT_LANGUAGE; + return; + } + + curLangName = s; + if (curTable == "GSUB") + { + if (!HB_GSUB_Select_Language (_gsub, + OTF_name_tag (curLangName), + curScript, + &curLang, + &curLangReq)) + qDebug ("Unable to set lang index"); + } + if (curTable == "GPOS") + { + if (!HB_GPOS_Select_Language + (_gpos, OTF_name_tag (curLangName),curScript, &curLang, &curLangReq)) + qDebug ("Unable to set lang index"); + } + +} + + +QStringList +myotf::get_features (bool required ) +{ + QStringList ret; + + if (curTable == "GSUB") + { + + HB_UInt *taglist; + required ? HB_GSUB_Query_Features (_gsub, curScript, curLangReq, + &taglist) : + HB_GSUB_Query_Features (_gsub, curScript, curLang, &taglist); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + required ? HB_GPOS_Query_Features (_gpos, curScript, curLangReq, + &taglist) : + HB_GPOS_Query_Features (_gpos, curScript, curLang, &taglist); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + return ret; +} + +void +myotf::set_features (QStringList ls) +{ + curFeatures = ls; +} + +void dump_pos(HB_PositionRec p) +{ + qDebug(QString("xpos = %1 | ypos = %2 | xadv = %3 | yadv = %4 | %5 | back = %6 ").arg(p.x_pos).arg(p.y_pos).arg(p.x_advance).arg(p.y_advance).arg(p.new_advance ? "NEW" : "NOT_NEW").arg(p.back)); +} + +posglyph myotf::get_position (int g) +{ + posglyph + ret; + if (g > _buffer->in_length) + return ret; + + dump_pos(_buffer->positions[g]); + if (_buffer->positions[g].new_advance) + { + ret.Xadvance = (double) _buffer->positions[g].x_advance; + ret.Yadvance = (double) _buffer->positions[g].y_advance; + } + else + { + FT_GlyphSlot + slot = _face->glyph; + if (!FT_Load_Glyph + (_face, _buffer->in_string[g].gindex, FT_LOAD_NO_SCALE)) + { + ret.Xadvance = + (double) (_buffer->positions[g].x_advance + slot->advance.x); + ret.Yadvance = + (double) (_buffer->positions[g].y_advance + slot->advance.y); + } + + } + + + return ret; +} Index: scribus/fonts/myotf.h =================================================================== RCS file: scribus/fonts/myotf.h diff -N scribus/fonts/myotf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.h 7 Apr 2007 19:00:06 -0000 @@ -0,0 +1,110 @@ +// myotf.h + +#ifndef WRAPLIBOTF +#define WRAPLIBOTF + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TABLES_H + +extern "C" +{ +// #include <otf.h> +// #include <stdlib.h> +#include "harfbuzz.h" +} + +#include <iostream> +#include <iomanip> + +#include <qstring.h> +#include <qstringlist.h> + +using namespace std; + +struct posglyph +{ + double Xposition; + double Yposition; + double Xadvance; + double Yadvance; + double xadvance(){return Xadvance;} + double yadvance(){return Yadvance;} + double xposition(){return Xposition;} + double yposition(){return Yposition;} +}; + +class myotf +{ + QString nom; + + //OTF *my; + FT_Library _ftlib; + FT_Face _face; + HB_FontRec hbFont; + QByteArray _memgdef,_memgsub,_memgpos; + HB_StreamRec* gdefstream; + HB_StreamRec* gsubstream; + HB_StreamRec* gposstream; + HB_GDEF _gdef; + HB_GSUB _gsub; + HB_GPOS _gpos; + + //OTF_GlyphString mys; + HB_Buffer _buffer; + + + bool subAlt; + bool glyphAlloc; + + int head, name, cmap, GDEF, GSUB, GPOS; + +public: +// OTF_GlyphString * otfString() {return &mys;} +// int unicode(int gid){ return OTF_get_unicode(my, gid);} + int get_glyph( int index);//{return _buffer->out_string[index].gindex;} + QString curTable; + HB_UShort curScript, curLang, curLangReq; + QString curScriptName, curLangName; + QStringList curFeatures; + myotf (QString n); + ~myotf (); +/* + * These members functions apply features currently set + */ + int procstring (QString ); + int procstring (); + int procstring (QString s, QString script, QString lang, QStringList gsub, QStringList gpos); +/* + * These functions give access to informations contained in the fontfile + */ + QStringList get_tables (); + QStringList get_scripts (); + QStringList get_langs (); + QStringList get_features (bool required=false); +/* + * These allow to set up the features ( Tab -> Scr -> Lan -> Fea ) + */ + void set_table (QString); + void set_script (QString); + void set_lang (QString); + void set_features (QStringList); + void set_subalt (bool); +/* + * I can't remember what this so important method is expected to achieve ! + */ + int get_position_type (int); + /* + * for the moment, it just does nothing. Because I have no idea + * of which sruct can be the target of this function.Nevertheless + * I'm clearly aware that's the key function, it's the reason why + * i put this apart from procstring(). + * The argument is the number of the glyph + */ + + posglyph get_position(int); + int get_glyph_used(); + +}; + +#endif Index: scribus/fonts/scface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/scface.h,v retrieving revision 1.1.2.11 diff -u -8 -p -r1.1.2.11 scface.h --- scribus/fonts/scface.h 25 Mar 2007 22:34:32 -0000 1.1.2.11 +++ scribus/fonts/scface.h 7 Apr 2007 19:00:07 -0000 @@ -16,16 +16,19 @@ virtual: dispatch to constituents, #include <qstring.h> //#include <qvector.h> #include <qmap.h> //#include <qarray.h> #include <utility> #include "fpointarray.h" +//TEST libotf + +#include "myotf.h" struct GlyphMetrics { double width; double ascent; double descent; }; @@ -109,16 +112,21 @@ public: bool usable; bool embedPs; bool subset; bool isStroked; bool isFixedPitch; bool hasNames; uint maxGlyph; + mutable double m_uniEM; + protected : + mutable myotf * _otf; + public: + myotf * otf() const { return _otf;} ScFaceData(); virtual ~ScFaceData() { }; protected: friend class ScFace; Status cachedStatus; @@ -145,16 +153,17 @@ public: m_cMap.clear(); status = ScFace::UNKNOWN; } virtual void loadGlyph(uint /*gl*/) const {} // dummy implementations + virtual double uniEM() const {return m_uniEM;} virtual double ascent(double sz) const { return sz; } virtual QString ascentAsString() const { return "0" ; } virtual QString descentAsString() const { return "0"; } virtual QString capHeightAsString() const { return "0"; } virtual QString FontBBoxAsString() const { return "0 0 0 0"; } virtual QString ItalicAngleAsString() const { return "0"; } virtual double descent(double /*sz*/) const { return 0.0; } virtual double xHeight(double sz) const { return sz; } @@ -166,16 +175,19 @@ public: 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<uint, std::pair<QChar, QString> >& gList) const; + + virtual QString otfied(QString s) const {return s;} + // 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; }; @@ -293,16 +305,17 @@ public: /// 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 unitsEM () const {return m->uniEM();} double ascent(double sz=1.0) const { return m->ascent(sz); } QString ascentAsString() const { return m->ascentAsString() ; } QString descentAsString() const { return m->descentAsString() ; } QString capHeightAsString() const { return m->capHeightAsString() ; } QString FontBBoxAsString() const { return m->FontBBoxAsString() ; } QString ItalicAngleAsString() const { return m->ItalicAngleAsString() ; } double descent(double sz=1.0) const { return m->descent(sz); } double xHeight(double sz=1.0) const { return m->xHeight(sz); } @@ -359,16 +372,19 @@ public: 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; } + //TEST libotf + QString otfied (QString s) const { return m->otfied(s); } + myotf * otf() const { return m->otf();} private: friend class SCFonts; ScFace(ScFaceData* md); ScFaceData* m; QString replacedName; QString replacedInDoc; |
|
harfbuzz-patch-2.diff export to pdf and print seems to work, even for pagenumbers ! |
2007-04-09 15:21
|
|
2007-04-09 15:40
|
harfbuzz-patch-3.diff (63,217 bytes)
Index: scribus/pageitem.cpp =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.cpp,v retrieving revision 1.121.2.419 diff -u -8 -p -r1.121.2.419 pageitem.cpp --- scribus/pageitem.cpp 25 Mar 2007 22:34:31 -0000 1.121.2.419 +++ scribus/pageitem.cpp 9 Apr 2007 15:38:25 -0000 @@ -1747,16 +1747,179 @@ double PageItem::layoutGlyphs(const Char layout.yadvance = layout.more->yadvance; } else { layout.shrink(); } return retval; } +// the same, but character to render is retrieved from contextStringPointer +double PageItem::layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout) +{ + QString chars; + bool otf = style.font().isOTF(); + if(contextString[0] == 0) // We have a special char that can't be processed by libotf + { + chars = contextString[1].unicode(); + } + else if(otf) + { + + if (contextStringPointer == 0) + { + contextGlyphsString = style.font().otfied(contextString, style.font().otfLang(style.language()),style.fontFeatures()); + //Now, we have 4 possibilities : + // 1/ one glyph for one character ; + // 2/ many glyphs for one character ; + // 3/ one glyph for many characters ; + // 4/ nothing if character was rendered in a previous case 3 call. + // Too much complicated for me, I take the shorter way. + int ls = contextString.length(); + int lg = contextGlyphsString.length(); + contexLengthChange = lg - ls; + } + if (contexLengthChange < 0) // source string is longer then the rendered string + { + contexLengthChange += 1; // waiting + contextStringPointer = -1; + layout.glyph = ScFace::CONTROL_GLYPHS + SpecialChars::ZWSPACE.unicode(); + return 0.0; + } + else if (contexLengthChange > 0) // in that case we just trust the GLyphLayout grow() + { + chars = contextGlyphsString.mid(contextStringPointer,contexLengthChange + len); + contexLengthChange = 0; + } + else if(contexLengthChange == 0) + { + if(contextStringPointer == -1) contextStringPointer = 0; + chars = contextGlyphsString.mid(contextStringPointer,len); + } + //contextStringPointer += 1; + } + else + { + chars = contextString.mid(contextStringPointer,len); + } + qDebug(QString("char is [%1], contextGlyphsString is [%2], contextStringPointer[%3], len [%4]").arg(chars[0].unicode()).arg(contextGlyphsString).arg(contextStringPointer).arg(len)); + double retval = 0.0; + double asce = style.font().ascent(style.fontSize() / 10.0); + int chst = style.effects() & 1919; + if (chars[0] == SpecialChars::ZWSPACE || + chars[0] == SpecialChars::ZWNBSPACE || + chars[0] == SpecialChars::NBSPACE || + chars[0] == SpecialChars::NBHYPHEN || + chars[0] == SpecialChars::SHYPHEN || + chars[0] == SpecialChars::PARSEP || + chars[0] == SpecialChars::COLBREAK || + chars[0] == SpecialChars::LINEBREAK || + chars[0] == SpecialChars::FRAMEBREAK || + chars[0] == SpecialChars::TAB) + { + layout.glyph = ScFace::CONTROL_GLYPHS + chars[0].unicode(); + } + else + { + layout.glyph = style.font().char2CMap(chars[0].unicode()); //otf comment : here we assume that the proper pair is in the c_Map cache + } + + double tracking = 0.0; + if ( (style.effects() & ScStyle_StartOfLine) == 0) + tracking = style.fontSize() * style.tracking() / 10000.0; + + layout.xoffset = tracking; + layout.yoffset = 0; + if (chst != ScStyle_Default) + { + if (chst & ScStyle_Superscript) + { + retval -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.yoffset -= asce * m_Doc->typographicSettings.valueSuperScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSuperScript / 100.0, 10.0 / style.fontSize()); + } + else if (chst & ScStyle_Subscript) + { + retval += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.yoffset += asce * m_Doc->typographicSettings.valueSubScript / 100.0; + layout.scaleV = layout.scaleH = QMAX(m_Doc->typographicSettings.scalingSubScript / 100.0, 10.0 / style.fontSize()); + } + else { + layout.scaleV = layout.scaleH = 1.0; + } + layout.scaleH *= style.scaleH() / 1000.0; + layout.scaleV *= style.scaleV() / 1000.0; + if (chst & ScStyle_AllCaps) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + } + if (chst & ScStyle_SmallCaps) + { + + double smallcapsScale = m_Doc->typographicSettings.valueSmallCaps / 100.0; + QChar uc = chars[0].upper(); + if (uc != chars[0]) + { + layout.glyph = style.font().char2CMap(chars[0].upper().unicode()); + layout.scaleV *= smallcapsScale; + layout.scaleH *= smallcapsScale; + } + } + } + else { + layout.scaleH = style.scaleH() / 1000.0; + layout.scaleV = style.scaleV() / 1000.0; + } + + if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBSPACE.unicode())) { + uint replGlyph = style.font().char2CMap(QChar(' ')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph == (ScFace::CONTROL_GLYPHS + SpecialChars::NBHYPHEN.unicode())) { + uint replGlyph = style.font().char2CMap(QChar('-')); + layout.xadvance = style.font().glyphWidth(replGlyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(replGlyph, style.fontSize() / 10).ascent * layout.scaleV; + } + else if (layout.glyph >= ScFace::CONTROL_GLYPHS) { + layout.xadvance = 0; + layout.yadvance = 0; + } + else { + layout.xadvance = style.font().glyphWidth(layout.glyph, style.fontSize() / 10) * layout.scaleH; + layout.yadvance = style.font().glyphBBox(layout.glyph, style.fontSize() / 10).ascent * layout.scaleV; + } + if(otf)//Don't wait for ::layout to adjust with pair kerning + { + posglyph pg = style.font().otf()->get_position(contextStringPointer); + qDebug(QString("Adjust[%1] pg.xadv=%2 , pg.yadv=%3").arg(layout.glyph).arg(pg.xadvance()).arg(pg.yadvance())); + layout.xadvance = pg.xadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleH; + layout.yadvance = pg.yadvance() / style.font().unitsEM() * style.fontSize() / 10 * layout.scaleV; + + + } + if (layout.xadvance > 0) + layout.xadvance += tracking; + + if (chars.length() > 1) { + layout.grow(); + contextStringPointer += 1; + layoutGlyphs(style, chars.length()-1, *layout.more); + layout.xadvance += style.font().glyphKerning(layout.glyph, layout.more->glyph, style.fontSize() / 10) * layout.scaleH; + if (layout.more->yadvance > layout.yadvance) + layout.yadvance = layout.more->yadvance; + } + else { + contextStringPointer += 1; + layout.shrink(); + } + + return retval; +} + void PageItem::drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs) { uint glyph = glyphs.glyph; if ((m_Doc->guidesSettings.showControls) && (glyph == style.font().char2CMap(QChar(' ')) || glyph >= ScFace::CONTROL_GLYPHS)) { bool stroke = false; if (glyph >= ScFace::CONTROL_GLYPHS) Index: scribus/pageitem.h =================================================================== RCS file: /cvs/Scribus/scribus/pageitem.h,v retrieving revision 1.26.2.183 diff -u -8 -p -r1.26.2.183 pageitem.h --- scribus/pageitem.h 4 Apr 2007 21:46:32 -0000 1.26.2.183 +++ scribus/pageitem.h 9 Apr 2007 15:38:28 -0000 @@ -289,16 +289,17 @@ public: /// returns the style at the current charpos const ParagraphStyle& currentStyle() const; /// returns the style at the current charpos ParagraphStyle& changeCurrentStyle(); /// returns the style at the current charpos const CharStyle& currentCharStyle() const; // deprecated: double layoutGlyphs(const CharStyle& style, const QString chars, GlyphLayout& layout); + double layoutGlyphs(const CharStyle& style, int len, GlyphLayout& layout); void SetFarbe(QColor *tmp, QString farbe, int shad); void drawGlyphs(ScPainter *p, const CharStyle& style, GlyphLayout& glyphs ); void DrawPolyL(QPainter *p, QPointArray pts); QString ExpandToken(uint base); bool AutoName; double gXpos; double gYpos; @@ -1208,16 +1209,22 @@ public: /** Darstellungsart Bild/Titel */ bool PicArt; /** Line width */ double m_lineWidth; double Oldm_lineWidth; + /** Context String */ + QString contextString; + QString contextGlyphsString; + int contextStringPointer; + int contexLengthChange; + signals: //Frame signals void myself(PageItem *); void frameType(int); // not related to Frametype but to m_itemIype :-/ void position(double, double); //X,Y void widthAndHeight(double, double); //W,H void rotation(double); //Degrees rotation void colors(QString, QString, int, int); //lineColor, fillColor, lineShade, fillShade Index: scribus/pageitem_textframe.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/pageitem_textframe.cpp,v retrieving revision 1.1.2.159 diff -u -8 -p -r1.1.2.159 pageitem_textframe.cpp --- scribus/pageitem_textframe.cpp 5 Apr 2007 16:27:20 -0000 1.1.2.159 +++ scribus/pageitem_textframe.cpp 9 Apr 2007 15:38:34 -0000 @@ -565,19 +565,16 @@ static double opticalRightMargin(const S rightCorr -= itemText.charStyle(b).font().charWidth(chr, chs / 10.0, QChar('.')); } return rightCorr; } return 0.0; } - - - void PageItem_TextFrame::layout() { if (BackBox != NULL && BackBox->invalid) { // qDebug("textframe: len=%d, going back", itemText.length()); invalid = false; PageItem_TextFrame* prevInChain = dynamic_cast<PageItem_TextFrame*>(BackBox); if (!prevInChain) @@ -699,19 +696,71 @@ void PageItem_TextFrame::layout() else // empty itemText: { desc2 = -itemText.defaultStyle().charStyle().font().descent(itemText.defaultStyle().charStyle().fontSize() / 10.0); current.yPos = itemText.defaultStyle().lineSpacing() + extra.Top+lineCorr-desc2; } current.startLine(firstInFrame()); outs = false; OFs = 0; - MaxChars = 0; + MaxChars = 0; + // BIGLOOP + int contextrest = 0; + int sccontrol; for (int a = firstInFrame(); a < itemText.length(); ++a) { + // here we set the context string + if(contextrest == 0) + { + contextString = ""; + sccontrol = 0; + for(int ctsg = a; ctsg < itemText.length(); ++ctsg) + { + + QString contmp = ExpandToken(ctsg); + if(current.breakIndex == a) + { + break; + } + else if(contmp[0] == SpecialChars::ZWSPACE || + contmp[0] == SpecialChars::ZWNBSPACE || + contmp[0] == SpecialChars::NBSPACE || + contmp[0] == SpecialChars::NBHYPHEN || + contmp[0] == SpecialChars::SHYPHEN || + contmp[0] == SpecialChars::PARSEP || + contmp[0] == SpecialChars::COLBREAK || + contmp[0] == SpecialChars::LINEBREAK || + contmp[0] == SpecialChars::FRAMEBREAK || + contmp[0] == SpecialChars::TAB || + contmp[0] == SpecialChars::BLANK) + { + if(sccontrol > 0) + { + break; + } + else + { + contextString += QChar(0) ; + contextString += contmp[0].unicode(); + break; + } + } + else + { + sccontrol += 1; + contextString += contmp; + } + } + contextrest = (sccontrol == 0 ? 1 : contextString.length());// we send special char one by one + contextStringPointer = 0; + qDebug(QString("contextrest = %1 and context string is \"%2\"").arg(contextrest).arg(contextString)); + } + --contextrest; + + hl = itemText.item(a); if (a > 0 && itemText.text(a-1) == SpecialChars::PARSEP) style = itemText.paragraphStyle(a); if (current.itemsInLine == 0) opticalMargins = style.opticalMargins(); // qDebug(QString("style pos %1: %2 (%3)").arg(a).arg(style.alignment()).arg(style.parent())); const CharStyle& charStyle = itemText.charStyle(a); @@ -862,30 +911,35 @@ void PageItem_TextFrame::layout() kernVal = 0; } else { kernVal = 0; // chs * charStyle.tracking() / 10000.0; itemText.item(a)->setEffects(itemText.item(a)->effects() & ~ScStyle_StartOfLine); } hl->glyph.yadvance = 0; - oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); + //qDebug(QString("sending [%1] to layoutGlyphs()").arg(chstr)); + oldCurY = layoutGlyphs(*hl, chstr.length(), hl->glyph); + //oldCurY = layoutGlyphs(*hl, chstr, hl->glyph); // find out width of char if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); else { wide = hl->glyph.wide(); // apply kerning if (a+1 < itemText.length()) { - uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); - double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; - wide += kern; - hl->glyph.xadvance += kern; + if( !charStyle.font().isOTF() ) + { + uint glyph2 = charStyle.font().char2CMap(itemText.text(a+1)); + double kern= charStyle.font().glyphKerning(hl->glyph.glyph, glyph2, chs / 10.0) * hl->glyph.scaleH; + wide += kern; + hl->glyph.xadvance += kern; + } } } if (DropCmode) { // drop caps are wider... if ((hl->ch[0] == SpecialChars::OBJECT) && (hl->embedded.hasItem())) { wide = hl->embedded.getItem()->gWidth + hl->embedded.getItem()->lineWidth(); @@ -1352,16 +1406,17 @@ void PageItem_TextFrame::layout() tcli.setPoint(3, QPoint(qRound(hl->glyph.xoffset), qRound(maxDY))); cm = QRegion(pf2.xForm(tcli)); cl = cl.subtract(cm); // current.yPos = maxDY; } // end of line if ( SpecialChars::isBreak(hl->ch[0], Cols > 1) || (outs)) { + contextrest = 0; tabs.active = false; tabs.status = TabNONE; if (SpecialChars::isBreak(hl->ch[0], Cols > 1)) { // find end of line current.breakLine(itemText, a); EndX = current.endOfLine(cl, pf2, asce, desc, style.rightMargin()); current.finishLine(EndX); Index: scribus/scribusdoc.cpp =================================================================== RCS file: /cvs/Scribus/scribus/scribusdoc.cpp,v retrieving revision 1.25.2.448 diff -u -8 -p -r1.25.2.448 scribusdoc.cpp --- scribus/scribusdoc.cpp 4 Apr 2007 21:08:56 -0000 1.25.2.448 +++ scribus/scribusdoc.cpp 9 Apr 2007 15:38:49 -0000 @@ -2765,22 +2765,28 @@ void ScribusDoc::checkItemForFonts(PageI newText=getSectionPageNumberForPageIndex(a); for (uint nti=0;nti<newText.length();++nti) if (pageNumberText.find(newText[nti])==-1) pageNumberText+=newText[nti]; } } } //Now scan and add any glyphs used in page numbers + if(it->itemText.charStyle(e).font().isOTF()) + pageNumberText = it->itemText.charStyle(e).font().otfied(pageNumberText,it->itemText.charStyle(e).language(), it->itemText.charStyle(e).fontFeatures()); for (uint pnti=0;pnti<pageNumberText.length(); ++pnti) { uint chr = pageNumberText[pnti].unicode(); if (it->itemText.charStyle(e).font().canRender(chr)) { - uint gl = it->itemText.charStyle(e).font().char2CMap(pageNumberText[pnti]); + uint gl; + if(it->itemText.charStyle(e).font().isOTF()) + gl = pageNumberText[pnti].unicode() ; + else + gl = it->itemText.charStyle(e).font().char2CMap(pageNumberText[pnti]); FPointArray gly(it->itemText.charStyle(e).font().glyphOutline(gl)); Really[it->itemText.charStyle(e).font().replacementName()].insert(gl, gly); } } continue; } if (it->itemText.charStyle(e).effects() & ScStyle_SmartHyphenVisible) { @@ -2792,17 +2798,18 @@ void ScribusDoc::checkItemForFonts(PageI { chstr = it->itemText.text(e, 1); if (chstr.upper() != it->itemText.text(e, 1)) chstr = chstr.upper(); chr = chstr[0].unicode(); } if (it->itemText.charStyle(e).font().canRender(chr)) { - uint gl = it->itemText.charStyle(e).font().char2CMap(chr); + //uint gl = it->itemText.charStyle(e).font().char2CMap(chr); + uint gl = it->itemText.item(e)->glyph.glyph; gly = it->itemText.charStyle(e).font().glyphOutline(gl); Really[it->itemText.charStyle(e).font().replacementName()].insert(gl, gly); } } } } void ScribusDoc::getUsedProfiles(ProfilesL& usedProfiles) Index: scribus/smtextstyles.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/smtextstyles.cpp,v retrieving revision 1.1.2.59 diff -u -8 -p -r1.1.2.59 smtextstyles.cpp --- scribus/smtextstyles.cpp 6 Mar 2007 21:52:44 -0000 1.1.2.59 +++ scribus/smtextstyles.cpp 9 Apr 2007 15:38:53 -0000 @@ -59,16 +59,18 @@ void SMParagraphStyle::currentDoc(Scribu doc_ = doc; if (doc_) { if (pwidget_) { pwidget_->cpage->fillLangCombo(doc_->scMW()->LangTransl); pwidget_->cpage->fillColorCombo(doc_->PageColors); pwidget_->cpage->fontFace_->RebuildList(doc_); + pwidget_->cpage->fillFeaturesCombo(PrefsManager::instance()->appPrefs.AvailFonts[pwidget_->cpage->fontFace_->currentFont()]); + if (unitRatio_ != doc_->unitRatio()) unitChange(); } } else { removeConnections(); selection_.clear(); @@ -1205,16 +1207,17 @@ void SMCharacterStyle::currentDoc(Scribu doc_ = doc; if (doc_) { if (page_) { page_->fillLangCombo(doc_->scMW()->LangTransl); page_->fillColorCombo(doc_->PageColors); page_->fontFace_->RebuildList(doc_); + page_->fillFeaturesCombo(PrefsManager::instance()->appPrefs.AvailFonts[page_->fontFace_->currentFont()]); } } else { removeConnections(); selection_.clear(); tmpStyles_.clear(); } @@ -1540,16 +1543,17 @@ void SMCharacterStyle::setupConnections( connect(page_->fontSize_, SIGNAL(valueChanged(int)), this, SLOT(slotFontSize())); connect(page_->fontHScale_, SIGNAL(valueChanged(int)), this, SLOT(slotScaleH())); connect(page_->fontVScale_, SIGNAL(valueChanged(int)), this, SLOT(slotScaleV())); connect(page_->tracking_, SIGNAL(valueChanged(int)), this, SLOT(slotTracking())); connect(page_->baselineOffset_, SIGNAL(valueChanged(int)), this, SLOT(slotBaselineOffset())); connect(page_->fontFace_, SIGNAL(fontSelected(QString)), this, SLOT(slotFont(QString))); connect(page_->parentCombo, SIGNAL(activated(const QString&)), this, SLOT(slotParentChanged(const QString&))); + connect(page_->features_, SIGNAL(activated(int)), this, SLOT(slotFeatures())); } void SMCharacterStyle::removeConnections() { if (!page_) return; disconnect(page_->fontFace_, SIGNAL(fontSelected(QString)), this, SLOT(slotFont(QString))); @@ -1576,16 +1580,17 @@ void SMCharacterStyle::removeConnections disconnect(page_->fontSize_, SIGNAL(valueChanged(int)), this, SLOT(slotFontSize())); disconnect(page_->fontHScale_, SIGNAL(valueChanged(int)), this, SLOT(slotScaleH())); disconnect(page_->fontVScale_, SIGNAL(valueChanged(int)), this, SLOT(slotScaleV())); disconnect(page_->tracking_, SIGNAL(valueChanged(int)), this, SLOT(slotTracking())); disconnect(page_->baselineOffset_, SIGNAL(valueChanged(int)), this, SLOT(slotBaselineOffset())); disconnect(page_->fontFace_, SIGNAL(fontSelected(QString)), this, SLOT(slotFont(QString))); disconnect(page_->parentCombo, SIGNAL(activated(const QString&)), this, SLOT(slotParentChanged(const QString&))); + disconnect(page_->features_, SIGNAL(activated(int)), this, SLOT(slotFeatures())); } void SMCharacterStyle::slotFontSize() { if (page_->fontSize_->useParentValue()) for (uint i = 0; i < selection_.count(); ++i) selection_[i]->resetFontSize(); else @@ -1915,25 +1920,61 @@ void SMCharacterStyle::slotFont(QString if (page_->fontFace_->useParentFont()) for (uint i = 0; i < selection_.count(); ++i) selection_[i]->resetFont(); else { sf = PrefsManager::instance()->appPrefs.AvailFonts[s]; for (uint i = 0; i < selection_.count(); ++i) selection_[i]->setFont(sf); + page_->fillFeaturesCombo(sf); } + if (!selectionIsDirty_) { selectionIsDirty_ = true; emit selectionDirty(); } } +void SMCharacterStyle::slotFeatures() +{ + if (page_->features_->useParentValue()) + for (uint i = 0; i < selection_.count(); ++i) + selection_[i]->resetFontFeatures(); + else + { + + QString ct = page_->features_->currentText(); + if(ct.right(4) == "_ON_") + page_->features_->setCurrentText(ct.left(4)); + else + page_->features_->setCurrentText(ct + "_ON_"); + + QStringList features; + for(uint i = 0; i < page_->features_->count() ; ++i) + { + if(page_->features_->text(i).right(4) == "_ON_") + features.append(page_->features_->text(i).left(4)); + } + + for (uint i = 0; i < selection_.count(); ++i) + selection_[i]->setFontFeatures(features); + } + + + if (!selectionIsDirty_) + { + selectionIsDirty_ = true; + emit selectionDirty(); + } + +} + void SMCharacterStyle::slotParentChanged(const QString &parent) { Q_ASSERT(!parent.isNull()); QStringList sel; for (uint i = 0; i < selection_.count(); ++i) { @@ -1946,16 +1987,17 @@ void SMCharacterStyle::slotParentChanged if (!selectionIsDirty_) { selectionIsDirty_ = true; emit selectionDirty(); } } + SMCharacterStyle::~SMCharacterStyle() { delete page_; delete widget_; page_ = 0; widget_ = 0; } Index: scribus/smtextstyles.h =================================================================== RCS file: /cvs/Scribus/scribus/Attic/smtextstyles.h,v retrieving revision 1.1.2.21 diff -u -8 -p -r1.1.2.21 smtextstyles.h --- scribus/smtextstyles.h 6 Mar 2007 09:18:33 -0000 1.1.2.21 +++ scribus/smtextstyles.h 9 Apr 2007 15:38:53 -0000 @@ -152,13 +152,14 @@ private slots: void slotStrokeColor(); void slotStrokeShade(); void slotLanguage(); void slotScaleH(); void slotScaleV(); void slotTracking(); void slotBaselineOffset(); void slotFont(QString s); + void slotFeatures(); void slotParentChanged(const QString &parent); }; #endif Index: scribus/smtextstylewidgets.cpp =================================================================== RCS file: /cvs/Scribus/scribus/Attic/smtextstylewidgets.cpp,v retrieving revision 1.1.2.46 diff -u -8 -p -r1.1.2.46 smtextstylewidgets.cpp --- scribus/smtextstylewidgets.cpp 29 Mar 2007 20:11:42 -0000 1.1.2.46 +++ scribus/smtextstylewidgets.cpp 9 Apr 2007 15:38:55 -0000 @@ -731,16 +731,19 @@ SMCStylePage::SMCStylePage(QWidget *pare advBoxLayout->addLayout( spinBoxLayout_, Qt::AlignLeft ); layout9a = new QHBoxLayout( 0, 0, 0, "layout9"); languageLabel_ = new QLabel( "", advGroup, "languageLabel_" ); language_ = new SMScComboBox(false, advGroup, "language_"); layout9a->addWidget(languageLabel_); layout9a->addWidget(language_); + + features_ = new SMScComboBox(false, advGroup, "features_"); + layout9a->addWidget(features_); spacer1 = new QSpacerItem( 0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ); layout9a->addItem( spacer1 ); advBoxLayout->addLayout( layout9a, Qt::AlignLeft ); @@ -835,16 +838,41 @@ void SMCStylePage::languageChange() languageLabel_->setText( tr("Language:")); fontVScale_->setSuffix( tr(" %")); fontHScale_->setSuffix( tr(" %")); baselineOffset_->setSuffix( tr(" %")); tracking_->setSuffix( tr(" %")); fontSize_->setSuffix(unitGetSuffixFromIndex(0)); } +void SMCStylePage::fillFeaturesCombo(ScFace face) +{ + qDebug(QString("SMCStylePage::fillFeaturesCombo(%1)").arg(face.scName())); + if(face.isOTF()) + { + QStringList fl; + QString la; + features_->clear(); + face.canRender('a');// We need the face to be loaded + for(QMap<QString,QString>::Iterator it=langMap_.begin(); + it != langMap_.end(); + it++) + { + if(it.data() == language_->currentText()) + { + la = it.key(); + break; + } + } + fl = face.allFeatures(face.otfLang(la)); + features_->insertStringList(fl); + } + +} + void SMCStylePage::fillLangCombo(QMap<QString,QString> langMap) { QStringList sortList; QMap<QString,QString>::Iterator it; langMap_ = langMap; language_->clear(); Index: scribus/smtextstylewidgets.h =================================================================== RCS file: /cvs/Scribus/scribus/Attic/smtextstylewidgets.h,v retrieving revision 1.1.2.22 diff -u -8 -p -r1.1.2.22 smtextstylewidgets.h --- scribus/smtextstylewidgets.h 11 Mar 2007 00:22:16 -0000 1.1.2.22 +++ scribus/smtextstylewidgets.h 9 Apr 2007 15:38:56 -0000 @@ -110,16 +110,17 @@ class SMCStylePage : public CStylePBase public: SMCStylePage(QWidget *parent = 0); ~SMCStylePage(); void show(CharStyle *cstyle, QValueList<CharStyle> &cstyles, const QString &defLang, int unitIndex); void show(QValueList<CharStyle*> &cstyles, QValueList<CharStyle> &cstylesAll, const QString &defLang, int unitIndex); void fillLangCombo(QMap<QString,QString> langMap); void fillColorCombo(ColorList &colors); + void fillFeaturesCombo(ScFace face); void languageChange(); void clearAll(); private: QVBoxLayout *basicBoxLayout; QVBoxLayout *advBoxLayout; QVBoxLayout *colorBoxLayout; QHBoxLayout *layout8; @@ -131,16 +132,17 @@ private: SMFontComboH *fontFace_; SMStyleSelect *effects_; SMColorCombo *fillColor_; SMShadeButton *fillShade_; SMColorCombo *strokeColor_; SMShadeButton *strokeShade_; SMScComboBox *language_; + SMScComboBox *features_; SMMSpinBox *fontSize_; SMMSpinBox *fontHScale_; SMMSpinBox *fontVScale_; SMMSpinBox *tracking_; SMMSpinBox *baselineOffset_; QLabel *fontSizeLabel_; Index: scribus/smwidgets.h =================================================================== RCS file: /cvs/Scribus/scribus/Attic/smwidgets.h,v retrieving revision 1.1.2.10 diff -u -8 -p -r1.1.2.10 smwidgets.h --- scribus/smwidgets.h 13 Nov 2006 06:15:54 -0000 1.1.2.10 +++ scribus/smwidgets.h 9 Apr 2007 15:38:58 -0000 @@ -232,16 +232,17 @@ private: QString usePFont_; void setFont(bool wantBold); private slots: void currentChanged(); void checkStyle(); }; + class SMTabruler : public Tabruler { Q_OBJECT public: SMTabruler(QWidget* parent, bool haveFirst = true, int dEin = 1, QValueList<ParagraphStyle::TabRecord> Tabs = QValueList<ParagraphStyle::TabRecord>(), Index: scribus/styleselect.h =================================================================== RCS file: /cvs/Scribus/scribus/styleselect.h,v retrieving revision 1.2.2.12 diff -u -8 -p -r1.2.2.12 styleselect.h --- scribus/styleselect.h 22 Jan 2006 22:42:02 -0000 1.2.2.12 +++ scribus/styleselect.h 9 Apr 2007 15:38:59 -0000 @@ -8,16 +8,17 @@ for which a new license (GPL+exception) #define STYLESELECT_H class QGroupBox; class QToolButton; class QLayout; class MSpinBox; class QLabel; class QPopupMenu; +class QListView; #include "scribusapi.h" class SCRIBUS_API StrikeValues : public QGroupBox { Q_OBJECT public: @@ -132,12 +133,13 @@ protected: QToolButton* allcapsButton; QToolButton* strikeoutButton; QToolButton* outlineButton; QToolButton* shadowButton; QPopupMenu* ShadowPop; QPopupMenu* OutlinePop; QPopupMenu* UnderlinePop; QPopupMenu* StrikePop; + }; #endif Index: scribus/desaxe/saxiohelper.cpp =================================================================== RCS file: /cvs/Scribus/scribus/desaxe/Attic/saxiohelper.cpp,v retrieving revision 1.1.2.8 diff -u -8 -p -r1.1.2.8 saxiohelper.cpp --- scribus/desaxe/saxiohelper.cpp 4 Apr 2007 21:46:32 -0000 1.1.2.8 +++ scribus/desaxe/saxiohelper.cpp 9 Apr 2007 15:39:00 -0000 @@ -191,8 +191,13 @@ Xml_string toXMLString(const ScFace& val return val.scName(); } Xml_string toXMLString(const FPointArray& path) { return path.svgPath(); } + +Xml_string toXMLString(const QStringList& sl) +{ + return sl.join(","); +} Index: scribus/desaxe/saxiohelper.h =================================================================== RCS file: /cvs/Scribus/scribus/desaxe/Attic/saxiohelper.h,v retrieving revision 1.1.2.8 diff -u -8 -p -r1.1.2.8 saxiohelper.h --- scribus/desaxe/saxiohelper.h 4 Apr 2007 21:46:32 -0000 1.1.2.8 +++ scribus/desaxe/saxiohelper.h 9 Apr 2007 15:39:00 -0000 @@ -1,14 +1,15 @@ #ifndef SAXHELPER_H #define SAXHELPER_H #include "desaxe_conf.h" #include <qvaluelist.h> #include <qvaluestack.h> +#include <qstringlist.h> class ScFace; class FPointArray; Xml_string toXMLString(unsigned int val); Xml_string toXMLString(int val); Xml_string toXMLString(unsigned long val); @@ -18,16 +19,17 @@ Xml_string toXMLString(float val); Xml_string toXMLString(bool val); Xml_string toXMLString(const Xml_string& val); Xml_string toXMLString(const ScFace& val); Xml_string toXMLString(const FPointArray& path); Xml_string toXMLString(const QValueList<double>& doublelist); Xml_string toXMLString(const QValueList<int>& intlist); +Xml_string toXMLString(const QStringList& sl); unsigned int parseUInt(const Xml_string& str); int parseInt(const Xml_string& str); unsigned long parseULong(const Xml_string& str); long parseLong(const Xml_string& str); double parseDouble(const Xml_string& str); float parseFloat(const Xml_string& str); bool parseBool(const Xml_string& str); Index: scribus/fonts/CMakeLists.txt =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/CMakeLists.txt,v retrieving revision 1.1.2.1 diff -u -8 -p -r1.1.2.1 CMakeLists.txt --- scribus/fonts/CMakeLists.txt 23 Jul 2006 12:07:47 -0000 1.1.2.1 +++ scribus/fonts/CMakeLists.txt 9 Apr 2007 15:39:02 -0000 @@ -5,12 +5,20 @@ ${CMAKE_SOURCE_DIR}/scribus SET(SCRIBUS_FONTS_LIB_SOURCES scface.cpp ftface.cpp scface_ps.cpp scface_ttf.cpp scfontmetrics.cpp +myotf.cpp ) + + SET(SCRIBUS_FONTS_LIB "scribus_fonts_lib") ADD_LIBRARY(${SCRIBUS_FONTS_LIB} STATIC ${SCRIBUS_FONTS_LIB_SOURCES}) + +INSTALL(FILES +opentype_langmap.txt + DESTINATION ${SHAREDIR} +) Index: scribus/fonts/ftface.cpp =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.cpp,v retrieving revision 1.1.2.9 diff -u -8 -p -r1.1.2.9 ftface.cpp --- scribus/fonts/ftface.cpp 11 Jan 2007 15:29:46 -0000 1.1.2.9 +++ scribus/fonts/ftface.cpp 9 Apr 2007 15:39:03 -0000 @@ -2,18 +2,22 @@ #include "fonts/ftface.h" #include FT_OUTLINE_H #include FT_GLYPH_H #include <qobject.h> #include <qfile.h> +#include <qmessagebox.h> +#include <qinputdialog.h> + #include "scfonts.h" #include "fonts/scfontmetrics.h" +#include "scpaths.h" // static: FT_Library FtFace::library = NULL; /***** ScFace lifecycle: unchecked -> loaded -> glyphs checked | \-> broken glyphs \-> broken @@ -136,36 +140,127 @@ void FtFace::load() const ++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; } + //TEST libotf + if(typeCode == ScFace::OTF) + { + // First we load language - script/lang pairs map from config file. + langMap.clear(); + QFile file(ScPaths::instance().shareDir() + "opentype_langmap.txt"); + //QMap < QPair<QString, QString>, QString > reversedLangMap; + if (file.open( IO_ReadOnly ) ) + { + QStringList list(QStringList::split('\n', file.readAll())); + file.close(); + QStringList line; + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + { + line = QStringList::split(':', *it); + langMap[line[0]] = qMakePair(line[1], line[2]); + scriptMap[line[0]] = line[1] + "dflt"; + //reversedLangMap[qMakePair(line[1].lower(), line[2].lower())] = line[0]; + } + } + else + qDebug("error reading opentype_langmap"); + + //_otf = new myotf(QFile::encodeName(fontFile)); + _otf = new myotf(m_face); + + if(_otf->get_tables().contains("GSUB")) + { + _otf->set_table("GSUB"); + QStringList sc = _otf->get_scripts(); + for(int sci = 0; sci < sc.count(); sci++) + { + _otf->set_script(sc[sci]); + QStringList la = _otf->get_langs(); + la.append("dflt"); + for(int lai=0; lai < la.count() ; lai++) + { + //QPair<QString, QString> p = qMakePair(sc[sci], la[lai]); + QString lang = sc[sci] + la[lai] ; + _otf->set_lang(la[lai]); + OtFeatures ot_f; + ot_f.gsub = _otf->get_features(); + features[lang] = ot_f; + } + } + } + if(_otf->get_tables().contains("GPOS")) + { + _otf->set_table("GPOS"); + QStringList sc = _otf->get_scripts(); + for(int sci = 0; sci < sc.count(); sci++) + { + _otf->set_script(sc[sci]); + QStringList la = _otf->get_langs(); + la.append("dflt"); + for(int lai=0; lai < la.count() ; lai++) + { + //QPair<QString, QString> p= qMakePair(sc[sci], la[lai]); + QString lang = sc[sci] + la[lai] ; + _otf->set_lang(la[lai]); + + if(features.contains(lang)) + { + QStringList gp = _otf->get_features(); + features[lang].gpos = gp; + } + else + { + OtFeatures ot_f; + ot_f.gpos = _otf->get_features(); + features[lang] = ot_f; + } + } + } + } + // Dump features + for(QMapIterator < QString, OtFeatures > it = features.begin(); it != features.end(); ++it) + { + qDebug(it.key()); + qDebug(it.data().gsub.join("|")); + qDebug(it.data().gpos.join("|")); + } + } } void FtFace::unload() const { if (m_face) { FT_Done_Face( m_face ); m_face = NULL; } // clear caches + if(_otf) delete _otf; 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; + if(m_cMap.contains(ch.unicode())) + { + return m_cMap[ch.unicode()]; + } + else + { + FT_Face face = ftFace(); + uint gl = FT_Get_Char_Index(face, ch.unicode()); + m_cMap.insert(ch.unicode(), gl); + return gl; + } } void FtFace::loadGlyph(uint gl) const { if (m_glyphWidth.contains(gl)) return; @@ -307,9 +402,63 @@ void FtFace::RawData(QByteArray & bb) co // 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())); } */ } +QString FtFace::otfLang(QString s) const +{ + QString fullLang = langMap[s].first + langMap[s].second; + QString dfltLang = scriptMap[s]; + if(features.contains(fullLang)) + return fullLang; + if(features.contains(dfltLang)) + return dfltLang; + qDebug(QString("otfLang(%1) : can't find match in features map").arg(s)); + return s; +} +/* param lang has to be an otfLang returned by the method above */ +QString FtFace::otfied(QString s, QString lang, QStringList f) const +{ + qDebug(QString("otfied(%1, %2, %3)").arg(s).arg(lang).arg(f.join("|"))); + if(status != ScFace::LOADED || status != ScFace::CHECKED ) + { + qDebug("Face is not loaded"); + } + if(!features.contains(lang)) + { + qDebug(QString("Ça va mal, la langue (%1) demandée n'est pas supportée par la police").arg(lang)); + return s; + } + else if(typeCode == ScFace::OTF) + { + QString sc = lang.left(4); + QString la = lang.right(4); + QStringList osf; + QStringList opf ; + for(int i=0 ; i < f.count() ; ++i) + { + if(features[lang].gpos.contains(f[i])) + opf.append(f[i]); + if(features[lang].gsub.contains(f[i])) + osf.append(f[i]); + } + int nbg = _otf->procstring(s,sc,la,osf, opf); + // Actually, newstring should be a QValueList<uint> as it's a glyphstring + QString newstring; + for (int i = 0; i < nbg ; ++i) + { + int gi= _otf->get_glyph(i); + newstring += QChar(gi); + m_cMap.insert(gi,gi); + } + + + qDebug(QString("oldstring is \"%1\" and new string is \"%2\"").arg(s).arg(newstring)); + return newstring; + + } + return s; +} Index: scribus/fonts/ftface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/ftface.h,v retrieving revision 1.1.2.5 diff -u -8 -p -r1.1.2.5 ftface.h --- scribus/fonts/ftface.h 1 Sep 2006 23:55:18 -0000 1.1.2.5 +++ scribus/fonts/ftface.h 9 Apr 2007 15:39:03 -0000 @@ -96,22 +96,31 @@ protected: mutable QString Descender; mutable QString ItalicAngle; mutable QString StdVW; QString FontEnc; mutable QString FontBBox; mutable int m_encoding; - mutable double m_uniEM; +// mutable double m_uniEM; mutable double m_ascent; mutable double m_descent; mutable double m_height; mutable double m_xHeight; mutable double m_capHeight; mutable double m_maxAdvanceWidth; mutable double m_underlinePos; mutable double m_strikeoutPos; mutable double m_strokeWidth; + //TEST libotf + public: + mutable QMap < QString, QPair<QString, QString> > langMap; //Didn't found the good place for it :( + mutable QMap < QString, QString> scriptMap; + //mutable QMap < QString, OtFeatures > allFeatures; // form is < scrilang , [gsublist,gposlist] > + QString otfied(QString s, QString lang, QStringList features) const ; + QString otfLang(QString) const; + + }; #endif Index: scribus/fonts/myotf.cpp =================================================================== RCS file: scribus/fonts/myotf.cpp diff -N scribus/fonts/myotf.cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.cpp 9 Apr 2007 15:39:04 -0000 @@ -0,0 +1,630 @@ +/* un test de libotf mer18jan qui se transforme en test de harfbuzz mer4avr*/ + + +#include "myotf.h" + +///Required by this great lib that do not provide all symbols +#include <harfbuzz-external.h> +//#include <Qt/private/qunicodetables_p.h> + +HB_LineBreakClass HB_GetLineBreakClass(HB_UChar32 ch) +{ +// #if QT_VERSION >= 0x040300 +// return (HB_LineBreakClass)QUnicodeTables::lineBreakClass(ch); +// #else +// #error "This test currently requires Qt >= 4.3" +// #endif + return (HB_LineBreakClass) 0; +} + +void HB_GetUnicodeCharProperties(HB_UChar32 ch, HB_CharCategory *category, int *combiningClass) +{ + *category = (HB_CharCategory)QChar::Category(ch); + *combiningClass = QChar::CombiningClass(ch); +} + +HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch) +{ + return (HB_CharCategory)QChar::Category(ch); +} + +int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch) +{ + return QChar::CombiningClass(ch); +} + +HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) +{ + return QChar(ch).mirroredChar(); +} +/// + +QString +OTF_tag_name (HB_UInt tag) +{ + QString name; + name[0] = (char) (tag >> 24); + name[1] = (char) ((tag >> 16) & 0xFF); + name[2] = (char) ((tag >> 8) & 0xFF); + name[3] = (char) (tag & 0xFF); +// qDebug(QString("OTF_tag_name (%1) -> %2").arg(tag).arg(name)); + return name; +} + +HB_UInt +OTF_name_tag (QString s) +{ + // QChar sometimestagnameisthreecharslong = + // s.length () > 3 ? s[3].unicode () : ' '; +// qDebug(QString("Making tag %6 for name \"%1\" with [%2][%3][%4][%5]").arg(s).arg(s[0].unicode ()).arg(s[1].unicode ()).arg(s[2].unicode ()).arg(s[3].unicode ()).arg(FT_MAKE_TAG (s[0].unicode (), s[1].unicode (), s[2].unicode (),s[3].unicode ()))); + HB_UInt ret = FT_MAKE_TAG (s[0].unicode (), s[1].unicode (), (s[2].isNull() ? ' ' :s[2].unicode ()), (s[3].isNull() ? ' ' :s[3].unicode ())); +// qDebug(QString("OTF_name_tag (%1) -> %2").arg(s).arg(ret)); + return ret; +} + +//#define DFLT 0xFFFF + +void +myotf::set_subalt (bool b) +{ + subAlt = b; +} + +int myotf::get_glyph( int index) +{ + return _buffer->in_string[index].gindex; +} +int +myotf::get_glyph_used () +{ + // return mys.used; + return _buffer->in_length; +} + +myotf::myotf (FT_Face f) +{ +// nom = n; +// if (FT_Init_FreeType (&_ftlib)) +// qDebug ("oh merde"); +// if (FT_New_Face (_ftlib, nom, 0, &_face)) +// qDebug ("oh putaing"); + _face = f; + byface = true; + + hbFont.klass = NULL; /* Hope it will work without more code */ + hbFont.userData = 0; + hbFont.faceData = _face; + hbFont.x_ppem = _face->size->metrics.x_ppem; + hbFont.y_ppem = _face->size->metrics.y_ppem; + hbFont.x_scale = 0x10000;//_face->size->metrics.x_scale; + hbFont.y_scale = 0x10000;//_face->size->metrics.y_scale; + + subAlt = false; + glyphAlloc = false; + FT_ULong length = 0; + + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, NULL, &length)) + { + qDebug(QString("length of GDEF table is %1").arg(length)); + if(length > 0) + { + _memgdef.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, + (FT_Byte *) _memgdef.data (), &length); + gdefstream = new (HB_StreamRec); + gdefstream->base = (HB_Byte *) _memgdef.data (); + gdefstream->size = _memgdef.size (); + gdefstream->pos = 0; + + + HB_New_GDEF_Table (&_gdef); + if (!HB_Load_GDEF_Table (gdefstream, &_gdef)) + GDEF = 1; + else + GDEF = 0; + } + + else + GDEF = 0; + } + else + GDEF = 0; + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, NULL, &length)) + { + qDebug(QString("length of GSUB table is %1").arg(length)); + if(length > 32)//Some font files seem to have a fake table that is just 32 words long and make harbuzz confused + { + _memgsub.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, + (FT_Byte *) _memgsub.data (), &length); + gsubstream = new (HB_StreamRec); + gsubstream->base = (HB_Byte *) _memgsub.data (); + gsubstream->size = _memgsub.size (); + gsubstream->pos = 0; + + if (GDEF ? !HB_Load_GSUB_Table (gsubstream, &_gsub, _gdef, gdefstream) : + !HB_Load_GSUB_Table (gsubstream, &_gsub, NULL, NULL)) + GSUB = 1; + else + GSUB = 0; + } + else + GSUB = 0; + } + else + GSUB = 0; + // What are thes f... properties ? +// if(GSUB) +// { +// for(int i = 0; i < _gsub->LookupList.LookupCount ; i++) +// qDebug(QString("property[%1] = %2").arg(i).arg(_gsub->LookupList.Properties[i])); +// } + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, NULL, &length)) + { + qDebug(QString("length of GPOS table is %1").arg(length)); + if(length > 32) + { + _memgpos.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, + (FT_Byte *) _memgpos.data (), &length); + gposstream = new (HB_StreamRec); + gposstream->base = (HB_Byte *) _memgpos.data (); + gposstream->size = _memgpos.size (); + gposstream->pos = 0; + + if (GDEF ? !HB_Load_GPOS_Table (gposstream, &_gpos, _gdef, gdefstream) : + !HB_Load_GPOS_Table (gposstream, &_gpos, NULL, NULL)) + GPOS = 1; + else + GPOS = 0; + } + else + GPOS = 0; + } + else + GPOS = 0; + if (hb_buffer_new (&_buffer)) + qDebug ("unable to get _buffer"); +} + +myotf::myotf (QString n) +{ + byface = false; + nom = n; + if (FT_Init_FreeType (&_ftlib)) + qDebug ("oh merde"); + if (FT_New_Face (_ftlib, nom, 0, &_face)) + qDebug ("oh putaing"); + + hbFont.klass = NULL; /* Hope it will work without more code */ + hbFont.userData = 0; + hbFont.faceData = _face; + hbFont.x_ppem = _face->size->metrics.x_ppem; + hbFont.y_ppem = _face->size->metrics.y_ppem; + hbFont.x_scale = 0x10000;//_face->size->metrics.x_scale; + hbFont.y_scale = 0x10000;//_face->size->metrics.y_scale; + + subAlt = false; + glyphAlloc = false; + FT_ULong length = 0; + + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, NULL, &length)) + { + qDebug(QString("length of GDEF table is %1").arg(length)); + if(length > 0) + { + _memgdef.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GDEF"), 0, + (FT_Byte *) _memgdef.data (), &length); + gdefstream = new (HB_StreamRec); + gdefstream->base = (HB_Byte *) _memgdef.data (); + gdefstream->size = _memgdef.size (); + gdefstream->pos = 0; + + + HB_New_GDEF_Table (&_gdef); + if (!HB_Load_GDEF_Table (gdefstream, &_gdef)) + GDEF = 1; + else + GDEF = 0; + } + + else + GDEF = 0; + } + else + GDEF = 0; + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, NULL, &length)) + { + qDebug(QString("length of GSUB table is %1").arg(length)); + if(length > 32)//Some font files seem to have a fake table that is just 32 words long and make harbuzz confused + { + _memgsub.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GSUB"), 0, + (FT_Byte *) _memgsub.data (), &length); + gsubstream = new (HB_StreamRec); + gsubstream->base = (HB_Byte *) _memgsub.data (); + gsubstream->size = _memgsub.size (); + gsubstream->pos = 0; + + if (GDEF ? !HB_Load_GSUB_Table (gsubstream, &_gsub, _gdef, gdefstream) : + !HB_Load_GSUB_Table (gsubstream, &_gsub, NULL, NULL)) + GSUB = 1; + else + GSUB = 0; + } + else + GSUB = 0; + } + else + GSUB = 0; + // What are thes f... properties ? +// if(GSUB) +// { +// for(int i = 0; i < _gsub->LookupList.LookupCount ; i++) +// qDebug(QString("property[%1] = %2").arg(i).arg(_gsub->LookupList.Properties[i])); +// } + length = 0; + if (!FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, NULL, &length)) + { + qDebug(QString("length of GPOS table is %1").arg(length)); + if(length > 32) + { + _memgpos.resize (length); + FT_Load_Sfnt_Table (_face, OTF_name_tag ("GPOS"), 0, + (FT_Byte *) _memgpos.data (), &length); + gposstream = new (HB_StreamRec); + gposstream->base = (HB_Byte *) _memgpos.data (); + gposstream->size = _memgpos.size (); + gposstream->pos = 0; + + if (GDEF ? !HB_Load_GPOS_Table (gposstream, &_gpos, _gdef, gdefstream) : + !HB_Load_GPOS_Table (gposstream, &_gpos, NULL, NULL)) + GPOS = 1; + else + GPOS = 0; + } + else + GPOS = 0; + } + else + GPOS = 0; + if (hb_buffer_new (&_buffer)) + qDebug ("unable to get _buffer"); +} + +myotf::~myotf () +{ + + if (_buffer) + hb_buffer_free (_buffer); + if (GDEF) + HB_Done_GDEF_Table (_gdef); + if (GSUB) + HB_Done_GSUB_Table (_gsub); + if (GPOS) + HB_Done_GPOS_Table (_gpos); + if(!byface) + { + if (_face) + FT_Done_Face (_face); + if (_ftlib) + FT_Done_FreeType (_ftlib); + } +} + + +/// the actual function +int +myotf::procstring (QString s, QString script, QString lang, QStringList gsub, + QStringList gpos) +{ + qDebug (QString("procstring(%1, %2, %3, ...)").arg(s).arg(script).arg(lang)); + hb_buffer_clear( _buffer ); + int n = s.length (); + HB_Error error; + for (int i = 0; i < n; i++) + { + + error = hb_buffer_add_glyph (_buffer, + FT_Get_Char_Index (_face, s[i].unicode()), + 0, + 0); + qDebug(QString("adding glyph [%1] gives glyph [%2] properties [%3] cluster [%4]").arg(FT_Get_Char_Index (_face, s[i].unicode())).arg(_buffer->in_string[i].gindex).arg(_buffer->in_string[i].properties).arg(_buffer->in_string[i].cluster)); + + } + + qDebug(QString("in_string is %1 long").arg(_buffer->in_length)); + + if (gsub.count ()) + { + HB_GSUB_Clear_Features (_gsub); + set_table ("GSUB"); + set_script (script); + set_lang (lang); + + for (QStringList::iterator ife = gsub.begin (); ife != gsub.end (); + ife++) + { + HB_UShort fidx; + error = HB_GSUB_Select_Feature (_gsub, + OTF_name_tag (*ife), + curScript, curLang, &fidx); + if(!error) + { + HB_GSUB_Add_Feature (_gsub, fidx, 1); + qDebug(QString("GSUB [%2] feature.lookupcount = %1").arg(_gsub->FeatureList.FeatureRecord[fidx].Feature.LookupListCount).arg(*ife)); + } + else + qDebug(QString("adding gsub feature [%1] failed : %2").arg(*ife).arg(error)); + } + + error = HB_GSUB_Apply_String (_gsub, _buffer); + if(error)qDebug(QString("applying gsub features to string \"%1\" returned %2").arg(s).arg(error)); + + } + if (gpos.count ()) + { + HB_GPOS_Clear_Features (_gpos); + set_table ("GPOS"); + set_script (script); + set_lang (lang); + + for (QStringList::iterator ife = gpos.begin (); ife != gpos.end (); + ife++) + { + HB_UShort fidx; + error = HB_GPOS_Select_Feature (_gpos, + OTF_name_tag (*ife), + curScript, curLang, &fidx); + if(!error) + { + HB_GPOS_Add_Feature (_gpos, fidx, 1); + qDebug(QString("GPOS [%2] feature.lookupcount = %1").arg(_gpos->FeatureList.FeatureRecord[fidx].Feature.LookupListCount).arg(*ife)); + } + else + qDebug(QString("adding gsub feature [%1] failed : %2").arg(*ife).arg(error)); + } + if(_buffer->in_length > 0) memset(_buffer->positions, 0, _buffer->in_length*sizeof(HB_PositionRec)); + error = HB_GPOS_Apply_String (&hbFont, _gpos, FT_LOAD_NO_SCALE, _buffer, + /*while dvi is true font klass is not used */ true, + /*r2l */ true); + if(error)qDebug(QString("applying gpos features to string \"%1\" returned %2").arg(s).arg(error)); + + } + + + return _buffer->in_length; +} + + + + + + +QStringList +myotf::get_tables () +{ + QStringList ret; + + // if (GDEF) + // ret.insert (ret.end (), "GDEF"); + if (GPOS) + ret.insert (ret.end (), "GPOS"); + if (GSUB) + ret.insert (ret.end (), "GSUB"); + + return ret; +} + +void +myotf::set_table (QString s) +{ + curTable = s; +} + +QStringList +myotf::get_scripts () +{ + qDebug("myotf::get_scripts ()"); + QStringList ret; + + if (curTable == "GSUB") + { + HB_UInt *taglist; + if (HB_GSUB_Query_Scripts (_gsub, &taglist)) + qDebug ("error HB_GSUB_Query_Scripts"); + while (*taglist) + { + qDebug(QString("script [%1]").arg(OTF_tag_name (*taglist))); + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + if (HB_GPOS_Query_Scripts (_gpos, &taglist)) + qDebug ("error HB_GPOS_Query_Scripts"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + } + return ret; + +} + +void +myotf::set_script (QString s) +{ + qDebug(QString("set_script (%1)").arg(s)); + curScriptName = s; + if (curTable == "GSUB") + { + if (HB_GSUB_Select_Script + (_gsub, OTF_name_tag (curScriptName), &curScript)) + qDebug (QString("Unable to set script index for %1").arg( curScriptName)); + } + if (curTable == "GPOS") + { + if (HB_GPOS_Select_Script + (_gpos, OTF_name_tag (curScriptName), &curScript)) + qDebug ("Unable to set script index"); + } +} + + +QStringList +myotf::get_langs () +{ + QStringList ret; + + if (curTable == "GSUB") + { + + HB_UInt *taglist; + if (HB_GSUB_Query_Languages (_gsub, curScript, &taglist)) + qDebug ("error HB_GSUB_Query_Langs"); + while (*taglist) + { + qDebug(QString("lang [%1]").arg(OTF_tag_name (*taglist))); + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + if (HB_GPOS_Query_Languages (_gpos, curScript, &taglist)) + qDebug ("error HB_GPOS_Query_Langs"); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + + return ret; +} + +void +myotf::set_lang (QString s) +{ + qDebug(QString("set_lang (%1)").arg(s)); + if (s == "default" || s == "dflt" || s.isEmpty ()) + { + curLangName = "dflt"; + curLang = HB_DEFAULT_LANGUAGE; + return; + } + HB_Error error; + curLangName = s; + if (curTable == "GSUB") + { + error = HB_GSUB_Select_Language (_gsub, + OTF_name_tag (curLangName), + curScript, + &curLang, + &curLangReq); + if(error) + qDebug (QString("Unable to set lang index due to error %1").arg(error)); + } + if (curTable == "GPOS") + { + error = HB_GPOS_Select_Language(_gpos, OTF_name_tag (curLangName),curScript, &curLang, &curLangReq); + if(error) + qDebug (QString("Unable to set lang index due to error %1").arg(error)); + } + +} + + +QStringList +myotf::get_features (bool required ) +{ + QStringList ret; + + if (curTable == "GSUB") + { + + HB_UInt *taglist; + required ? HB_GSUB_Query_Features (_gsub, curScript, curLangReq, + &taglist) : + HB_GSUB_Query_Features (_gsub, curScript, curLang, &taglist); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + + } + if (curTable == "GPOS") + { + + HB_UInt *taglist; + required ? HB_GPOS_Query_Features (_gpos, curScript, curLangReq, + &taglist) : + HB_GPOS_Query_Features (_gpos, curScript, curLang, &taglist); + while (*taglist) + { + ret.append (OTF_tag_name (*taglist)); + ++taglist; + } + + } + return ret; +} + +void +myotf::set_features (QStringList ls) +{ + curFeatures = ls; +} + +void dump_pos(HB_PositionRec p) +{ + qDebug(QString("xpos = %1 | ypos = %2 | xadv = %3 | yadv = %4 | %5 | back = %6 ").arg(p.x_pos).arg(p.y_pos).arg(p.x_advance).arg(p.y_advance).arg(p.new_advance ? "NEW" : "NOT_NEW").arg(p.back)); +} + +posglyph myotf::get_position (int g) +{ + posglyph + ret; + if (g > _buffer->in_length) + return ret; + + dump_pos(_buffer->positions[g]); + if (_buffer->positions[g].new_advance) + { + ret.Xadvance = (double) _buffer->positions[g].x_advance; + ret.Yadvance = (double) _buffer->positions[g].y_advance; + } + else + { + FT_GlyphSlot + slot = _face->glyph; + if (!FT_Load_Glyph + (_face, _buffer->in_string[g].gindex, FT_LOAD_NO_SCALE)) + { + ret.Xadvance = + (double) (_buffer->positions[g].x_advance + slot->advance.x); + ret.Yadvance = + (double) (_buffer->positions[g].y_advance + slot->advance.y); + } + + } + + + return ret; +} Index: scribus/fonts/myotf.h =================================================================== RCS file: scribus/fonts/myotf.h diff -N scribus/fonts/myotf.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/myotf.h 9 Apr 2007 15:39:04 -0000 @@ -0,0 +1,115 @@ +// myotf.h + +#ifndef WRAPLIBOTF +#define WRAPLIBOTF + +#include <ft2build.h> +#include FT_FREETYPE_H +#include FT_TRUETYPE_TABLES_H + +extern "C" +{ +// #include <otf.h> +// #include <stdlib.h> +#include "harfbuzz.h" +} + +#include <iostream> +#include <iomanip> + +#include <qstring.h> +#include <qstringlist.h> + +using namespace std; + +struct posglyph +{ + double Xposition; + double Yposition; + double Xadvance; + double Yadvance; + double xadvance(){return Xadvance;} + double yadvance(){return Yadvance;} + double xposition(){return Xposition;} + double yposition(){return Yposition;} +}; + +class myotf +{ + public: + myotf (QString n); + myotf (FT_Face); + ~myotf (); + + private: + QString nom; + bool byface; + //OTF *my; + FT_Library _ftlib; + FT_Face _face; + HB_FontRec hbFont; + QByteArray _memgdef,_memgsub,_memgpos; + HB_StreamRec* gdefstream; + HB_StreamRec* gsubstream; + HB_StreamRec* gposstream; + HB_GDEF _gdef; + HB_GSUB _gsub; + HB_GPOS _gpos; + + //OTF_GlyphString mys; + HB_Buffer _buffer; + + + bool subAlt; + bool glyphAlloc; + + int head, name, cmap, GDEF, GSUB, GPOS; + +public: +// OTF_GlyphString * otfString() {return &mys;} +// int unicode(int gid){ return OTF_get_unicode(my, gid);} + int get_glyph( int index);//{return _buffer->out_string[index].gindex;} + QString curTable; + HB_UShort curScript, curLang, curLangReq; + QString curScriptName, curLangName; + QStringList curFeatures; + +/* + * These members functions apply features currently set + */ + int procstring (QString ); + int procstring (); + int procstring (QString s, QString script, QString lang, QStringList gsub, QStringList gpos); +/* + * These functions give access to informations contained in the fontfile + */ + QStringList get_tables (); + QStringList get_scripts (); + QStringList get_langs (); + QStringList get_features (bool required=false); +/* + * These allow to set up the features ( Tab -> Scr -> Lan -> Fea ) + */ + void set_table (QString); + void set_script (QString); + void set_lang (QString); + void set_features (QStringList); + void set_subalt (bool); +/* + * I can't remember what this so important method is expected to achieve ! + */ + int get_position_type (int); + /* + * for the moment, it just does nothing. Because I have no idea + * of which sruct can be the target of this function.Nevertheless + * I'm clearly aware that's the key function, it's the reason why + * i put this apart from procstring(). + * The argument is the number of the glyph + */ + + posglyph get_position(int); + int get_glyph_used(); + +}; + +#endif Index: scribus/fonts/opentype_langmap.txt =================================================================== RCS file: scribus/fonts/opentype_langmap.txt diff -N scribus/fonts/opentype_langmap.txt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scribus/fonts/opentype_langmap.txt 9 Apr 2007 15:39:04 -0000 @@ -0,0 +1,2 @@ +French:latn:FRA +English:latn:ENG Index: scribus/fonts/scface.h =================================================================== RCS file: /cvs/Scribus/scribus/fonts/Attic/scface.h,v retrieving revision 1.1.2.11 diff -u -8 -p -r1.1.2.11 scface.h --- scribus/fonts/scface.h 25 Mar 2007 22:34:32 -0000 1.1.2.11 +++ scribus/fonts/scface.h 9 Apr 2007 15:39:05 -0000 @@ -16,25 +16,32 @@ virtual: dispatch to constituents, #include <qstring.h> //#include <qvector.h> #include <qmap.h> //#include <qarray.h> #include <utility> #include "fpointarray.h" +//TEST libotf + +#include "myotf.h" struct GlyphMetrics { double width; double ascent; double descent; }; - +struct OtFeatures { + QStringList gsub; + QStringList gpos; + QStringList all() const {return (gsub + gpos);} +}; /*! \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. @@ -109,16 +116,23 @@ public: bool usable; bool embedPs; bool subset; bool isStroked; bool isFixedPitch; bool hasNames; uint maxGlyph; + mutable double m_uniEM; + protected : + mutable myotf * _otf; + mutable QMap < QString, OtFeatures > features; // form is < scrilang , [gsublist,gposlist] > + public: + myotf * otf() const { return _otf;} + virtual QString otfLang(QString s) const {return s;} ScFaceData(); virtual ~ScFaceData() { }; protected: friend class ScFace; Status cachedStatus; @@ -145,16 +159,17 @@ public: m_cMap.clear(); status = ScFace::UNKNOWN; } virtual void loadGlyph(uint /*gl*/) const {} // dummy implementations + virtual double uniEM() const {return m_uniEM;} virtual double ascent(double sz) const { return sz; } virtual QString ascentAsString() const { return "0" ; } virtual QString descentAsString() const { return "0"; } virtual QString capHeightAsString() const { return "0"; } virtual QString FontBBoxAsString() const { return "0 0 0 0"; } virtual QString ItalicAngleAsString() const { return "0"; } virtual double descent(double /*sz*/) const { return 0.0; } virtual double xHeight(double sz) const { return sz; } @@ -166,16 +181,19 @@ public: 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<uint, std::pair<QChar, QString> >& gList) const; + + virtual QString otfied(QString s, QString l, QStringList f) const {return s;} + // 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; }; @@ -293,16 +311,17 @@ public: /// 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 unitsEM () const {return m->uniEM();} double ascent(double sz=1.0) const { return m->ascent(sz); } QString ascentAsString() const { return m->ascentAsString() ; } QString descentAsString() const { return m->descentAsString() ; } QString capHeightAsString() const { return m->capHeightAsString() ; } QString FontBBoxAsString() const { return m->FontBBoxAsString() ; } QString ItalicAngleAsString() const { return m->ItalicAngleAsString() ; } double descent(double sz=1.0) const { return m->descent(sz); } double xHeight(double sz=1.0) const { return m->xHeight(sz); } @@ -359,16 +378,23 @@ public: 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; } + //TEST libotf + QString otfied (QString s, QString l, QStringList f) const { return m->otfied(s,l,f); } + myotf * otf() const { return m->otf();} + QString otfLang(QString s) const { return m->otfLang(s); } + QStringList gsubFeatures(QString lang) const { return m->features[lang].gsub; } + QStringList gposFeatures(QString lang) const { return m->features[lang].gpos; } + QStringList allFeatures(QString lang) const { return m->features[lang].all(); } private: friend class SCFonts; ScFace(ScFaceData* md); ScFaceData* m; QString replacedName; QString replacedInDoc; Index: scribus/styles/charstyle.attrdefs.cxx =================================================================== RCS file: /cvs/Scribus/scribus/styles/Attic/charstyle.attrdefs.cxx,v retrieving revision 1.1.2.3 diff -u -8 -p -r1.1.2.3 charstyle.attrdefs.cxx --- scribus/styles/charstyle.attrdefs.cxx 25 Jan 2007 15:29:08 -0000 1.1.2.3 +++ scribus/styles/charstyle.attrdefs.cxx 9 Apr 2007 15:39:09 -0000 @@ -30,9 +30,10 @@ ATTRDEF(int, underlineOffset, UnderlineO ATTRDEF(int, underlineWidth, UnderlineWidth, 0) ATTRDEF(int, strikethruOffset, StrikethruOffset, 0) ATTRDEF(int, strikethruWidth, StrikethruWidth, 0) ATTRDEF(int, tracking, Tracking, 0) ATTRDEF(QString, fillColor, FillColor, "undef") ATTRDEF(QString, strokeColor, StrokeColor, "Black") ATTRDEF(QString, language, Language, "") ATTRDEF(ScFace, font, Font, ScFace::none()) +ATTRDEF(QStringList, fontFeatures, FontFeatures, "") // Odd but "QStringList::QStringList ( const QString & i )" |
|
harfbuzz-patch-3.diff Integrates OpenType support in charstyle infrastructure. |
|
So, this never got merged? |
|
avox, what is the status of this? |
|
What is the status of this ?? |
|
How can this now fit in to the box model ? |
Date Modified | Username | Field | Change |
---|---|---|---|
2006-11-29 14:11 | pierremarchand | New Issue | |
2006-11-29 14:11 | pierremarchand | File Added: ftface.diff | |
2006-11-29 22:31 | cbradney | File Deleted: ftface.diff | |
2006-11-29 22:33 | pierremarchand | File Added: ftface.diff | |
2006-11-29 22:37 |
|
Status | new => assigned |
2006-11-29 22:37 |
|
Assigned To | => avox |
2006-11-29 23:23 | pierremarchand | File Added: ftface2.diff | |
2006-11-29 23:34 | pierremarchand | Note Added: 0013655 | |
2006-11-30 08:22 | avox | Note Added: 0013656 | |
2006-11-30 10:34 | cbradney | Note Added: 0013663 | |
2006-11-30 11:20 | avox | Note Added: 0013670 | |
2006-11-30 11:43 | christoph_s | Note Added: 0013671 | |
2006-11-30 13:37 | avox | Note Added: 0013672 | |
2006-11-30 15:32 | christoph_s | Note Added: 0013673 | |
2006-12-01 07:19 | PLucAuclair | Note Added: 0013686 | |
2006-12-01 07:22 | PLucAuclair | Note Edited: 0013686 | |
2006-12-01 18:21 | pierremarchand | Note Added: 0013702 | |
2006-12-05 13:01 | pierremarchand | Note Added: 0013773 | |
2006-12-05 13:09 | pierremarchand | Note Added: 0013774 | |
2006-12-05 16:33 | pierremarchand | Note Added: 0013781 | |
2006-12-06 10:24 | avox | Note Added: 0013792 | |
2006-12-06 10:39 | avox | Note Edited: 0013792 | |
2006-12-06 10:40 | avox | Note Edited: 0013792 | |
2006-12-06 11:08 | avox | Note Added: 0013793 | |
2006-12-06 22:58 | pierremarchand | File Added: vface.h | |
2006-12-06 22:58 | pierremarchand | File Added: vface.cpp | |
2006-12-06 23:17 | pierremarchand | Note Added: 0013806 | |
2006-12-12 16:14 | pierremarchand | File Added: vface-first-result.png | |
2006-12-12 16:18 | pierremarchand | Note Added: 0013884 | |
2006-12-12 17:19 | avox | Note Added: 0013886 | |
2006-12-12 19:16 | pierremarchand | Note Added: 0013887 | |
2006-12-12 19:29 | pierremarchand | File Added: vface-0.0.tar.gz | |
2006-12-13 14:09 | pierremarchand | Note Added: 0013897 | |
2006-12-13 14:12 | pierremarchand | File Added: vface2.png | |
2006-12-13 19:46 | pierremarchand | File Added: vface3.png | |
2006-12-13 20:39 | pierremarchand | File Added: vface-0.0.0.tar.gz | |
2006-12-13 20:45 |
|
File Deleted: vface-0.0.0.tar.gz | |
2006-12-13 20:46 | pierremarchand | File Added: vface-0.0.0.tar.gz | |
2006-12-13 20:50 | pierremarchand | Note Added: 0013907 | |
2006-12-13 23:32 | pierremarchand | File Added: vface-first-print.ps | |
2006-12-13 23:35 | pierremarchand | Note Added: 0013912 | |
2006-12-14 22:31 | pierremarchand | Note Added: 0013925 | |
2006-12-14 22:33 | pierremarchand | File Added: userfontressource.ufr | |
2006-12-15 20:33 | pierremarchand | File Added: vface4.png | |
2006-12-15 20:43 | pierremarchand | File Added: vface-0.0.0.0.tar.gz | |
2006-12-16 14:59 | pierremarchand | File Added: vface-0.0.0.1.tar.gz | |
2006-12-16 15:04 | pierremarchand | Note Added: 0013956 | |
2006-12-16 15:06 | pierremarchand | Note Edited: 0013956 | |
2006-12-21 23:35 | avox | Relationship added | has duplicate 0001680 |
2007-03-17 12:50 | pierremarchand | Note Added: 0015548 | |
2007-03-17 12:51 | pierremarchand | File Added: scribus-otf.png | |
2007-03-17 12:54 | pierremarchand | File Added: myotf-patch.diff | |
2007-03-17 16:26 | avox | Note Added: 0015549 | |
2007-03-17 16:57 | pierremarchand | Note Added: 0015550 | |
2007-03-19 20:43 | pierremarchand | File Added: myotf-patch-2.diff | |
2007-03-20 09:08 | pierremarchand | File Added: myotf-patch-3.diff | |
2007-03-21 14:42 | pierremarchand | File Added: myotf-patch-4.diff | |
2007-03-21 15:16 | pierremarchand | Note Added: 0015581 | |
2007-04-06 19:16 | pierremarchand | File Added: harfbuzz-patch-0.diff | |
2007-04-07 10:04 | pierremarchand | File Added: harfbuzz-patch-1.diff | |
2007-04-07 10:05 | pierremarchand | Note Added: 0015781 | |
2007-04-07 19:00 | pierremarchand | File Added: harfbuzz-patch-2.diff | |
2007-04-07 19:01 | pierremarchand | Note Added: 0015790 | |
2007-04-09 15:21 | pierremarchand | File Added: scribus-otf11.png | |
2007-04-09 15:40 | pierremarchand | File Added: harfbuzz-patch-3.diff | |
2007-04-09 15:41 | pierremarchand | Note Added: 0015829 | |
2009-07-27 15:52 |
|
Relationship added | related to 0008305 |
2010-02-07 15:43 | alexandre | Note Added: 0023219 | |
2015-08-25 16:36 | Kunda | Note Added: 0036086 | |
2015-08-26 11:20 | saba2277 | Note Added: 0036087 | |
2016-03-07 12:35 | Kunda | Note Added: 0039021 | |
2016-04-04 03:15 | Kunda | Tag Attached: kerning |