~ubuntu-branches/ubuntu/breezy/koffice/breezy

« back to all changes in this revision

Viewing changes to karbon/core/vtext.cc

  • Committer: Bazaar Package Importer
  • Author(s): Ben Burton
  • Date: 2004-05-09 11:33:00 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040509113300-vfrdadqsvjfuhn3b
Tags: 1:1.3.1-1
* New upstream bugfix release.
* Built against newer imagemagick (closes: #246623).
* Made koffice-libs/kformula recommend/depend on latex-xft-fonts, which
  provides mathematical fonts that the formula editor can use.  Also
  patched the kformula part to make these fonts the default.
* Changed kword menu hint from "WordProcessors" to "Word processors"
  (closes: #246209).
* Spellchecker configuration is now fixed (closes: #221256, #227568).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 59 Temple Place - Suite 330,
 
17
   Boston, MA 02111-1307, USA.
 
18
*/
 
19
 
 
20
#include <qdom.h>
 
21
#include <qfile.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
 
 
54
int traceMoveto( FT_Vector *to, VPath *composite )
 
55
{
 
56
        double tox = ( to->x / 64.0 );
 
57
        double toy = ( -to->y / 64.0 );
 
58
 
 
59
        //QString add = "M" + QString::number(tox) + "," + QString::number(toy) + " ";
 
60
        //kdDebug(38000) << add.latin1() << endl;
 
61
        composite->moveTo( KoPoint( tox, toy ) );
 
62
 
 
63
        return 0;
 
64
}
 
65
 
 
66
int traceLineto( FT_Vector *to, VPath *composite )
 
67
{
 
68
        double tox = ( to->x / 64.0 );
 
69
        double toy = ( -to->y / 64.0 );
 
70
 
 
71
        //QString add = "L" + QString::number(tox) + "," + QString::number(toy) + " ";
 
72
        //kdDebug(38000) << add.latin1() << endl;
 
73
 
 
74
        composite->lineTo( KoPoint( tox, toy ) );
 
75
 
 
76
        return 0;
 
77
};
 
78
 
 
79
int 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
        //QString add = "Q" + QString::number(x1) + "," + QString::number(y1) + "," + QString::number(x2) + "," + QString::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
 
 
94
int 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
        //QString add = "C" + QString::number(x1) + "," + QString::number(y1) + "," + QString::number(x2) + "," + QString::number(y2) + "," + QString::number(x3) + "," + QString::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
 
 
111
FT_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
 
 
123
VText::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
}
 
137
 
 
138
 
 
139
VText::VText( const QFont &font, const VSubpath& basePath, Position position, Alignment alignment, const QString& text )
 
140
        : VObject( 0L ), m_font( font ), m_basePath( basePath ), m_position( position ), m_alignment( alignment ), m_text( text )
 
141
{
 
142
        m_glyphs.setAutoDelete( true );
 
143
        m_boundingBoxIsInvalid = true;
 
144
        m_stroke = new VStroke( this );
 
145
        m_fill = new VFill();
 
146
}
 
147
 
 
148
VText::VText( const VText& text )
 
149
        : 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 )
 
150
{
 
151
        m_stroke = new VStroke( *text.m_stroke );
 
152
        m_stroke->setParent( this );
 
153
        m_fill = new VFill( *text.m_fill );
 
154
 
 
155
        // copy glyphs
 
156
        VPathListIterator itr( text.m_glyphs );
 
157
        for( ; itr.current() ; ++itr )
 
158
        {
 
159
                VPath* c = itr.current()->clone();
 
160
                c->setParent( this );
 
161
                m_glyphs.append( c );
 
162
        }
 
163
 
 
164
        m_boundingBoxIsInvalid = true;
 
165
}
 
166
 
 
167
VText::~VText()
 
168
{
 
169
}
 
170
 
 
171
DCOPObject* VText::dcopObject()
 
172
{
 
173
        if( !m_dcop )
 
174
                m_dcop = new VTextIface( this );
 
175
 
 
176
        return m_dcop;
 
177
}
 
178
 
 
179
 
 
180
void
 
181
VText::draw( VPainter* painter, const KoRect* /*rect*/ ) const
 
182
{
 
183
        if(
 
184
                state() == deleted ||
 
185
                state() == hidden ||
 
186
                state() == hidden_locked )
 
187
        {
 
188
                return;
 
189
        }
 
190
 
 
191
        painter->save();
 
192
 
 
193
        VPathListIterator itr( m_glyphs );
 
194
 
 
195
        if( state() != edit )
 
196
        {
 
197
                // paint fill:
 
198
                painter->newPath();
 
199
 
 
200
                if ( m_shadow )
 
201
                {
 
202
                        VColor color;
 
203
                        if ( m_translucentShadow )
 
204
                        {
 
205
                                color.set( 0., 0., 0. );
 
206
                                color.setOpacity( .3 );
 
207
                        }
 
208
                        else
 
209
                        {
 
210
                                color.set( .3, .3, .3 );
 
211
                                color.setOpacity( 1. );
 
212
                        }
 
213
                        int shadowDx = int( m_shadowDistance * cos( m_shadowAngle / 360. * 6.2832 ) );
 
214
                        int shadowDy = int( m_shadowDistance * sin( m_shadowAngle / 360. * 6.2832 ) );
 
215
 
 
216
                        VTransformCmd trafo( 0L, QWMatrix() );
 
217
                        for( itr.toFirst(); itr.current(); ++itr )
 
218
                        {
 
219
                                trafo.setMatrix( QWMatrix( 1, 0, 0, 1, shadowDx, shadowDy ) );
 
220
                                trafo.visit( *( itr.current() ) );
 
221
                                itr.current()->setFill( VFill( color ) );
 
222
                                itr.current()->setStroke( VStroke( color ) );
 
223
                                itr.current()->draw( painter );
 
224
                                trafo.setMatrix( QWMatrix( 1, 0, 0, 1, -shadowDx, -shadowDy ) );
 
225
                                trafo.visit( *( itr.current() ) );
 
226
                        }
 
227
                }
 
228
 
 
229
                for( itr.toFirst(); itr.current(); ++itr )
 
230
                {
 
231
                        itr.current()->setFill( *m_fill );
 
232
                        itr.current()->setStroke( *m_stroke );
 
233
                        itr.current()->draw( painter );
 
234
                }
 
235
        }
 
236
 
 
237
        // draw simplistic contour:
 
238
        if( state() == edit )//|| state() == selected )
 
239
        {
 
240
                painter->newPath();
 
241
                painter->setRasterOp( Qt::XorROP );
 
242
                painter->setPen( Qt::yellow );
 
243
                painter->setBrush( Qt::NoBrush );
 
244
 
 
245
                for( itr.toFirst(); itr.current(); ++itr )
 
246
                        itr.current()->draw( painter );
 
247
 
 
248
                painter->strokePath();
 
249
        }
 
250
 
 
251
        painter->restore();
 
252
}
 
253
 
 
254
const KoRect&
 
255
VText::boundingBox() const
 
256
{
 
257
        if( m_boundingBoxIsInvalid )
 
258
        {
 
259
                VPathListIterator itr( m_glyphs );
 
260
                itr.toFirst();
 
261
                // clear:
 
262
                m_boundingBox = itr.current() ? itr.current()->boundingBox() : KoRect();
 
263
                for( ++itr; itr.current(); ++itr )
 
264
                        if( !itr.current()->boundingBox().isEmpty() )
 
265
                                m_boundingBox |= itr.current()->boundingBox();
 
266
 
 
267
                // take line width into account:
 
268
                m_boundingBox.setCoords(
 
269
                        m_boundingBox.left()   - 0.5 * stroke()->lineWidth(),
 
270
                        m_boundingBox.top()    - 0.5 * stroke()->lineWidth(),
 
271
                        m_boundingBox.right()  + 0.5 * stroke()->lineWidth(),
 
272
                        m_boundingBox.bottom() + 0.5 * stroke()->lineWidth() );
 
273
 
 
274
                m_boundingBoxIsInvalid = false;
 
275
        }
 
276
 
 
277
        return m_boundingBox;
 
278
}
 
279
 
 
280
VText*
 
281
VText::clone() const
 
282
{
 
283
        return new VText( *this );
 
284
}
 
285
 
 
286
VGroup* VText::toVGroup() const
 
287
{
 
288
        VGroup* group = new VGroup( parent() );
 
289
 
 
290
        VPathListIterator itr( m_glyphs );
 
291
        for( itr.toFirst(); itr.current(); ++itr )
 
292
        {
 
293
                VPath* c = itr.current()->clone();
 
294
                c->setParent( group );
 
295
                group->append( c );
 
296
        }
 
297
 
 
298
        group->setFill( *m_fill );
 
299
        group->setStroke( *m_stroke );
 
300
 
 
301
        return group;
 
302
} // VText::toVGroup
 
303
 
 
304
void
 
305
VText::save( QDomElement& element ) const
 
306
{
 
307
        if( state() != deleted )
 
308
        {
 
309
                QDomElement me = element.ownerDocument().createElement( "TEXT" );
 
310
 
 
311
                m_basePath.save( me );
 
312
 
 
313
                VObject::save( me );
 
314
 
 
315
                // save font properties
 
316
                me.setAttribute( "text",                                m_text );
 
317
                me.setAttribute( "family",                              m_font.family() );
 
318
                me.setAttribute( "size",                                m_font.pointSize() );
 
319
                me.setAttribute( "italic",                              m_font.italic() );
 
320
                me.setAttribute( "bold",                                m_font.bold() );
 
321
                me.setAttribute( "position",                    m_position );
 
322
                me.setAttribute( "alignment",                   m_alignment );
 
323
                me.setAttribute( "shadow",                              m_shadow );
 
324
                me.setAttribute( "translucentshadow",   m_translucentShadow );
 
325
                me.setAttribute( "shadowangle",                 m_shadowAngle );
 
326
                me.setAttribute( "shadowdist",                  m_shadowDistance );
 
327
 
 
328
                element.appendChild( me );
 
329
 
 
330
                // save all glyphs / paths
 
331
                VPathListIterator itr = m_glyphs;
 
332
                for( itr.toFirst(); itr.current(); ++itr )
 
333
                        itr.current()->save( me );
 
334
        }
 
335
}
 
336
 
 
337
void
 
338
VText::load( const QDomElement& element )
 
339
{
 
340
        m_glyphs.clear();
 
341
 
 
342
        m_font.setFamily( element.attribute( "family", "Times" ) );
 
343
        m_font.setPointSize( element.attribute( "size", "12" ).toInt() );
 
344
        m_font.setItalic( element.attribute( "italic" ) == 0 ? false : true );
 
345
        m_font.setWeight( QFont::Normal );
 
346
        m_font.setBold( element.attribute( "bold" ) == 0 ? false : true );
 
347
        m_position                      = (Position)element.attribute( "position", "0" ).toInt();
 
348
        m_alignment                     = (Alignment)element.attribute( "alignment", "0" ).toInt();
 
349
        m_shadow                        = ( element.attribute( "shadow" ).toInt() == 1 );
 
350
        m_translucentShadow     = ( element.attribute( "translucentshadow" ).toInt() == 1 );
 
351
        m_shadowAngle           = element.attribute( "shadowangle" ).toInt();
 
352
        m_shadowDistance        = element.attribute( "shadowdist" ).toInt();
 
353
 
 
354
        m_text = element.attribute( "text", "" );
 
355
 
 
356
        QDomNodeList list = element.childNodes();
 
357
        QDomElement e = list.item( 0 ).toElement();
 
358
        if( e.tagName() == "PATH" )
 
359
                m_basePath.load( e );
 
360
 
 
361
        // load text glyphs:
 
362
        for( uint i = 1; i < list.count(); ++i )
 
363
        {
 
364
                if( list.item( i ).isElement() )
 
365
                {
 
366
                        e = list.item( i ).toElement();
 
367
                        if( e.tagName() == "PATH" )
 
368
                        {
 
369
                                VPath *composite = new VPath( this );
 
370
                                composite->load( e );
 
371
                                m_glyphs.append( composite );
 
372
                        }
 
373
                        if( e.tagName() == "STROKE" )
 
374
                                m_stroke->load( e );
 
375
                        if( e.tagName() == "FILL" )
 
376
                                m_fill->load( e );
 
377
                }
 
378
        }
 
379
        // if no glyphs yet, trace them
 
380
#ifdef HAVE_KARBONTEXT
 
381
        if( m_glyphs.count() == 0 )
 
382
                traceText();
 
383
#endif
 
384
        m_boundingBoxIsInvalid = true;
 
385
        //m_fill->setFillRule( VFill::evenOdd );
 
386
}
 
387
 
 
388
void
 
389
VText::setText( const QString& text )
 
390
{
 
391
        if( m_text != text )
 
392
        {
 
393
                m_text = text;
 
394
                m_glyphs.clear();
 
395
#ifdef HAVE_KARBONTEXT
 
396
                traceText();
 
397
#endif
 
398
        }
 
399
}
 
400
 
 
401
void
 
402
VText::setState( const VState state )
 
403
{
 
404
        VObject::setState( state );
 
405
 
 
406
        VPathListIterator itr( m_glyphs );
 
407
        for( itr.toFirst(); itr.current(); ++itr )
 
408
        {
 
409
                itr.current()->setState( state );
 
410
        }
 
411
}
 
412
 
 
413
void
 
414
VText::accept( VVisitor& visitor )
 
415
{
 
416
        visitor.visitVText( *this );
 
417
}
 
418
 
 
419
#ifdef HAVE_KARBONTEXT
 
420
 
 
421
void
 
422
VText::traceText()
 
423
{
 
424
        if( m_basePath.count() == 0 )
 
425
        {
 
426
                kdDebug(38000) << "Can't draw a text without base path (was: " << m_text << ")." << endl;
 
427
                return;
 
428
        }
 
429
 
 
430
        // TODO : set more options
 
431
        int slant = FC_SLANT_ROMAN;
 
432
        if( m_font.italic() )
 
433
                slant = FC_SLANT_ITALIC;
 
434
 
 
435
        int weight = 0;
 
436
        if( m_font.bold() )
 
437
                weight = FC_WEIGHT_BOLD;
 
438
 
 
439
        // Build FontConfig request pattern
 
440
        int id = -1;
 
441
        QString filename = buildRequest( m_font.family(), weight, slant, m_font.pointSize(), id );
 
442
        m_glyphs.clear();
 
443
 
 
444
        kdDebug(38000) << "Loading " << filename.latin1() << " for requested font \"" << m_font.family().latin1() << "\", " << m_font.pointSize() << " pt." << endl;
 
445
 
 
446
        FT_UInt glyphIndex;
 
447
        FT_Face fontFace;
 
448
        // TODO : this lib should probably be a singleton (Rob)
 
449
        FT_Library library;
 
450
        FT_Init_FreeType( &library );
 
451
        FT_Error error = FT_New_Face( library, QFile::encodeName(filename), id, &fontFace );
 
452
 
 
453
        if( error )
 
454
        {
 
455
                kdDebug(38000) << "traceText(), could not load font. Aborting!" << endl;
 
456
                return;
 
457
        }
 
458
 
 
459
        // Choose unicode charmap
 
460
        for( int charmap = 0; charmap < fontFace->num_charmaps; charmap++ )
 
461
        {
 
462
                if( fontFace->charmaps[charmap]->encoding == ft_encoding_unicode )
 
463
                {
 
464
                        FT_Error error = FT_Set_Charmap( fontFace, fontFace->charmaps[charmap] );
 
465
                        if( error )
 
466
                        {
 
467
                                kdDebug(38000) << "traceText(), unable to select unicode charmap. Aborting!" << endl;
 
468
                                FT_Done_Face( fontFace );
 
469
                                return;
 
470
                        }
 
471
                }
 
472
        }
 
473
 
 
474
        FT_Set_Char_Size( fontFace, FT_FROMFLOAT( m_font.pointSize() ), FT_FROMFLOAT( m_font.pointSize() ), 0, 0 );
 
475
 
 
476
                // storing glyphs.
 
477
        float l = 0;
 
478
        QValueList<float> glyphXAdvance;
 
479
        QValueList<float> glyphYAdvance;
 
480
        for( unsigned int i = 0; i < m_text.length(); i++ )
 
481
        {
 
482
                // get the glyph index for the current character
 
483
                QChar character = m_text.at( i );
 
484
                glyphIndex = FT_Get_Char_Index( fontFace, character.unicode() );
 
485
                //kdDebug(38000) << "glyphIndex : " << glyphIndex << endl;
 
486
                FT_Error error = FT_Load_Glyph( fontFace, glyphIndex, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP );
 
487
                if( error )
 
488
                {
 
489
                        kdDebug(38000) << "Houston, we have a problem : " << error << endl;
 
490
                        continue;
 
491
                }
 
492
 
 
493
                // decompose to vpaths
 
494
                FT_OutlineGlyph g;
 
495
                FT_Get_Glyph( fontFace->glyph, reinterpret_cast<FT_Glyph *>( &g ) );
 
496
                VPath *composite = new VPath( this );
 
497
                //VFill *fill = composite->fill();
 
498
                //fill->setFillRule( VFill::evenOdd );
 
499
                //composite->setFill( *fill );
 
500
                FT_Outline_Decompose(&g->outline, &OutlineMethods, composite );
 
501
                //composite->close();
 
502
 
 
503
                m_glyphs.append( composite );
 
504
                glyphXAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.x ) );
 
505
                glyphYAdvance.append( FT_TOFLOAT( fontFace->glyph->advance.y ) );
 
506
                l += FT_TOFLOAT( fontFace->glyph->advance.x );
 
507
        }
 
508
 
 
509
         // Placing the stored glyphs.
 
510
        float pathLength = 0;
 
511
        VSubpathIterator pIt( m_basePath );
 
512
        VSegment* seg;
 
513
        while ( ( seg = ++pIt ) )
 
514
                pathLength += seg->length();
 
515
        float x = 0;
 
516
        switch( m_alignment )
 
517
        {
 
518
                case Left: x = 0; break;
 
519
                case Center: x = ( pathLength - l ) / 2; break;
 
520
                case Right: x = pathLength - l; break;
 
521
        }
 
522
        float y = 0;
 
523
        float dx = 0;
 
524
        float sp = 0;
 
525
        KoPoint point;
 
526
        KoPoint normal;
 
527
        KoPoint tangent;
 
528
        VSubpathIterator pathIt( m_basePath );
 
529
        VSegment* oldSeg = pathIt.current();
 
530
        seg = ++pathIt;
 
531
        KoPoint extPoint;
 
532
        bool ext = false;
 
533
        float fsx = 0;
 
534
        float yoffset = ( m_position == Above ? 0 : ( m_position == On ? m_font.pointSize() / 3 : m_font.pointSize() / 1.5 ) );
 
535
        kdDebug(38000) << "Position: " << m_position << " -> " << yoffset << endl;
 
536
        for( unsigned int i = 0; i < m_text.length(); i++ )
 
537
        {
 
538
                VPath* composite = m_glyphs.at( i );
 
539
 
 
540
                // Step 1: place (0, 0) to the rotation center of the glyph.
 
541
                dx = *glyphXAdvance.at( i ) / 2;
 
542
                x += dx;
 
543
                VTransformCmd trafo( 0L, QWMatrix( 1, 0, 0, 1, -dx, y + yoffset ) );
 
544
                trafo.visit( *composite );
 
545
 
 
546
                // Step 2: find the position where to draw.
 
547
                //   3 possibilities: before, on, and after the basePath...
 
548
                if ( x < 0 )
 
549
                {
 
550
                        if( !ext )
 
551
                                seg->pointTangentNormalAt( 0, &extPoint, &tangent, &normal );
 
552
                        point = extPoint + x * tangent;
 
553
                        ext = true;
 
554
                }
 
555
                else
 
556
                {
 
557
                        while ( seg && x > fsx + seg->length() )
 
558
                        {
 
559
                                fsx += seg->length();
 
560
                                oldSeg = seg;
 
561
                                seg = ++pathIt;
 
562
                        }
 
563
                        if( seg )
 
564
                        {
 
565
                                ext = false;
 
566
                                sp = ( x - fsx ) / seg->length();
 
567
                                seg->pointTangentNormalAt( sp, &point, &tangent, &normal );
 
568
                        }
 
569
                        else
 
570
                        {
 
571
                                if( !ext )
 
572
                                        oldSeg->pointTangentNormalAt( 1, &extPoint, &tangent, &normal );
 
573
                                point = extPoint + ( x - fsx ) * tangent;
 
574
                                ext = true;
 
575
                        }
 
576
                }
 
577
 
 
578
                // Step 3: transform glyph and append it. That's it, we've got
 
579
                // text following a path. Really easy, isn't it ;) ?
 
580
                trafo.setMatrix( QWMatrix( tangent.x(), tangent.y(), tangent.y(), -tangent.x(), point.x(), point.y() ) );
 
581
                trafo.visit( *composite );
 
582
                composite->setState( state() );
 
583
 
 
584
                //kdDebug(38000) << "Glyph: " << (QString)character << " [String pos: " << x << ", " << y << " / Canvas pos: " << point.x() << ", " << point.y() << "]" << endl;
 
585
 
 
586
                x += dx;
 
587
                y += *glyphYAdvance.at( i );
 
588
        }
 
589
        FT_Done_Face( fontFace );
 
590
        FT_Done_FreeType( library );
 
591
        m_boundingBoxIsInvalid = true;
 
592
}
 
593
 
 
594
// This routine is copied from KSVGFont (Rob)
 
595
QString
 
596
VText::buildRequest( QString family, int weight, int slant, double size, int &id )
 
597
{
 
598
        // Strip those stupid [Xft or whatever]...
 
599
        int pos;
 
600
        if( ( pos = family.find( '[' ) ) )
 
601
                family = family.left( pos );
 
602
 
 
603
        // Use FontConfig to locate & select fonts and use  FreeType2 to open them
 
604
        FcPattern *pattern;
 
605
        QString fileName;
 
606
 
 
607
        pattern = FcPatternBuild( 0, FC_WEIGHT, FcTypeInteger, weight,
 
608
                                                          FC_SLANT, FcTypeInteger, slant,
 
609
                                                          FC_SIZE, FcTypeDouble, size, 0 );
 
610
 
 
611
        // Add font name
 
612
        FcPatternAddString( pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>( family.latin1() ) );
 
613
 
 
614
        // Disable hinting
 
615
        FcPatternAddBool( pattern, FC_HINTING, false );
 
616
 
 
617
        // Perform the default font pattern modification operations.
 
618
        FcDefaultSubstitute( pattern );
 
619
        FcConfigSubstitute( FcConfigGetCurrent(), pattern, FcMatchPattern );
 
620
 
 
621
        // Match the pattern!
 
622
        FcResult result;
 
623
        FcPattern *match = FcFontMatch( 0, pattern, &result );
 
624
 
 
625
        // Destroy pattern
 
626
        FcPatternDestroy( pattern );
 
627
 
 
628
        // Get index & filename
 
629
        FcChar8 *temp;
 
630
 
 
631
        if(match)
 
632
        {
 
633
                FcPattern *pattern = FcPatternDuplicate( match );
 
634
 
 
635
                // Get index & filename
 
636
                if(     FcPatternGetString(pattern, FC_FILE, 0, &temp) != FcResultMatch ||
 
637
                        FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch )
 
638
                {
 
639
                        kdDebug(38000) << "VText::buildRequest(), could not load font file for requested font \"" << family.latin1() << "\"" << endl;
 
640
                        return QString::null;
 
641
                }
 
642
 
 
643
                fileName = QFile::decodeName(reinterpret_cast<const char *>( temp ));
 
644
 
 
645
                // Kill pattern
 
646
                FcPatternDestroy( pattern );
 
647
        }
 
648
 
 
649
        // Kill pattern
 
650
        FcPatternDestroy( match );
 
651
 
 
652
        return fileName;
 
653
}
 
654
 
 
655
#endif // HAVE_KARBONTEXT