karbon

vtext.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002, The Karbon Developers
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <qdom.h>
00021 #include <qfile.h>
00022 
00023 #include <kdebug.h>
00024 #include <KoPoint.h>
00025 #include <KoRect.h>
00026 
00027 #include "vpath.h"
00028 #include "vtext.h"
00029 #include "vtext_iface.h"
00030 #include "vstroke.h"
00031 #include "vfill.h"
00032 #include "vvisitor.h"
00033 #include "vsegment.h"
00034 #include "vgroup.h"
00035 #include "vpainter.h"
00036 #include "commands/vtransformcmd.h"
00037 
00038 #ifdef HAVE_KARBONTEXT
00039 
00040 #include <ft2build.h>
00041 #include <fontconfig/fontconfig.h>
00042 
00043 
00044 #include FT_FREETYPE_H
00045 #include FT_OUTLINE_H
00046 #include FT_GLYPH_H
00047 
00048 #define FT_TOFLOAT(x) ((x) * (1.0 / 64.0))
00049 #define FT_FROMFLOAT(x) ((int) floor ((x) * 64.0 + 0.5))
00050 
00051 
00052 // Trace routines for ttf / ps font -> VSubpath
00053 
00054 int traceMoveto( FT_Vector *to, VPath *composite )
00055 {
00056     double tox = ( to->x / 64.0 );
00057     double toy = ( -to->y / 64.0 );
00058 
00059     //QString add = "M" + QString::number(tox) + "," + QString::number(toy) + " ";
00060     //kdDebug(38000) << add.latin1() << endl;
00061     composite->moveTo( KoPoint( tox, toy ) );
00062 
00063     return 0;
00064 }
00065 
00066 int traceLineto( FT_Vector *to, VPath *composite )
00067 {
00068     double tox = ( to->x / 64.0 );
00069     double toy = ( -to->y / 64.0 );
00070 
00071     //QString add = "L" + QString::number(tox) + "," + QString::number(toy) + " ";
00072     //kdDebug(38000) << add.latin1() << endl;
00073 
00074     composite->lineTo( KoPoint( tox, toy ) );
00075 
00076     return 0;
00077 }
00078 
00079 int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, VPath *composite )
00080 {
00081     double x1 = ( control->x / 64.0 );
00082     double y1 = ( -control->y / 64.0 );
00083     double x2 = ( to->x / 64.0 );
00084     double y2 = ( -to->y / 64.0 );
00085 
00086     //QString add = "Q" + QString::number(x1) + "," + QString::number(y1) + "," + QString::number(x2) + "," + QString::number(y2) + " ";
00087     //kdDebug(38000) << add.latin1() << endl;
00088     composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x2, y2 ) );
00089     //composite->curve2To( KoPoint( x1, y1 ), KoPoint( x2, y2 ) );
00090 
00091     return 0;
00092 }
00093 
00094 int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, VPath *composite )
00095 {
00096     double x1 = ( p->x / 64.0 );
00097     double y1 = ( -p->y / 64.0 );
00098     double x2 = ( q->x / 64.0 );
00099     double y2 = ( -q->y / 64.0 );
00100     double x3 = ( to->x / 64.0 );
00101     double y3 = ( -to->y / 64.0 );
00102 
00103     //QString add = "C" + QString::number(x1) + "," + QString::number(y1) + "," + QString::number(x2) + "," + QString::number(y2) + "," + QString::number(x3) + "," + QString::number(y3);
00104     //kdDebug(38000) << add.latin1() << endl;
00105 
00106     composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x3, y3 ) );
00107 
00108     return 0;
00109 }
00110 
00111 FT_Outline_Funcs OutlineMethods =
00112 {
00113     (FT_Outline_MoveTo_Func) traceMoveto,
00114     (FT_Outline_LineTo_Func) traceLineto,
00115     (FT_Outline_ConicTo_Func) traceQuadraticBezier,
00116     (FT_Outline_CubicTo_Func) traceCubicBezier,
00117     0,
00118     0
00119 };
00120 
00121 #endif // HAVE_KARBONTEXT
00122 
00123 VText::VText( VObject* parent, VState state )
00124     : VObject( parent, state ), m_basePath( 0L )
00125 {
00126     m_glyphs.setAutoDelete( true );
00127     m_boundingBoxIsInvalid = true;
00128     m_stroke = new VStroke( this );
00129     m_fill = new VFill();
00130     m_position          = (VText::Position)0;
00131     m_alignment         = (VText::Alignment)0;
00132     m_shadow            = false;
00133     m_translucentShadow = false;
00134     m_shadowAngle       = 0;
00135     m_shadowDistance    = 0;
00136     m_offset            = 0.0;
00137 }
00138 
00139 
00140 VText::VText( const QFont &font, const VSubpath& basePath, Position position, Alignment alignment, const QString& text )
00141     : VObject( 0L ), m_font( font ), m_basePath( basePath ), m_position( position ), m_alignment( alignment ), m_text( text )
00142 {
00143     m_glyphs.setAutoDelete( true );
00144     m_boundingBoxIsInvalid = true;
00145     m_stroke = new VStroke( this );
00146     m_fill = new VFill();
00147     m_offset = 0.0;
00148 }
00149 
00150 VText::VText( const VText& text )
00151     : VObject( text ), m_font( text.m_font ), m_basePath( text.m_basePath ), m_position( text.m_position ), m_alignment( text.m_alignment ), m_text( text.m_text ), m_shadow( text.m_shadow ), m_translucentShadow( text.m_translucentShadow ), m_shadowDistance( text.m_shadowDistance ), m_shadowAngle( text.m_shadowAngle ), m_offset( text.m_offset )
00152 {
00153     m_stroke = new VStroke( *text.m_stroke );
00154     m_stroke->setParent( this );
00155     m_fill = new VFill( *text.m_fill );
00156 
00157     // copy glyphs
00158     VPathListIterator itr( text.m_glyphs );
00159     for( ; itr.current() ; ++itr )
00160     {
00161         VPath* c = itr.current()->clone();
00162         c->setParent( this );
00163         m_glyphs.append( c );
00164     }
00165 
00166     m_boundingBoxIsInvalid = true;
00167 }
00168 
00169 VText::~VText()
00170 {
00171 }
00172 
00173 DCOPObject* VText::dcopObject()
00174 {
00175     if( !m_dcop )
00176         m_dcop = new VTextIface( this );
00177 
00178     return m_dcop;
00179 }
00180 
00181 
00182 void
00183 VText::draw( VPainter* painter, const KoRect* /*rect*/ ) const
00184 {
00185     if(
00186         state() == deleted ||
00187         state() == hidden ||
00188         state() == hidden_locked )
00189     {
00190         return;
00191     }
00192 
00193     painter->save();
00194 
00195     VPathListIterator itr( m_glyphs );
00196 
00197     if( state() != edit )
00198     {
00199         // paint fill:
00200         painter->newPath();
00201 
00202         if ( m_shadow )
00203         {
00204             VColor color;
00205             if ( m_translucentShadow )
00206             {
00207                 color.set( 0., 0., 0. );
00208                 color.setOpacity( .3 );
00209             }
00210             else
00211             {
00212                 color.set( .3, .3, .3 );
00213                 color.setOpacity( 1. );
00214             }
00215             int shadowDx = int( m_shadowDistance * cos( m_shadowAngle / 360. * 6.2832 ) );
00216             int shadowDy = int( m_shadowDistance * sin( m_shadowAngle / 360. * 6.2832 ) );
00217 
00218             VTransformCmd trafo( 0L, QWMatrix() );
00219             for( itr.toFirst(); itr.current(); ++itr )
00220             {
00221                 trafo.setMatrix( QWMatrix( 1, 0, 0, 1, shadowDx, shadowDy ) );
00222                 trafo.visit( *( itr.current() ) );
00223                 itr.current()->setFill( VFill( color ) );
00224                 itr.current()->setStroke( VStroke( color ) );
00225                 itr.current()->draw( painter );
00226                 trafo.setMatrix( QWMatrix( 1, 0, 0, 1, -shadowDx, -shadowDy ) );
00227                 trafo.visit( *( itr.current() ) );
00228             }
00229         }
00230 
00231         for( itr.toFirst(); itr.current(); ++itr )
00232         {
00233             itr.current()->setFill( *m_fill );
00234             itr.current()->setStroke( *m_stroke );
00235             itr.current()->draw( painter );
00236         }
00237     }
00238 
00239     // draw simplistic contour:
00240     if( state() == edit )//|| state() == selected )
00241     {
00242         painter->newPath();
00243         painter->setRasterOp( Qt::XorROP );
00244         painter->setPen( Qt::yellow );
00245         painter->setBrush( Qt::NoBrush );
00246 
00247         for( itr.toFirst(); itr.current(); ++itr )
00248             itr.current()->draw( painter );
00249 
00250         painter->strokePath();
00251     }
00252 
00253     painter->restore();
00254 }
00255 
00256 const KoRect&
00257 VText::boundingBox() const
00258 {
00259     if( m_boundingBoxIsInvalid )
00260     {
00261         VPathListIterator itr( m_glyphs );
00262         itr.toFirst();
00263         // clear:
00264         m_boundingBox = itr.current() ? itr.current()->boundingBox() : KoRect();
00265         for( ++itr; itr.current(); ++itr )
00266             if( !itr.current()->boundingBox().isEmpty() )
00267                 m_boundingBox |= itr.current()->boundingBox();
00268 
00269         // take line width into account:
00270         m_boundingBox.setCoords(
00271             m_boundingBox.left()   - 0.5 * stroke()->lineWidth(),
00272             m_boundingBox.top()    - 0.5 * stroke()->lineWidth(),
00273             m_boundingBox.right()  + 0.5 * stroke()->lineWidth(),
00274             m_boundingBox.bottom() + 0.5 * stroke()->lineWidth() );
00275 
00276         m_boundingBoxIsInvalid = false;
00277     }
00278 
00279     return m_boundingBox;
00280 }
00281 
00282 VText*
00283 VText::clone() const
00284 {
00285     return new VText( *this );
00286 }
00287 
00288 VGroup* VText::toVGroup() const
00289 {
00290     VGroup* group = new VGroup( parent() );
00291 
00292     VPathListIterator itr( m_glyphs );
00293     for( itr.toFirst(); itr.current(); ++itr )
00294     {
00295         VPath* c = itr.current()->clone();
00296         c->setParent( group );
00297         group->append( c );
00298     }
00299 
00300     group->setFill( *m_fill );
00301     group->setStroke( *m_stroke );
00302 
00303     return group;
00304 } // VText::toVGroup
00305 
00306 void
00307 VText::save( QDomElement& element ) const
00308 {
00309     if( state() != deleted )
00310     {
00311         QDomElement me = element.ownerDocument().createElement( "TEXT" );
00312 
00313         VPath path( 0L );
00314         path.combinePath( m_basePath );
00315         path.save( me );
00316 
00317         VObject::save( me );
00318 
00319         // save font properties
00320         me.setAttribute( "text",                m_text );
00321         me.setAttribute( "family",              m_font.family() );
00322         me.setAttribute( "size",                m_font.pointSize() );
00323         me.setAttribute( "italic",              m_font.italic() );
00324         me.setAttribute( "bold",                m_font.bold() );
00325         me.setAttribute( "position",            m_position );
00326         me.setAttribute( "alignment",           m_alignment );
00327         me.setAttribute( "shadow",              m_shadow );
00328         me.setAttribute( "translucentshadow",   m_translucentShadow );
00329         me.setAttribute( "shadowangle",         m_shadowAngle );
00330         me.setAttribute( "shadowdist",          m_shadowDistance );
00331         me.setAttribute( "offset",              m_offset );
00332         element.appendChild( me );
00333 
00334         // save all glyphs / paths
00335         VPathListIterator itr = m_glyphs;
00336         for( itr.toFirst(); itr.current(); ++itr )
00337             itr.current()->save( me );
00338     }
00339 }
00340 
00341 void
00342 VText::load( const QDomElement& element )
00343 {
00344     m_glyphs.clear();
00345 
00346     m_font.setFamily( element.attribute( "family", "Times" ) );
00347     m_font.setPointSize( element.attribute( "size", "12" ).toInt() );
00348     m_font.setItalic( element.attribute( "italic" ).toInt() == 1 );
00349     m_font.setWeight( QFont::Normal );
00350     m_font.setBold( element.attribute( "bold" ).toInt() == 1 );
00351     m_position          = (Position)element.attribute( "position", "0" ).toInt();
00352     m_alignment         = (Alignment)element.attribute( "alignment", "0" ).toInt();
00353     m_shadow            = ( element.attribute( "shadow" ).toInt() == 1 );
00354     m_translucentShadow = ( element.attribute( "translucentshadow" ).toInt() == 1 );
00355     m_shadowAngle       = element.attribute( "shadowangle" ).toInt();
00356     m_shadowDistance    = element.attribute( "shadowdist" ).toInt();
00357     m_offset            = element.attribute( "offset" ).toDouble();
00358     m_text = element.attribute( "text", "" );
00359 
00360     VObject::load( element );
00361 
00362     QDomNodeList list = element.childNodes();
00363     QDomElement e = list.item( 0 ).toElement();
00364     
00365     // element to start with reading glyph paths and stroke, fill, etc.
00366     uint startElement = 0;
00367 
00368     if( e.tagName() == "PATH" )
00369     {
00370         VPath path( 0L );
00371         path.load( e );
00372         m_basePath = *path.paths().getFirst();
00373         startElement++;
00374     }
00375 
00376     // load text glyphs:
00377     for( uint i = startElement; i < list.count(); ++i )
00378     {
00379         if( list.item( i ).isElement() )
00380         {
00381             e = list.item( i ).toElement();
00382             if( e.tagName() == "PATH" )
00383             {
00384                 VPath *composite = new VPath( this );
00385                 composite->load( e );
00386                 m_glyphs.append( composite );
00387             }
00388             if( e.tagName() == "STROKE" )
00389                 m_stroke->load( e );
00390             if( e.tagName() == "FILL" )
00391                 m_fill->load( e );
00392         }
00393     }
00394     // if no glyphs yet, trace them
00395 #ifdef HAVE_KARBONTEXT
00396     if( m_glyphs.count() == 0 )
00397         traceText();
00398 #endif
00399     m_boundingBoxIsInvalid = true;
00400     //m_fill->setFillRule( VFill::evenOdd );
00401 }
00402 
00403 void
00404 VText::setText( const QString& text )
00405 {
00406     if( m_text != text )
00407     {
00408         m_text = text;
00409         m_glyphs.clear();
00410 #ifdef HAVE_KARBONTEXT
00411         traceText();
00412 #endif
00413     }
00414 }
00415 
00416 void
00417 VText::setState( const VState state )
00418 {
00419     VObject::setState( state );
00420 
00421     VPathListIterator itr( m_glyphs );
00422     for( itr.toFirst(); itr.current(); ++itr )
00423     {
00424         itr.current()->setState( state );
00425     }
00426 }
00427 
00428 void
00429 VText::accept( VVisitor& visitor )
00430 {
00431     visitor.visitVText( *this );
00432 }
00433 
00434 #ifdef HAVE_KARBONTEXT
00435 
00436 void
00437 VText::traceText()
00438 {
00439     if( m_basePath.count() == 0 )
00440     {
00441         kdDebug(38000) << "Can't draw a text without base path (was: " << m_text << ")." << endl;
00442         return;
00443     }
00444 
00445     // TODO : set more options
00446     int slant = FC_SLANT_ROMAN;
00447     if( m_font.italic() )
00448         slant = FC_SLANT_ITALIC;
00449 
00450     int weight = 0;
00451     if( m_font.bold() )
00452         weight = FC_WEIGHT_BOLD;
00453 
00454     // Build FontConfig request pattern
00455     int id = -1;
00456     QString filename = buildRequest( m_font.family(), weight, slant, m_font.pointSize(), id );
00457     m_glyphs.clear();
00458 
00459     kdDebug(38000) << "Loading " << filename.latin1() << " for requested font \"" << m_font.family().latin1() << "\", " << m_font.pointSize() << " pt." << endl;
00460 
00461     FT_UInt glyphIndex;
00462     FT_Face fontFace;
00463     // TODO : this lib should probably be a singleton (Rob)
00464     FT_Library library;
00465     FT_Init_FreeType( &library );
00466     FT_Error error = FT_New_Face( library, QFile::encodeName(filename), id, &fontFace );
00467 
00468     if( error )
00469     {
00470         kdDebug(38000) << "traceText(), could not load font. Aborting!" << endl;
00471         return;
00472     }
00473 
00474     bool foundCharmap = false;
00475 
00476     // Try to choose unicode charmap
00477     for( int charmap = 0; charmap < fontFace->num_charmaps; charmap++ )
00478     {
00479         if( fontFace->charmaps[charmap]->encoding == ft_encoding_unicode )
00480         {
00481             FT_Error error = FT_Set_Charmap( fontFace, fontFace->charmaps[charmap] );
00482             if( error )
00483             {
00484                 kdDebug(38000) << "traceText(), unable to select unicode charmap." << endl;
00485                 continue;
00486             }
00487             foundCharmap = true;
00488         }
00489     }
00490 
00491     // Choose first charmap if no unicode charmap was found
00492     if( ! foundCharmap )
00493     {
00494         error = FT_Set_Charmap( fontFace, fontFace->charmaps[0] );
00495         if( error )
00496         {
00497             kdDebug(38000) << "traceText(), unable to select charmap. Aborting!" << endl;
00498             FT_Done_Face( fontFace );
00499             FT_Done_FreeType( library );
00500             return;
00501         }
00502     }
00503 
00504     error = FT_Set_Char_Size( fontFace, FT_FROMFLOAT( m_font.pointSize() ), FT_FROMFLOAT( m_font.pointSize() ), 0, 0 );
00505     if( error )
00506     {
00507         kdDebug(38000) << "traceText(), unable to set font size. Aborting!" << endl;
00508         FT_Done_Face( fontFace );
00509         FT_Done_FreeType( library );
00510         return;
00511     }
00512 
00513         // storing glyphs.
00514     float l = 0;
00515     QValueList<float> glyphXAdvance;
00516     QValueList<float> glyphYAdvance;
00517     for( unsigned int i = 0; i < m_text.length(); i++ )
00518     {
00519         // get the glyph index for the current character
00520         QChar character = m_text.at( i );
00521         glyphIndex = FT_Get_Char_Index( fontFace, character.unicode() );
00522         if( ! glyphIndex ) 
00523         {
00524             kdDebug(38000) << "traceText(), unable get index of char : " << character << endl;
00525             continue;
00526         }
00527         //kdDebug(38000) << "glyphIndex : " << glyphIndex << endl;
00528         FT_Error error = FT_Load_Glyph( fontFace, glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP );
00529         if( error )
00530         {
00531             kdDebug(38000) << "traceText(), unable to load glyph : " << error << endl;
00532             continue;
00533         }
00534 
00535         // decompose to vpaths
00536         FT_OutlineGlyph g;
00537         error = FT_Get_Glyph( fontFace->glyph, reinterpret_cast<FT_Glyph *>( &g ) );
00538         if( error )
00539         {
00540             kdDebug(38000) << "traceText(), unable to get glyph: " << error << endl;
00541             continue;
00542         }
00543 
00544         VPath *composite = new VPath( this );
00545         error = FT_Outline_Check( &g->outline );
00546         if( error ) 
00547         {
00548             kdDebug(38000) << "traceText(), outline is broken : " << error << endl;
00549             continue;
00550         }
00551 
00552         error = FT_Outline_Decompose(&g->outline, &OutlineMethods, composite );
00553         if( error )
00554         {
00555             kdDebug(38000) << "traceText(), unable to decompose outline : " << error << endl;
00556             continue;
00557         }
00558 
00559         m_glyphs.append( composite );
00560         glyphXAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.x ) );
00561         glyphYAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.y ) );
00562         l += FT_TOFLOAT( fontFace->glyph->advance.x );
00563         FT_Done_Glyph( reinterpret_cast<FT_Glyph>( g ) );
00564     }
00565 
00566      // Placing the stored glyphs.
00567     float pathLength = 0;
00568     VSubpathIterator pIt( m_basePath );
00569     
00570     VSegment* seg;
00571     for( ; pIt.current(); ++pIt )
00572         if( (seg = pIt.current() ) ) 
00573             pathLength += seg->length();
00574 
00575     kdDebug(38000) << "traceText(), using offset : " << m_offset << endl;
00576     float x = m_offset * pathLength;
00577     
00578     switch( m_alignment )
00579     {
00580         case Left: x += 0; break;
00581         case Center: x -=  0.5 * l; break;
00582         case Right: x -= l; break;
00583     }
00584     float y = 0;
00585     float dx = 0;
00586     float sp = 0;
00587     KoPoint point;
00588     KoPoint normal;
00589     KoPoint tangent;
00590     VSubpathIterator pathIt( m_basePath );
00591     VSegment* oldSeg = pathIt.current();
00592     seg = ++pathIt;
00593     KoPoint extPoint;
00594     bool ext = false;
00595     float fsx = 0;
00596     float yoffset = ( m_position == Above ? 0 : ( m_position == On ? m_font.pointSize() / 3 : m_font.pointSize() / 1.5 ) );
00597     kdDebug(38000) << "Position: " << m_position << " -> " << yoffset << endl;
00598     for( unsigned int i = 0; i < m_text.length(); i++ )
00599     {
00600         VPath* composite = m_glyphs.at( i );
00601         if( ! composite ) 
00602             continue;
00603         // Step 1: place (0, 0) to the rotation center of the glyph.
00604         dx = *glyphXAdvance.at( i ) / 2;
00605         x += dx;
00606         VTransformCmd trafo( 0L, QWMatrix( 1, 0, 0, 1, -dx, y + yoffset ) );
00607         trafo.visit( *composite );
00608 
00609         // Step 2: find the position where to draw.
00610         //   3 possibilities: before, on, and after the basePath...
00611         if ( x < 0 )
00612         {
00613             if( !ext )
00614                 seg->pointTangentNormalAt( 0, &extPoint, &tangent, &normal );
00615             point = extPoint + x * tangent;
00616             ext = true;
00617         }
00618         else
00619         {
00620             while ( seg && x > fsx + seg->length() )
00621             {
00622                 fsx += seg->length();
00623                 oldSeg = seg;
00624                 seg = ++pathIt;
00625             }
00626             if( seg )
00627             {
00628                 ext = false;
00629                 sp = ( x - fsx ) / seg->length();
00630                 seg->pointTangentNormalAt( sp, &point, &tangent, &normal );
00631             }
00632             else
00633             {
00634                 if( !ext )
00635                     oldSeg->pointTangentNormalAt( 1, &extPoint, &tangent, &normal );
00636                 point = extPoint + ( x - fsx ) * tangent;
00637                 ext = true;
00638             }
00639         }
00640 
00641         // Step 3: transform glyph and append it. That's it, we've got
00642         // text following a path. Really easy, isn't it ;) ?
00643         trafo.setMatrix( QWMatrix( tangent.x(), tangent.y(), tangent.y(), -tangent.x(), point.x(), point.y() ) );
00644         trafo.visit( *composite );
00645         composite->setState( state() );
00646 
00647         //kdDebug(38000) << "Glyph: " << (QString)character << " [String pos: " << x << ", " << y << " / Canvas pos: " << point.x() << ", " << point.y() << "]" << endl;
00648 
00649         x += dx;
00650         y += *glyphYAdvance.at( i );
00651     }
00652     FT_Done_Face( fontFace );
00653     FT_Done_FreeType( library );
00654     m_boundingBoxIsInvalid = true;
00655 }
00656 
00657 // This routine is copied from KSVGFont (Rob)
00658 QString
00659 VText::buildRequest( QString family, int weight, int slant, double size, int &id )
00660 {
00661     // Strip those stupid [Xft or whatever]...
00662     int pos;
00663     if( ( pos = family.find( '[' ) ) )
00664         family = family.left( pos );
00665 
00666     // Use FontConfig to locate & select fonts and use  FreeType2 to open them
00667     FcPattern *pattern;
00668     QString fileName;
00669 
00670     pattern = FcPatternBuild( 0, FC_WEIGHT, FcTypeInteger, weight,
00671                               FC_SLANT, FcTypeInteger, slant,
00672                               FC_SIZE, FcTypeDouble, size, NULL );
00673 
00674     // Add font name
00675     FcPatternAddString( pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>( family.latin1() ) );
00676 
00677     // Disable hinting
00678     FcPatternAddBool( pattern, FC_HINTING, FcFalse );
00679     // Enforce scalability
00680     FcPatternAddBool( pattern, FC_SCALABLE, FcTrue );
00681 
00682     // Perform the default font pattern modification operations.
00683     FcDefaultSubstitute( pattern );
00684     FcConfigSubstitute( FcConfigGetCurrent(), pattern, FcMatchPattern );
00685 
00686     FcResult result;
00687 
00688     // we dont want to use bitmap fonts, so get a list of fonts sorted by closeness to pattern
00689     // and use the best matching scalable font
00690     FcFontSet *fset = FcFontSort( 0, pattern, FcFalse, 0L, &result );
00691 
00692     // Destroy pattern
00693     FcPatternDestroy( pattern );
00694 
00695     if( fset )
00696     {
00697         FcBool scalable;
00698         FcChar8 *temp;
00699     
00700         // iterate over font list and take best scaleable font
00701         for( int i = 0; i < fset->nfont; ++i )
00702         {
00703             pattern = fset->fonts[i];
00704             if( FcResultMatch != FcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) )
00705                 continue;
00706             if( scalable == FcTrue )
00707             {
00708                 // Get index & filename
00709                 if( FcPatternGetString(pattern, FC_FILE, 0, &temp) != FcResultMatch ||
00710                     FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch )
00711                 {
00712                     kdDebug(38000) << "VText::buildRequest(), could not load font file for requested font \"" << family.latin1() << "\"" << endl;
00713                     return QString::null;
00714                 }
00715         
00716                 fileName = QFile::decodeName(reinterpret_cast<const char *>( temp ));
00717                 
00718                 // get family name of matched font
00719                 QString newFamily;
00720 
00721                 if( FcResultMatch == FcPatternGetString( pattern, FC_FAMILY, 0, &temp ) )
00722                     m_font.setFamily( reinterpret_cast<const char *>( temp ) );
00723 
00724                 break;
00725             }
00726         }
00727         
00728         FcFontSetDestroy( fset );
00729     }
00730 
00731     
00732     return fileName;
00733 }
00734 
00735 void VText::setOffset( double offset )
00736 {
00737     if( offset < 0.0 )
00738         m_offset = 0.0;
00739     else if( offset > 1.0 )
00740         m_offset = 1.0;
00741     else
00742         m_offset = offset;
00743 }
00744 
00745 #endif // HAVE_KARBONTEXT
KDE Home | KDE Accessibility Home | Description of Access Keys