summaryrefslogtreecommitdiffstats
path: root/karbon/core/vtext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'karbon/core/vtext.cpp')
-rw-r--r--karbon/core/vtext.cpp746
1 files changed, 746 insertions, 0 deletions
diff --git a/karbon/core/vtext.cpp b/karbon/core/vtext.cpp
new file mode 100644
index 000000000..b8e15c4f3
--- /dev/null
+++ b/karbon/core/vtext.cpp
@@ -0,0 +1,746 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, The Karbon Developers
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <tqdom.h>
+#include <tqfile.h>
+
+#include <kdebug.h>
+#include <KoPoint.h>
+#include <KoRect.h>
+
+#include "vpath.h"
+#include "vtext.h"
+#include "vtext_iface.h"
+#include "vstroke.h"
+#include "vfill.h"
+#include "vvisitor.h"
+#include "vsegment.h"
+#include "vgroup.h"
+#include "vpainter.h"
+#include "commands/vtransformcmd.h"
+
+#ifdef HAVE_KARBONTEXT
+
+#include <ft2build.h>
+#include <fontconfig/fontconfig.h>
+
+
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_GLYPH_H
+
+#define FT_TOFLOAT(x) ((x) * (1.0 / 64.0))
+#define FT_FROMFLOAT(x) ((int) floor ((x) * 64.0 + 0.5))
+
+
+// Trace routines for ttf / ps font -> VSubpath
+
+int traceMoveto( FT_Vector *to, VPath *composite )
+{
+ double tox = ( to->x / 64.0 );
+ double toy = ( -to->y / 64.0 );
+
+ //TQString add = "M" + TQString::number(tox) + "," + TQString::number(toy) + " ";
+ //kdDebug(38000) << add.latin1() << endl;
+ composite->moveTo( KoPoint( tox, toy ) );
+
+ return 0;
+}
+
+int traceLineto( FT_Vector *to, VPath *composite )
+{
+ double tox = ( to->x / 64.0 );
+ double toy = ( -to->y / 64.0 );
+
+ //TQString add = "L" + TQString::number(tox) + "," + TQString::number(toy) + " ";
+ //kdDebug(38000) << add.latin1() << endl;
+
+ composite->lineTo( KoPoint( tox, toy ) );
+
+ return 0;
+}
+
+int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, VPath *composite )
+{
+ double x1 = ( control->x / 64.0 );
+ double y1 = ( -control->y / 64.0 );
+ double x2 = ( to->x / 64.0 );
+ double y2 = ( -to->y / 64.0 );
+
+ //TQString add = "Q" + TQString::number(x1) + "," + TQString::number(y1) + "," + TQString::number(x2) + "," + TQString::number(y2) + " ";
+ //kdDebug(38000) << add.latin1() << endl;
+ composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x2, y2 ) );
+ //composite->curve2To( KoPoint( x1, y1 ), KoPoint( x2, y2 ) );
+
+ return 0;
+}
+
+int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, VPath *composite )
+{
+ double x1 = ( p->x / 64.0 );
+ double y1 = ( -p->y / 64.0 );
+ double x2 = ( q->x / 64.0 );
+ double y2 = ( -q->y / 64.0 );
+ double x3 = ( to->x / 64.0 );
+ double y3 = ( -to->y / 64.0 );
+
+ //TQString add = "C" + TQString::number(x1) + "," + TQString::number(y1) + "," + TQString::number(x2) + "," + TQString::number(y2) + "," + TQString::number(x3) + "," + TQString::number(y3);
+ //kdDebug(38000) << add.latin1() << endl;
+
+ composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x3, y3 ) );
+
+ return 0;
+}
+
+FT_Outline_Funcs OutlineMethods =
+{
+ (FT_Outline_MoveTo_Func) traceMoveto,
+ (FT_Outline_LineTo_Func) traceLineto,
+ (FT_Outline_ConicTo_Func) traceQuadraticBezier,
+ (FT_Outline_CubicTo_Func) traceCubicBezier,
+ 0,
+ 0
+};
+
+#endif // HAVE_KARBONTEXT
+
+VText::VText( VObject* parent, VState state )
+ : VObject( parent, state ), m_basePath( 0L )
+{
+ m_glyphs.setAutoDelete( true );
+ m_boundingBoxIsInvalid = true;
+ m_stroke = new VStroke( this );
+ m_fill = new VFill();
+ m_position = (VText::Position)0;
+ m_alignment = (VText::Alignment)0;
+ m_shadow = false;
+ m_translucentShadow = false;
+ m_shadowAngle = 0;
+ m_shadowDistance = 0;
+ m_offset = 0.0;
+}
+
+
+VText::VText( const TQFont &font, const VSubpath& basePath, Position position, Alignment alignment, const TQString& text )
+ : VObject( 0L ), m_font( font ), m_basePath( basePath ), m_position( position ), m_alignment( alignment ), m_text( text )
+{
+ m_glyphs.setAutoDelete( true );
+ m_boundingBoxIsInvalid = true;
+ m_stroke = new VStroke( this );
+ m_fill = new VFill();
+ m_offset = 0.0;
+}
+
+VText::VText( const VText& text )
+ : 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 )
+{
+ m_stroke = new VStroke( *text.m_stroke );
+ m_stroke->setParent( this );
+ m_fill = new VFill( *text.m_fill );
+
+ // copy glyphs
+ VPathListIterator itr( text.m_glyphs );
+ for( ; itr.current() ; ++itr )
+ {
+ VPath* c = itr.current()->clone();
+ c->setParent( this );
+ m_glyphs.append( c );
+ }
+
+ m_boundingBoxIsInvalid = true;
+}
+
+VText::~VText()
+{
+}
+
+DCOPObject* VText::dcopObject()
+{
+ if( !m_dcop )
+ m_dcop = new VTextIface( this );
+
+ return m_dcop;
+}
+
+
+void
+VText::draw( VPainter* painter, const KoRect* /*rect*/ ) const
+{
+ if(
+ state() == deleted ||
+ state() == hidden ||
+ state() == hidden_locked )
+ {
+ return;
+ }
+
+ painter->save();
+
+ VPathListIterator itr( m_glyphs );
+
+ if( state() != edit )
+ {
+ // paint fill:
+ painter->newPath();
+
+ if ( m_shadow )
+ {
+ VColor color;
+ if ( m_translucentShadow )
+ {
+ color.set( 0., 0., 0. );
+ color.setOpacity( .3 );
+ }
+ else
+ {
+ color.set( .3, .3, .3 );
+ color.setOpacity( 1. );
+ }
+ int shadowDx = int( m_shadowDistance * cos( m_shadowAngle / 360. * 6.2832 ) );
+ int shadowDy = int( m_shadowDistance * sin( m_shadowAngle / 360. * 6.2832 ) );
+
+ VTransformCmd trafo( 0L, TQWMatrix() );
+ for( itr.toFirst(); itr.current(); ++itr )
+ {
+ trafo.setMatrix( TQWMatrix( 1, 0, 0, 1, shadowDx, shadowDy ) );
+ trafo.visit( *( itr.current() ) );
+ itr.current()->setFill( VFill( color ) );
+ itr.current()->setStroke( VStroke( color ) );
+ itr.current()->draw( painter );
+ trafo.setMatrix( TQWMatrix( 1, 0, 0, 1, -shadowDx, -shadowDy ) );
+ trafo.visit( *( itr.current() ) );
+ }
+ }
+
+ for( itr.toFirst(); itr.current(); ++itr )
+ {
+ itr.current()->setFill( *m_fill );
+ itr.current()->setStroke( *m_stroke );
+ itr.current()->draw( painter );
+ }
+ }
+
+ // draw simplistic contour:
+ if( state() == edit )//|| state() == selected )
+ {
+ painter->newPath();
+ painter->setRasterOp( TQt::XorROP );
+ painter->setPen( TQt::yellow );
+ painter->setBrush( TQt::NoBrush );
+
+ for( itr.toFirst(); itr.current(); ++itr )
+ itr.current()->draw( painter );
+
+ painter->strokePath();
+ }
+
+ painter->restore();
+}
+
+const KoRect&
+VText::boundingBox() const
+{
+ if( m_boundingBoxIsInvalid )
+ {
+ VPathListIterator itr( m_glyphs );
+ itr.toFirst();
+ // clear:
+ m_boundingBox = itr.current() ? itr.current()->boundingBox() : KoRect();
+ for( ++itr; itr.current(); ++itr )
+ if( !itr.current()->boundingBox().isEmpty() )
+ m_boundingBox |= itr.current()->boundingBox();
+
+ // take line width into account:
+ m_boundingBox.setCoords(
+ m_boundingBox.left() - 0.5 * stroke()->lineWidth(),
+ m_boundingBox.top() - 0.5 * stroke()->lineWidth(),
+ m_boundingBox.right() + 0.5 * stroke()->lineWidth(),
+ m_boundingBox.bottom() + 0.5 * stroke()->lineWidth() );
+
+ m_boundingBoxIsInvalid = false;
+ }
+
+ return m_boundingBox;
+}
+
+VText*
+VText::clone() const
+{
+ return new VText( *this );
+}
+
+VGroup* VText::toVGroup() const
+{
+ VGroup* group = new VGroup( parent() );
+
+ VPathListIterator itr( m_glyphs );
+ for( itr.toFirst(); itr.current(); ++itr )
+ {
+ VPath* c = itr.current()->clone();
+ c->setParent( group );
+ group->append( c );
+ }
+
+ group->setFill( *m_fill );
+ group->setStroke( *m_stroke );
+
+ return group;
+} // VText::toVGroup
+
+void
+VText::save( TQDomElement& element ) const
+{
+ if( state() != deleted )
+ {
+ TQDomElement me = element.ownerDocument().createElement( "TEXT" );
+
+ VPath path( 0L );
+ path.combinePath( m_basePath );
+ path.save( me );
+
+ VObject::save( me );
+
+ // save font properties
+ me.setAttribute( "text", m_text );
+ me.setAttribute( "family", m_font.family() );
+ me.setAttribute( "size", m_font.pointSize() );
+ me.setAttribute( "italic", m_font.italic() );
+ me.setAttribute( "bold", m_font.bold() );
+ me.setAttribute( "position", m_position );
+ me.setAttribute( "alignment", m_alignment );
+ me.setAttribute( "shadow", m_shadow );
+ me.setAttribute( "translucentshadow", m_translucentShadow );
+ me.setAttribute( "shadowangle", m_shadowAngle );
+ me.setAttribute( "shadowdist", m_shadowDistance );
+ me.setAttribute( "offset", m_offset );
+ element.appendChild( me );
+
+ // save all glyphs / paths
+ VPathListIterator itr = m_glyphs;
+ for( itr.toFirst(); itr.current(); ++itr )
+ itr.current()->save( me );
+ }
+}
+
+void
+VText::load( const TQDomElement& element )
+{
+ m_glyphs.clear();
+
+ m_font.setFamily( element.attribute( "family", "Times" ) );
+ m_font.setPointSize( element.attribute( "size", "12" ).toInt() );
+ m_font.setItalic( element.attribute( "italic" ).toInt() == 1 );
+ m_font.setWeight( TQFont::Normal );
+ m_font.setBold( element.attribute( "bold" ).toInt() == 1 );
+ m_position = (Position)element.attribute( "position", "0" ).toInt();
+ m_alignment = (Alignment)element.attribute( "alignment", "0" ).toInt();
+ m_shadow = ( element.attribute( "shadow" ).toInt() == 1 );
+ m_translucentShadow = ( element.attribute( "translucentshadow" ).toInt() == 1 );
+ m_shadowAngle = element.attribute( "shadowangle" ).toInt();
+ m_shadowDistance = element.attribute( "shadowdist" ).toInt();
+ m_offset = element.attribute( "offset" ).toDouble();
+ m_text = element.attribute( "text", "" );
+
+ VObject::load( element );
+
+ TQDomNodeList list = element.childNodes();
+ TQDomElement e = list.item( 0 ).toElement();
+
+ // element to start with reading glyph paths and stroke, fill, etc.
+ uint startElement = 0;
+
+ if( e.tagName() == "PATH" )
+ {
+ VPath path( 0L );
+ path.load( e );
+ m_basePath = *path.paths().getFirst();
+ startElement++;
+ }
+
+ // load text glyphs:
+ for( uint i = startElement; i < list.count(); ++i )
+ {
+ if( list.item( i ).isElement() )
+ {
+ e = list.item( i ).toElement();
+ if( e.tagName() == "PATH" )
+ {
+ VPath *composite = new VPath( this );
+ composite->load( e );
+ m_glyphs.append( composite );
+ }
+ if( e.tagName() == "STROKE" )
+ m_stroke->load( e );
+ if( e.tagName() == "FILL" )
+ m_fill->load( e );
+ }
+ }
+ // if no glyphs yet, trace them
+#ifdef HAVE_KARBONTEXT
+ if( m_glyphs.count() == 0 )
+ traceText();
+#endif
+ m_boundingBoxIsInvalid = true;
+ //m_fill->setFillRule( VFill::evenOdd );
+}
+
+void
+VText::setText( const TQString& text )
+{
+ if( m_text != text )
+ {
+ m_text = text;
+ m_glyphs.clear();
+#ifdef HAVE_KARBONTEXT
+ traceText();
+#endif
+ }
+}
+
+void
+VText::setState( const VState state )
+{
+ VObject::setState( state );
+
+ VPathListIterator itr( m_glyphs );
+ for( itr.toFirst(); itr.current(); ++itr )
+ {
+ itr.current()->setState( state );
+ }
+}
+
+void
+VText::accept( VVisitor& visitor )
+{
+ visitor.visitVText( *this );
+}
+
+#ifdef HAVE_KARBONTEXT
+
+void
+VText::traceText()
+{
+ if( m_basePath.count() == 0 )
+ {
+ kdDebug(38000) << "Can't draw a text without base path (was: " << m_text << ")." << endl;
+ return;
+ }
+
+ // TODO : set more options
+ int slant = FC_SLANT_ROMAN;
+ if( m_font.italic() )
+ slant = FC_SLANT_ITALIC;
+
+ int weight = 0;
+ if( m_font.bold() )
+ weight = FC_WEIGHT_BOLD;
+
+ // Build FontConfig request pattern
+ int id = -1;
+ TQString filename = buildRequest( m_font.family(), weight, slant, m_font.pointSize(), id );
+ m_glyphs.clear();
+
+ kdDebug(38000) << "Loading " << filename.latin1() << " for requested font \"" << TQString(m_font.family()).latin1() << "\", " << m_font.pointSize() << " pt." << endl;
+
+ FT_UInt glyphIndex;
+ FT_Face fontFace;
+ // TODO : this lib should probably be a singleton (Rob)
+ FT_Library library;
+ FT_Init_FreeType( &library );
+ FT_Error error = FT_New_Face( library, TQFile::encodeName(filename), id, &fontFace );
+
+ if( error )
+ {
+ kdDebug(38000) << "traceText(), could not load font. Aborting!" << endl;
+ return;
+ }
+
+ bool foundCharmap = false;
+
+ // Try to choose unicode charmap
+ for( int charmap = 0; charmap < fontFace->num_charmaps; charmap++ )
+ {
+ if( fontFace->charmaps[charmap]->encoding == ft_encoding_unicode )
+ {
+ FT_Error error = FT_Set_Charmap( fontFace, fontFace->charmaps[charmap] );
+ if( error )
+ {
+ kdDebug(38000) << "traceText(), unable to select unicode charmap." << endl;
+ continue;
+ }
+ foundCharmap = true;
+ }
+ }
+
+ // Choose first charmap if no unicode charmap was found
+ if( ! foundCharmap )
+ {
+ error = FT_Set_Charmap( fontFace, fontFace->charmaps[0] );
+ if( error )
+ {
+ kdDebug(38000) << "traceText(), unable to select charmap. Aborting!" << endl;
+ FT_Done_Face( fontFace );
+ FT_Done_FreeType( library );
+ return;
+ }
+ }
+
+ error = FT_Set_Char_Size( fontFace, FT_FROMFLOAT( m_font.pointSize() ), FT_FROMFLOAT( m_font.pointSize() ), 0, 0 );
+ if( error )
+ {
+ kdDebug(38000) << "traceText(), unable to set font size. Aborting!" << endl;
+ FT_Done_Face( fontFace );
+ FT_Done_FreeType( library );
+ return;
+ }
+
+ // storing glyphs.
+ float l = 0;
+ TQValueList<float> glyphXAdvance;
+ TQValueList<float> glyphYAdvance;
+ for( unsigned int i = 0; i < m_text.length(); i++ )
+ {
+ // get the glyph index for the current character
+ TQChar character = m_text.at( i );
+ glyphIndex = FT_Get_Char_Index( fontFace, character.unicode() );
+ if( ! glyphIndex )
+ {
+ kdDebug(38000) << "traceText(), unable get index of char : " << character << endl;
+ continue;
+ }
+ //kdDebug(38000) << "glyphIndex : " << glyphIndex << endl;
+ FT_Error error = FT_Load_Glyph( fontFace, glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP );
+ if( error )
+ {
+ kdDebug(38000) << "traceText(), unable to load glyph : " << error << endl;
+ continue;
+ }
+
+ // decompose to vpaths
+ FT_OutlineGlyph g;
+ error = FT_Get_Glyph( fontFace->glyph, reinterpret_cast<FT_Glyph *>( &g ) );
+ if( error )
+ {
+ kdDebug(38000) << "traceText(), unable to get glyph: " << error << endl;
+ continue;
+ }
+
+ VPath *composite = new VPath( this );
+ error = FT_Outline_Check( &g->outline );
+ if( error )
+ {
+ kdDebug(38000) << "traceText(), outline is broken : " << error << endl;
+ continue;
+ }
+
+ error = FT_Outline_Decompose(&g->outline, &OutlineMethods, composite );
+ if( error )
+ {
+ kdDebug(38000) << "traceText(), unable to decompose outline : " << error << endl;
+ continue;
+ }
+
+ m_glyphs.append( composite );
+ glyphXAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.x ) );
+ glyphYAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.y ) );
+ l += FT_TOFLOAT( fontFace->glyph->advance.x );
+ FT_Done_Glyph( reinterpret_cast<FT_Glyph>( g ) );
+ }
+
+ // Placing the stored glyphs.
+ float pathLength = 0;
+ VSubpathIterator pIt( m_basePath );
+
+ VSegment* seg;
+ for( ; pIt.current(); ++pIt )
+ if( (seg = pIt.current() ) )
+ pathLength += seg->length();
+
+ kdDebug(38000) << "traceText(), using offset : " << m_offset << endl;
+ float x = m_offset * pathLength;
+
+ switch( m_alignment )
+ {
+ case Left: x += 0; break;
+ case Center: x -= 0.5 * l; break;
+ case Right: x -= l; break;
+ }
+ float y = 0;
+ float dx = 0;
+ float sp = 0;
+ KoPoint point;
+ KoPoint normal;
+ KoPoint tangent;
+ VSubpathIterator pathIt( m_basePath );
+ VSegment* oldSeg = pathIt.current();
+ seg = ++pathIt;
+ KoPoint extPoint;
+ bool ext = false;
+ float fsx = 0;
+ float yoffset = ( m_position == Above ? 0 : ( m_position == On ? m_font.pointSize() / 3 : m_font.pointSize() / 1.5 ) );
+ kdDebug(38000) << "Position: " << m_position << " -> " << yoffset << endl;
+ for( unsigned int i = 0; i < m_text.length(); i++ )
+ {
+ VPath* composite = m_glyphs.at( i );
+ if( ! composite )
+ continue;
+ // Step 1: place (0, 0) to the rotation center of the glyph.
+ dx = *glyphXAdvance.at( i ) / 2;
+ x += dx;
+ VTransformCmd trafo( 0L, TQWMatrix( 1, 0, 0, 1, -dx, y + yoffset ) );
+ trafo.visit( *composite );
+
+ // Step 2: find the position where to draw.
+ // 3 possibilities: before, on, and after the basePath...
+ if ( x < 0 )
+ {
+ if( !ext )
+ seg->pointTangentNormalAt( 0, &extPoint, &tangent, &normal );
+ point = extPoint + x * tangent;
+ ext = true;
+ }
+ else
+ {
+ while ( seg && x > fsx + seg->length() )
+ {
+ fsx += seg->length();
+ oldSeg = seg;
+ seg = ++pathIt;
+ }
+ if( seg )
+ {
+ ext = false;
+ sp = ( x - fsx ) / seg->length();
+ seg->pointTangentNormalAt( sp, &point, &tangent, &normal );
+ }
+ else
+ {
+ if( !ext )
+ oldSeg->pointTangentNormalAt( 1, &extPoint, &tangent, &normal );
+ point = extPoint + ( x - fsx ) * tangent;
+ ext = true;
+ }
+ }
+
+ // Step 3: transform glyph and append it. That's it, we've got
+ // text following a path. Really easy, isn't it ;) ?
+ trafo.setMatrix( TQWMatrix( tangent.x(), tangent.y(), tangent.y(), -tangent.x(), point.x(), point.y() ) );
+ trafo.visit( *composite );
+ composite->setState( state() );
+
+ //kdDebug(38000) << "Glyph: " << (TQString)character << " [String pos: " << x << ", " << y << " / Canvas pos: " << point.x() << ", " << point.y() << "]" << endl;
+
+ x += dx;
+ y += *glyphYAdvance.at( i );
+ }
+ FT_Done_Face( fontFace );
+ FT_Done_FreeType( library );
+ m_boundingBoxIsInvalid = true;
+}
+
+// This routine is copied from KSVGFont (Rob)
+TQString
+VText::buildRequest( TQString family, int weight, int slant, double size, int &id )
+{
+ // Strip those stupid [Xft or whatever]...
+ int pos;
+ if( ( pos = family.find( '[' ) ) )
+ family = family.left( pos );
+
+ // Use FontConfig to locate & select fonts and use FreeType2 to open them
+ FcPattern *pattern;
+ TQString fileName;
+
+ pattern = FcPatternBuild( 0, FC_WEIGHT, FcTypeInteger, weight,
+ FC_SLANT, FcTypeInteger, slant,
+ FC_SIZE, FcTypeDouble, size, NULL );
+
+ // Add font name
+ FcPatternAddString( pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>( family.latin1() ) );
+
+ // Disable hinting
+ FcPatternAddBool( pattern, FC_HINTING, FcFalse );
+ // Enforce scalability
+ FcPatternAddBool( pattern, FC_SCALABLE, FcTrue );
+
+ // Perform the default font pattern modification operations.
+ FcDefaultSubstitute( pattern );
+ FcConfigSubstitute( FcConfigGetCurrent(), pattern, FcMatchPattern );
+
+ FcResult result;
+
+ // we dont want to use bitmap fonts, so get a list of fonts sorted by closeness to pattern
+ // and use the best matching scalable font
+ FcFontSet *fset = FcFontSort( 0, pattern, FcFalse, 0L, &result );
+
+ // Destroy pattern
+ FcPatternDestroy( pattern );
+
+ if( fset )
+ {
+ FcBool scalable;
+ FcChar8 *temp;
+
+ // iterate over font list and take best scaleable font
+ for( int i = 0; i < fset->nfont; ++i )
+ {
+ pattern = fset->fonts[i];
+ if( FcResultMatch != FcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) )
+ continue;
+ if( scalable == FcTrue )
+ {
+ // Get index & filename
+ if( FcPatternGetString(pattern, FC_FILE, 0, &temp) != FcResultMatch ||
+ FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch )
+ {
+ kdDebug(38000) << "VText::buildRequest(), could not load font file for requested font \"" << family.latin1() << "\"" << endl;
+ return TQString();
+ }
+
+ fileName = TQFile::decodeName(reinterpret_cast<const char *>( temp ));
+
+ // get family name of matched font
+ TQString newFamily;
+
+ if( FcResultMatch == FcPatternGetString( pattern, FC_FAMILY, 0, &temp ) )
+ m_font.setFamily( reinterpret_cast<const char *>( temp ) );
+
+ break;
+ }
+ }
+
+ FcFontSetDestroy( fset );
+ }
+
+
+ return fileName;
+}
+
+#endif // HAVE_KARBONTEXT
+
+void VText::setOffset( double offset )
+{
+ if( offset < 0.0 )
+ m_offset = 0.0;
+ else if( offset > 1.0 )
+ m_offset = 1.0;
+ else
+ m_offset = offset;
+}
+