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