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(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 #include +#include +#include + #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(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 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 +//#include + +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 +#include FT_FREETYPE_H +#include FT_TRUETYPE_TABLES_H + +extern "C" +{ +// #include +// #include +#include "harfbuzz.h" +} + +#include +#include + +#include +#include + +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 //#include #include //#include #include #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 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 >& 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;