karbon

vtext.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002, The Karbon Developers
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <tqdom.h>
21#include <tqfile.h>
22
23#include <kdebug.h>
24#include <KoPoint.h>
25#include <KoRect.h>
26
27#include "vpath.h"
28#include "vtext.h"
29#include "vtext_iface.h"
30#include "vstroke.h"
31#include "vfill.h"
32#include "vvisitor.h"
33#include "vsegment.h"
34#include "vgroup.h"
35#include "vpainter.h"
36#include "commands/vtransformcmd.h"
37
38#ifdef HAVE_KARBONTEXT
39
40#include <ft2build.h>
41#include <fontconfig/fontconfig.h>
42
43
44#include FT_FREETYPE_H
45#include FT_OUTLINE_H
46#include FT_GLYPH_H
47
48#define FT_TOFLOAT(x) ((x) * (1.0 / 64.0))
49#define FT_FROMFLOAT(x) ((int) floor ((x) * 64.0 + 0.5))
50
51
52// Trace routines for ttf / ps font -> VSubpath
53
54int traceMoveto( FT_Vector *to, VPath *composite )
55{
56 double tox = ( to->x / 64.0 );
57 double toy = ( -to->y / 64.0 );
58
59 //TQString add = "M" + TQString::number(tox) + "," + TQString::number(toy) + " ";
60 //kdDebug(38000) << add.latin1() << endl;
61 composite->moveTo( KoPoint( tox, toy ) );
62
63 return 0;
64}
65
66int traceLineto( FT_Vector *to, VPath *composite )
67{
68 double tox = ( to->x / 64.0 );
69 double toy = ( -to->y / 64.0 );
70
71 //TQString add = "L" + TQString::number(tox) + "," + TQString::number(toy) + " ";
72 //kdDebug(38000) << add.latin1() << endl;
73
74 composite->lineTo( KoPoint( tox, toy ) );
75
76 return 0;
77}
78
79int traceQuadraticBezier( FT_Vector *control, FT_Vector *to, VPath *composite )
80{
81 double x1 = ( control->x / 64.0 );
82 double y1 = ( -control->y / 64.0 );
83 double x2 = ( to->x / 64.0 );
84 double y2 = ( -to->y / 64.0 );
85
86 //TQString add = "Q" + TQString::number(x1) + "," + TQString::number(y1) + "," + TQString::number(x2) + "," + TQString::number(y2) + " ";
87 //kdDebug(38000) << add.latin1() << endl;
88 composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x2, y2 ) );
89 //composite->curve2To( KoPoint( x1, y1 ), KoPoint( x2, y2 ) );
90
91 return 0;
92}
93
94int traceCubicBezier( FT_Vector *p, FT_Vector *q, FT_Vector *to, VPath *composite )
95{
96 double x1 = ( p->x / 64.0 );
97 double y1 = ( -p->y / 64.0 );
98 double x2 = ( q->x / 64.0 );
99 double y2 = ( -q->y / 64.0 );
100 double x3 = ( to->x / 64.0 );
101 double y3 = ( -to->y / 64.0 );
102
103 //TQString add = "C" + TQString::number(x1) + "," + TQString::number(y1) + "," + TQString::number(x2) + "," + TQString::number(y2) + "," + TQString::number(x3) + "," + TQString::number(y3);
104 //kdDebug(38000) << add.latin1() << endl;
105
106 composite->curveTo( KoPoint( x1, y1 ), KoPoint( x2, y2 ), KoPoint( x3, y3 ) );
107
108 return 0;
109}
110
111FT_Outline_Funcs OutlineMethods =
112{
113 (FT_Outline_MoveTo_Func) traceMoveto,
114 (FT_Outline_LineTo_Func) traceLineto,
115 (FT_Outline_ConicTo_Func) traceQuadraticBezier,
116 (FT_Outline_CubicTo_Func) traceCubicBezier,
117 0,
118 0
119};
120
121#endif // HAVE_KARBONTEXT
122
123VText::VText( VObject* parent, VState state )
124 : VObject( parent, state ), m_basePath( 0L )
125{
126 m_glyphs.setAutoDelete( true );
127 m_boundingBoxIsInvalid = true;
128 m_stroke = new VStroke( this );
129 m_fill = new VFill();
130 m_position = (VText::Position)0;
131 m_alignment = (VText::Alignment)0;
132 m_shadow = false;
133 m_translucentShadow = false;
134 m_shadowAngle = 0;
135 m_shadowDistance = 0;
136 m_offset = 0.0;
137}
138
139
140VText::VText( const TQFont &font, const VSubpath& basePath, Position position, Alignment alignment, const TQString& text )
141 : VObject( 0L ), m_font( font ), m_basePath( basePath ), m_position( position ), m_alignment( alignment ), m_text( text )
142{
143 m_glyphs.setAutoDelete( true );
144 m_boundingBoxIsInvalid = true;
145 m_stroke = new VStroke( this );
146 m_fill = new VFill();
147 m_offset = 0.0;
148}
149
150VText::VText( const VText& text )
151 : 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 )
152{
153 m_stroke = new VStroke( *text.m_stroke );
154 m_stroke->setParent( this );
155 m_fill = new VFill( *text.m_fill );
156
157 // copy glyphs
158 VPathListIterator itr( text.m_glyphs );
159 for( ; itr.current() ; ++itr )
160 {
161 VPath* c = itr.current()->clone();
162 c->setParent( this );
163 m_glyphs.append( c );
164 }
165
166 m_boundingBoxIsInvalid = true;
167}
168
169VText::~VText()
170{
171}
172
173DCOPObject* VText::dcopObject()
174{
175 if( !m_dcop )
176 m_dcop = new VTextIface( this );
177
178 return m_dcop;
179}
180
181
182void
183VText::draw( VPainter* painter, const KoRect* /*rect*/ ) const
184{
185 if(
186 state() == deleted ||
187 state() == hidden ||
188 state() == hidden_locked )
189 {
190 return;
191 }
192
193 painter->save();
194
195 VPathListIterator itr( m_glyphs );
196
197 if( state() != edit )
198 {
199 // paint fill:
200 painter->newPath();
201
202 if ( m_shadow )
203 {
204 VColor color;
205 if ( m_translucentShadow )
206 {
207 color.set( 0., 0., 0. );
208 color.setOpacity( .3 );
209 }
210 else
211 {
212 color.set( .3, .3, .3 );
213 color.setOpacity( 1. );
214 }
215 int shadowDx = int( m_shadowDistance * cos( m_shadowAngle / 360. * 6.2832 ) );
216 int shadowDy = int( m_shadowDistance * sin( m_shadowAngle / 360. * 6.2832 ) );
217
218 VTransformCmd trafo( 0L, TQWMatrix() );
219 for( itr.toFirst(); itr.current(); ++itr )
220 {
221 trafo.setMatrix( TQWMatrix( 1, 0, 0, 1, shadowDx, shadowDy ) );
222 trafo.visit( *( itr.current() ) );
223 itr.current()->setFill( VFill( color ) );
224 itr.current()->setStroke( VStroke( color ) );
225 itr.current()->draw( painter );
226 trafo.setMatrix( TQWMatrix( 1, 0, 0, 1, -shadowDx, -shadowDy ) );
227 trafo.visit( *( itr.current() ) );
228 }
229 }
230
231 for( itr.toFirst(); itr.current(); ++itr )
232 {
233 itr.current()->setFill( *m_fill );
234 itr.current()->setStroke( *m_stroke );
235 itr.current()->draw( painter );
236 }
237 }
238
239 // draw simplistic contour:
240 if( state() == edit )//|| state() == selected )
241 {
242 painter->newPath();
243 painter->setRasterOp( TQt::XorROP );
244 painter->setPen( TQt::yellow );
245 painter->setBrush( TQt::NoBrush );
246
247 for( itr.toFirst(); itr.current(); ++itr )
248 itr.current()->draw( painter );
249
250 painter->strokePath();
251 }
252
253 painter->restore();
254}
255
256const KoRect&
257VText::boundingBox() const
258{
259 if( m_boundingBoxIsInvalid )
260 {
261 VPathListIterator itr( m_glyphs );
262 itr.toFirst();
263 // clear:
264 m_boundingBox = itr.current() ? itr.current()->boundingBox() : KoRect();
265 for( ++itr; itr.current(); ++itr )
266 if( !itr.current()->boundingBox().isEmpty() )
267 m_boundingBox |= itr.current()->boundingBox();
268
269 // take line width into account:
270 m_boundingBox.setCoords(
271 m_boundingBox.left() - 0.5 * stroke()->lineWidth(),
272 m_boundingBox.top() - 0.5 * stroke()->lineWidth(),
273 m_boundingBox.right() + 0.5 * stroke()->lineWidth(),
274 m_boundingBox.bottom() + 0.5 * stroke()->lineWidth() );
275
276 m_boundingBoxIsInvalid = false;
277 }
278
279 return m_boundingBox;
280}
281
282VText*
283VText::clone() const
284{
285 return new VText( *this );
286}
287
288VGroup* VText::toVGroup() const
289{
290 VGroup* group = new VGroup( parent() );
291
292 VPathListIterator itr( m_glyphs );
293 for( itr.toFirst(); itr.current(); ++itr )
294 {
295 VPath* c = itr.current()->clone();
296 c->setParent( group );
297 group->append( c );
298 }
299
300 group->setFill( *m_fill );
301 group->setStroke( *m_stroke );
302
303 return group;
304} // VText::toVGroup
305
306void
307VText::save( TQDomElement& element ) const
308{
309 if( state() != deleted )
310 {
311 TQDomElement me = element.ownerDocument().createElement( "TEXT" );
312
313 VPath path( 0L );
314 path.combinePath( m_basePath );
315 path.save( me );
316
317 VObject::save( me );
318
319 // save font properties
320 me.setAttribute( "text", m_text );
321 me.setAttribute( "family", m_font.family() );
322 me.setAttribute( "size", m_font.pointSize() );
323 me.setAttribute( "italic", m_font.italic() );
324 me.setAttribute( "bold", m_font.bold() );
325 me.setAttribute( "position", m_position );
326 me.setAttribute( "alignment", m_alignment );
327 me.setAttribute( "shadow", m_shadow );
328 me.setAttribute( "translucentshadow", m_translucentShadow );
329 me.setAttribute( "shadowangle", m_shadowAngle );
330 me.setAttribute( "shadowdist", m_shadowDistance );
331 me.setAttribute( "offset", m_offset );
332 element.appendChild( me );
333
334 // save all glyphs / paths
335 VPathListIterator itr = m_glyphs;
336 for( itr.toFirst(); itr.current(); ++itr )
337 itr.current()->save( me );
338 }
339}
340
341void
342VText::load( const TQDomElement& element )
343{
344 m_glyphs.clear();
345
346 m_font.setFamily( element.attribute( "family", "Times" ) );
347 m_font.setPointSize( element.attribute( "size", "12" ).toInt() );
348 m_font.setItalic( element.attribute( "italic" ).toInt() == 1 );
349 m_font.setWeight( TQFont::Normal );
350 m_font.setBold( element.attribute( "bold" ).toInt() == 1 );
351 m_position = (Position)element.attribute( "position", "0" ).toInt();
352 m_alignment = (Alignment)element.attribute( "alignment", "0" ).toInt();
353 m_shadow = ( element.attribute( "shadow" ).toInt() == 1 );
354 m_translucentShadow = ( element.attribute( "translucentshadow" ).toInt() == 1 );
355 m_shadowAngle = element.attribute( "shadowangle" ).toInt();
356 m_shadowDistance = element.attribute( "shadowdist" ).toInt();
357 m_offset = element.attribute( "offset" ).toDouble();
358 m_text = element.attribute( "text", "" );
359
360 VObject::load( element );
361
362 TQDomNodeList list = element.childNodes();
363 TQDomElement e = list.item( 0 ).toElement();
364
365 // element to start with reading glyph paths and stroke, fill, etc.
366 uint startElement = 0;
367
368 if( e.tagName() == "PATH" )
369 {
370 VPath path( 0L );
371 path.load( e );
372 m_basePath = *path.paths().getFirst();
373 startElement++;
374 }
375
376 // load text glyphs:
377 for( uint i = startElement; i < list.count(); ++i )
378 {
379 if( list.item( i ).isElement() )
380 {
381 e = list.item( i ).toElement();
382 if( e.tagName() == "PATH" )
383 {
384 VPath *composite = new VPath( this );
385 composite->load( e );
386 m_glyphs.append( composite );
387 }
388 if( e.tagName() == "STROKE" )
389 m_stroke->load( e );
390 if( e.tagName() == "FILL" )
391 m_fill->load( e );
392 }
393 }
394 // if no glyphs yet, trace them
395#ifdef HAVE_KARBONTEXT
396 if( m_glyphs.count() == 0 )
397 traceText();
398#endif
399 m_boundingBoxIsInvalid = true;
400 //m_fill->setFillRule( VFill::evenOdd );
401}
402
403void
404VText::setText( const TQString& text )
405{
406 if( m_text != text )
407 {
408 m_text = text;
409 m_glyphs.clear();
410#ifdef HAVE_KARBONTEXT
411 traceText();
412#endif
413 }
414}
415
416void
417VText::setState( const VState state )
418{
419 VObject::setState( state );
420
421 VPathListIterator itr( m_glyphs );
422 for( itr.toFirst(); itr.current(); ++itr )
423 {
424 itr.current()->setState( state );
425 }
426}
427
428void
429VText::accept( VVisitor& visitor )
430{
431 visitor.visitVText( *this );
432}
433
434#ifdef HAVE_KARBONTEXT
435
436void
437VText::traceText()
438{
439 if( m_basePath.count() == 0 )
440 {
441 kdDebug(38000) << "Can't draw a text without base path (was: " << m_text << ")." << endl;
442 return;
443 }
444
445 // TODO : set more options
446 int slant = FC_SLANT_ROMAN;
447 if( m_font.italic() )
448 slant = FC_SLANT_ITALIC;
449
450 int weight = 0;
451 if( m_font.bold() )
452 weight = FC_WEIGHT_BOLD;
453
454 // Build FontConfig request pattern
455 int id = -1;
456 TQString filename = buildRequest( m_font.family(), weight, slant, m_font.pointSize(), id );
457 m_glyphs.clear();
458
459 kdDebug(38000) << "Loading " << filename.latin1() << " for requested font \"" << TQString(m_font.family()).latin1() << "\", " << m_font.pointSize() << " pt." << endl;
460
461 FT_UInt glyphIndex;
462 FT_Face fontFace;
463 // TODO : this lib should probably be a singleton (Rob)
464 FT_Library library;
465 FT_Init_FreeType( &library );
466 FT_Error error = FT_New_Face( library, TQFile::encodeName(filename), id, &fontFace );
467
468 if( error )
469 {
470 kdDebug(38000) << "traceText(), could not load font. Aborting!" << endl;
471 return;
472 }
473
474 bool foundCharmap = false;
475
476 // Try to choose unicode charmap
477 for( int charmap = 0; charmap < fontFace->num_charmaps; charmap++ )
478 {
479 if( fontFace->charmaps[charmap]->encoding == ft_encoding_unicode )
480 {
481 FT_Error error = FT_Set_Charmap( fontFace, fontFace->charmaps[charmap] );
482 if( error )
483 {
484 kdDebug(38000) << "traceText(), unable to select unicode charmap." << endl;
485 continue;
486 }
487 foundCharmap = true;
488 }
489 }
490
491 // Choose first charmap if no unicode charmap was found
492 if( ! foundCharmap )
493 {
494 error = FT_Set_Charmap( fontFace, fontFace->charmaps[0] );
495 if( error )
496 {
497 kdDebug(38000) << "traceText(), unable to select charmap. Aborting!" << endl;
498 FT_Done_Face( fontFace );
499 FT_Done_FreeType( library );
500 return;
501 }
502 }
503
504 error = FT_Set_Char_Size( fontFace, FT_FROMFLOAT( m_font.pointSize() ), FT_FROMFLOAT( m_font.pointSize() ), 0, 0 );
505 if( error )
506 {
507 kdDebug(38000) << "traceText(), unable to set font size. Aborting!" << endl;
508 FT_Done_Face( fontFace );
509 FT_Done_FreeType( library );
510 return;
511 }
512
513 // storing glyphs.
514 float l = 0;
515 TQValueList<float> glyphXAdvance;
516 TQValueList<float> glyphYAdvance;
517 for( unsigned int i = 0; i < m_text.length(); i++ )
518 {
519 // get the glyph index for the current character
520 TQChar character = m_text.at( i );
521 glyphIndex = FT_Get_Char_Index( fontFace, character.unicode() );
522 if( ! glyphIndex )
523 {
524 kdDebug(38000) << "traceText(), unable get index of char : " << character << endl;
525 continue;
526 }
527 //kdDebug(38000) << "glyphIndex : " << glyphIndex << endl;
528 FT_Error error = FT_Load_Glyph( fontFace, glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP );
529 if( error )
530 {
531 kdDebug(38000) << "traceText(), unable to load glyph : " << error << endl;
532 continue;
533 }
534
535 // decompose to vpaths
536 FT_OutlineGlyph g;
537 error = FT_Get_Glyph( fontFace->glyph, reinterpret_cast<FT_Glyph *>( &g ) );
538 if( error )
539 {
540 kdDebug(38000) << "traceText(), unable to get glyph: " << error << endl;
541 continue;
542 }
543
544 VPath *composite = new VPath( this );
545 error = FT_Outline_Check( &g->outline );
546 if( error )
547 {
548 kdDebug(38000) << "traceText(), outline is broken : " << error << endl;
549 continue;
550 }
551
552 error = FT_Outline_Decompose(&g->outline, &OutlineMethods, composite );
553 if( error )
554 {
555 kdDebug(38000) << "traceText(), unable to decompose outline : " << error << endl;
556 continue;
557 }
558
559 m_glyphs.append( composite );
560 glyphXAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.x ) );
561 glyphYAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.y ) );
562 l += FT_TOFLOAT( fontFace->glyph->advance.x );
563 FT_Done_Glyph( reinterpret_cast<FT_Glyph>( g ) );
564 }
565
566 // Placing the stored glyphs.
567 float pathLength = 0;
568 VSubpathIterator pIt( m_basePath );
569
570 VSegment* seg;
571 for( ; pIt.current(); ++pIt )
572 if( (seg = pIt.current() ) )
573 pathLength += seg->length();
574
575 kdDebug(38000) << "traceText(), using offset : " << m_offset << endl;
576 float x = m_offset * pathLength;
577
578 switch( m_alignment )
579 {
580 case Left: x += 0; break;
581 case Center: x -= 0.5 * l; break;
582 case Right: x -= l; break;
583 }
584 float y = 0;
585 float dx = 0;
586 float sp = 0;
587 KoPoint point;
588 KoPoint normal;
589 KoPoint tangent;
590 VSubpathIterator pathIt( m_basePath );
591 VSegment* oldSeg = pathIt.current();
592 seg = ++pathIt;
593 KoPoint extPoint;
594 bool ext = false;
595 float fsx = 0;
596 float yoffset = ( m_position == Above ? 0 : ( m_position == On ? m_font.pointSize() / 3 : m_font.pointSize() / 1.5 ) );
597 kdDebug(38000) << "Position: " << m_position << " -> " << yoffset << endl;
598 for( unsigned int i = 0; i < m_text.length(); i++ )
599 {
600 VPath* composite = m_glyphs.at( i );
601 if( ! composite )
602 continue;
603 // Step 1: place (0, 0) to the rotation center of the glyph.
604 dx = *glyphXAdvance.at( i ) / 2;
605 x += dx;
606 VTransformCmd trafo( 0L, TQWMatrix( 1, 0, 0, 1, -dx, y + yoffset ) );
607 trafo.visit( *composite );
608
609 // Step 2: find the position where to draw.
610 // 3 possibilities: before, on, and after the basePath...
611 if ( x < 0 )
612 {
613 if( !ext )
614 seg->pointTangentNormalAt( 0, &extPoint, &tangent, &normal );
615 point = extPoint + x * tangent;
616 ext = true;
617 }
618 else
619 {
620 while ( seg && x > fsx + seg->length() )
621 {
622 fsx += seg->length();
623 oldSeg = seg;
624 seg = ++pathIt;
625 }
626 if( seg )
627 {
628 ext = false;
629 sp = ( x - fsx ) / seg->length();
630 seg->pointTangentNormalAt( sp, &point, &tangent, &normal );
631 }
632 else
633 {
634 if( !ext )
635 oldSeg->pointTangentNormalAt( 1, &extPoint, &tangent, &normal );
636 point = extPoint + ( x - fsx ) * tangent;
637 ext = true;
638 }
639 }
640
641 // Step 3: transform glyph and append it. That's it, we've got
642 // text following a path. Really easy, isn't it ;) ?
643 trafo.setMatrix( TQWMatrix( tangent.x(), tangent.y(), tangent.y(), -tangent.x(), point.x(), point.y() ) );
644 trafo.visit( *composite );
645 composite->setState( state() );
646
647 //kdDebug(38000) << "Glyph: " << (TQString)character << " [String pos: " << x << ", " << y << " / Canvas pos: " << point.x() << ", " << point.y() << "]" << endl;
648
649 x += dx;
650 y += *glyphYAdvance.at( i );
651 }
652 FT_Done_Face( fontFace );
653 FT_Done_FreeType( library );
654 m_boundingBoxIsInvalid = true;
655}
656
657// This routine is copied from KSVGFont (Rob)
658TQString
659VText::buildRequest( TQString family, int weight, int slant, double size, int &id )
660{
661 // Strip those stupid [Xft or whatever]...
662 int pos;
663 if( ( pos = family.find( '[' ) ) )
664 family = family.left( pos );
665
666 // Use FontConfig to locate & select fonts and use FreeType2 to open them
667 FcPattern *pattern;
668 TQString fileName;
669
670 pattern = FcPatternBuild( 0, FC_WEIGHT, FcTypeInteger, weight,
671 FC_SLANT, FcTypeInteger, slant,
672 FC_SIZE, FcTypeDouble, size, NULL );
673
674 // Add font name
675 FcPatternAddString( pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>( family.latin1() ) );
676
677 // Disable hinting
678 FcPatternAddBool( pattern, FC_HINTING, FcFalse );
679 // Enforce scalability
680 FcPatternAddBool( pattern, FC_SCALABLE, FcTrue );
681
682 // Perform the default font pattern modification operations.
683 FcDefaultSubstitute( pattern );
684 FcConfigSubstitute( FcConfigGetCurrent(), pattern, FcMatchPattern );
685
686 FcResult result;
687
688 // we dont want to use bitmap fonts, so get a list of fonts sorted by closeness to pattern
689 // and use the best matching scalable font
690 FcFontSet *fset = FcFontSort( 0, pattern, FcFalse, 0L, &result );
691
692 // Destroy pattern
693 FcPatternDestroy( pattern );
694
695 if( fset )
696 {
697 FcBool scalable;
698 FcChar8 *temp;
699
700 // iterate over font list and take best scaleable font
701 for( int i = 0; i < fset->nfont; ++i )
702 {
703 pattern = fset->fonts[i];
704 if( FcResultMatch != FcPatternGetBool( pattern, FC_SCALABLE, 0, &scalable ) )
705 continue;
706 if( scalable == FcTrue )
707 {
708 // Get index & filename
709 if( FcPatternGetString(pattern, FC_FILE, 0, &temp) != FcResultMatch ||
710 FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch )
711 {
712 kdDebug(38000) << "VText::buildRequest(), could not load font file for requested font \"" << family.latin1() << "\"" << endl;
713 return TQString();
714 }
715
716 fileName = TQFile::decodeName(reinterpret_cast<const char *>( temp ));
717
718 // get family name of matched font
719 TQString newFamily;
720
721 if( FcResultMatch == FcPatternGetString( pattern, FC_FAMILY, 0, &temp ) )
722 m_font.setFamily( reinterpret_cast<const char *>( temp ) );
723
724 break;
725 }
726 }
727
728 FcFontSetDestroy( fset );
729 }
730
731
732 return fileName;
733}
734
735#endif // HAVE_KARBONTEXT
736
737void VText::setOffset( double offset )
738{
739 if( offset < 0.0 )
740 m_offset = 0.0;
741 else if( offset > 1.0 )
742 m_offset = 1.0;
743 else
744 m_offset = offset;
745}
746
This class keeps track of color properties.
Definition vcolor.h:41
void set(float v1)
Sets the first color component.
Definition vcolor.h:91
void setOpacity(float opacity)
Sets the color opacity.
Definition vcolor.h:138
Manages the fill of shapes.
Definition vfill.h:45
Base class for all sort of VObject conglomerats.
Definition vgroup.h:35
virtual void setStroke(const VStroke &stroke)
Sets the stroke to a given new stroke.
Definition vgroup.cpp:137
virtual void setFill(const VFill &fill)
Sets the fill to a given new fill.
Definition vgroup.cpp:126
void append(VObject *object)
Appends a new child object.
Definition vgroup.cpp:372
The base class for all karbon objects.
Definition vobject.h:50
virtual void setState(const VState state)
Sets the state to a specified new state.
Definition vobject.h:163
void setParent(VObject *parent)
Sets a new parent object.
Definition vobject.h:140
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
Definition vobject.cpp:157
virtual void save(TQDomElement &element) const
Save this object's state to xml.
Definition vobject.cpp:102
A composite path consists of one or many subpaths.
Definition vcomposite.h:48
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
virtual VPath * clone() const
Create an exact copy of this object.
A class representing lines and beziers.
Definition vsegment.h:43
double length(double t=1.0) const
Calculates the arclength from p0 to the point parametrized by 0 <= t <= 1.
Definition vsegment.cpp:291
void pointTangentNormalAt(double t, KoPoint *p=0L, KoPoint *tn=0L, KoPoint *n=0L) const
Calculates the point, the tangent vector and the normal vector for 0 <= t <= 1.
Definition vsegment.cpp:258
Manages stroke properties.
Definition vstroke.h:49
VSubpathIterator provides an iterator class for highlevel path access.
Definition vpath.h:180
VSubpath provides a sophisticated list of VSegment.
Definition vpath.h:43
The abstract visitor class.
Definition vvisitor.h:51
virtual void visitVText(VText &text)
Visit method for a VText.
Definition vvisitor.cpp:102