View Issue Details

IDProjectCategoryView StatusLast Update
0004645ScribusFontspublic2016-04-04 03:15
Reporterpierremarchand Assigned Toavox  
PrioritynormalSeverityfeatureReproducibilityalways
Status assignedResolutionopen 
OSlinux 
Product Version1.3.4cvs 
Summary0004645: Fine tune kerning pairs
DescriptionAn experimental patch related to bypass fonts files metrics kerning pairs without edit the font file.
Tagskerning
Patch

Relationships

has duplicate 0001680 closedavox Automatic Kerning by user-defined pairs wanted 
related to 0008305 closedjghali Ligature support 

Activities

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;
+
 	
 };
 
ftface.diff (5,498 bytes)   

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;
+
 	
 };
 
ftface2.diff (6,116 bytes)   

pierremarchand

2006-11-29 23:34

reporter   ~0013655

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 ?

avox

2006-11-30 08:22

updater   ~0013656

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?

cbradney

2006-11-30 10:34

administrator   ~0013663

Please do not put this in 1.3.4. We do not need more to debug.

avox

2006-11-30 11:20

updater   ~0013670

No, I didnt plan to do it in 1.3.4 (didnt we have a feature stop? :-) )

christoph_s

2006-11-30 11:43

developer   ~0013671

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?

avox

2006-11-30 13:37

updater   ~0013672

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?

christoph_s

2006-11-30 15:32

developer   ~0013673

>>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.

PLucAuclair

2006-12-01 07:19

reporter   ~0013686

Last edited: 2006-12-01 07:22

>> 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.

pierremarchand

2006-12-01 18:21

reporter   ~0013702

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 |

pierremarchand

2006-12-05 13:01

reporter   ~0013773

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.

pierremarchand

2006-12-05 13:09

reporter   ~0013774

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 ?

pierremarchand

2006-12-05 16:33

reporter   ~0013781

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

avox

2006-12-06 10:24

updater   ~0013792

Last edited: 2006-12-06 10:40

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

avox

2006-12-06 11:08

updater   ~0013793

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	

vface.h (3,246 bytes)   

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];
}
*/


vface.cpp (13,383 bytes)   

pierremarchand

2006-12-06 23:17

reporter   ~0013806

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

 

vface-first-result.png (32,887 bytes)   
vface-first-result.png (32,887 bytes)   

pierremarchand

2006-12-12 16:18

reporter   ~0013884

I get some bad headache,and the first visual result. It's not very impressive but I put it here to givee an idea.

avox

2006-12-12 17:19

updater   ~0013886

cool.
did you manually select outline style and large spacing?

pierremarchand

2006-12-12 19:16

reporter   ~0013887

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

 

vface-0.0.tar.gz (6,566 bytes)

pierremarchand

2006-12-13 14:09

reporter   ~0013897

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

 

vface2.png (26,637 bytes)   
vface2.png (26,637 bytes)   

2006-12-13 19:46

 

vface3.png (41,363 bytes)   
vface3.png (41,363 bytes)   

2006-12-13 20:46

 

vface-0.0.0.tar.gz (9,739 bytes)

pierremarchand

2006-12-13 20:50

reporter   ~0013907

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

 

vface-first-print.ps (104,917 bytes)

pierremarchand

2006-12-13 23:35

reporter   ~0013912

PDF export still doesn't work, but printing seems to be ok. Next next step soon !

pierremarchand

2006-12-14 22:31

reporter   ~0013925

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

 

userfontressource.ufr (4,403 bytes)

2006-12-15 20:33

 

vface4.png (10,415 bytes)   
vface4.png (10,415 bytes)   

2006-12-15 20:43

 

vface-0.0.0.0.tar.gz (9,987 bytes)

2006-12-16 14:59

 

vface-0.0.0.1.tar.gz (11,920 bytes)

pierremarchand

2006-12-16 15:04

reporter   ~0013956

Last edited: 2006-12-16 15:06

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.

pierremarchand

2007-03-17 12:50

reporter   ~0015548

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

 

scribus-otf.png (29,560 bytes)   
scribus-otf.png (29,560 bytes)   

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;
myotf-patch.diff (23,567 bytes)   

avox

2007-03-17 16:26

updater   ~0015549

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.

pierremarchand

2007-03-17 16:57

reporter   ~0015550

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;
myotf-patch-2.diff (36,277 bytes)   

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;
myotf-patch-3.diff (37,774 bytes)   

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 (42,558 bytes)   

pierremarchand

2007-03-21 15:16

reporter   ~0015581

-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;
harfbuzz-patch-0.diff (40,337 bytes)   

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 (40,558 bytes)   

pierremarchand

2007-04-07 10:05

reporter   ~0015781

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 (42,860 bytes)   

pierremarchand

2007-04-07 19:01

reporter   ~0015790

harfbuzz-patch-2.diff

export to pdf and print seems to work, even for pagenumbers !

2007-04-09 15:21

 

scribus-otf11.png (97,676 bytes)   
scribus-otf11.png (97,676 bytes)   

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 (63,217 bytes)   

pierremarchand

2007-04-09 15:41

reporter   ~0015829

harfbuzz-patch-3.diff

Integrates OpenType support in charstyle infrastructure.

alexandre

2010-02-07 15:43

developer   ~0023219

So, this never got merged?

Kunda

2015-08-25 16:36

updater   ~0036086

avox, what is the status of this?

saba2277

2015-08-26 11:20

reporter   ~0036087

What is the status of this ??

Kunda

2016-03-07 12:35

updater   ~0039021

How can this now fit in to the box model ?

Issue History

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 plinnell Status new => assigned
2006-11-29 22:37 plinnell 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 plinnell 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 plinnell 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