karbon

vkopainter.cpp
1/* This file is part of the KDE project.
2 Copyright (C) 2001, 2002, 2003 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// kopainter/libart wrapper
21
22#include "vkopainter.h"
23#include "vstroke.h"
24#include "vfill.h"
25#include "vcolor.h"
26#include "vpattern.h"
27
28#include <tqpaintdevice.h>
29#include <tqpixmap.h>
30#include <tqpointarray.h>
31#include <tqimage.h>
32
33#include "libart_lgpl/art_vpath.h"
34#include <libart_lgpl/art_bpath.h>
35#include <libart_lgpl/art_vpath_bpath.h>
36#include <libart_lgpl/art_svp_vpath.h>
37#include <libart_lgpl/art_svp_vpath_stroke.h>
38#include <libart_lgpl/art_svp.h>
39#include <libart_lgpl/art_svp_ops.h>
40#include <libart_lgpl/art_affine.h>
41#include <libart_lgpl/art_svp_intersect.h>
42#include <libart_lgpl/art_rect_svp.h>
43#include <libart_lgpl/art_pathcode.h>
44#include <libart_lgpl/art_vpath_dash.h>
45#include "art_rgba_affine.h"
46#include "art_render_misc.h"
47#include <libart_lgpl/art_render_svp.h>
48
49#include "art_rgb_svp.h"
50#include "art_render_pattern.h"
51
52#include <X11/Xlib.h>
53
54#include <gdk-pixbuf-xlibrgb.h>
55
56#include <kdebug.h>
57#include <tdeglobal.h>
58#include <kiconloader.h>
59#include <math.h>
60
61#include <KoPoint.h>
62#include <KoRect.h>
63#include <karbon_factory.h>
64#include <karbon_resourceserver.h>
65
66
67#define INITIAL_ALLOC 300
68#define ALLOC_INCREMENT 100
69
70VKoPainter::VKoPainter( TQPaintDevice *target, unsigned int w, unsigned int h, bool bDrawNodes )
71: VPainter( target, w, h ), m_target( target ), m_bDrawNodes( bDrawNodes )
72{
73 //kdDebug(38000) << "w : " << w << endl;
74 //kdDebug(38000) << "h : " << h << endl;
75 m_width = w;//( w > 0 ) ? w : target->width();
76 m_height= h;//( h > 0 ) ? h : target->height();
77 m_buffer = 0L;
78 m_path = 0L;
79 m_index = 0;
80 resize( m_width, m_height );
81 clear();
82 m_clipPaths.setAutoDelete( false );
83
84 m_stroke = 0L;
85 m_fill = 0L;
86 m_fillRule = evenOdd;
87
88 xlib_rgb_init_with_depth( target->x11Display(), XScreenOfDisplay( target->x11Display(),
89 target->x11Screen() ), target->x11Depth() );
90
91 gc = XCreateGC( target->x11Display(), target->handle(), 0, 0 );
92
93 m_zoomFactor = 1;
94}
95
96VKoPainter::VKoPainter( unsigned char *buffer, unsigned int w, unsigned int h, bool bDrawNodes )
97: VPainter( 0L, w, h ), m_buffer( buffer ), m_bDrawNodes( bDrawNodes )
98{
99 //kdDebug(38000) << "w : " << w << endl;
100 //kdDebug(38000) << "h : " << h << endl;
101 m_target = 0L;
102 m_width = w;
103 m_height= h;
104 m_path = 0L;
105 m_index = 0;
106 clear();
107 m_clipPaths.setAutoDelete( false );
108
109 m_stroke = 0L;
110 m_fill = 0L;
111
112 gc = 0L;
113
114 m_zoomFactor = 1;
115}
116
117VKoPainter::~VKoPainter()
118{
119 // If we are in target mode, we created a buffer, else if we used the other ctor
120 // we didn't.
121 if( m_target )
122 art_free( m_buffer );
123
124 delete m_stroke;
125 delete m_fill;
126 if( m_path )
127 art_free( m_path );
128
129 if( gc )
130 XFreeGC( m_target->x11Display(), gc );
131}
132
133void
134VKoPainter::resize( unsigned int w, unsigned int h )
135{
136 if( !m_buffer || w != m_width || h != m_height )
137 {
138 // TODO : realloc?
139 art_free( m_buffer );
140 m_buffer = 0;
141 m_width = w;
142 m_height = h;
143 if ( m_width != 0 && m_height != 0 )
144 m_buffer = art_new( art_u8, m_width * m_height * 4 );
145 clear();
146 }
147}
148
149void
150VKoPainter::begin()
151{
152}
153
154void
155VKoPainter::end()
156{
157 //xlib_draw_rgb_image( m_target->handle(), gc, 0, 0, m_width, m_height,
158 // XLIB_RGB_DITHER_NONE, m_buffer, m_width * 4 );
159 xlib_draw_rgb_32_image( m_target->handle(), gc, 0, 0, m_width, m_height,
160 XLIB_RGB_DITHER_NONE, m_buffer, m_width * 4 );
161 /*xlib_draw_rgb_image( pix.handle(), gc, 0, 0, m_width, m_height,
162 XLIB_RGB_DITHER_NONE, m_buffer, m_width * 3 );
163 bitBlt( m_target, 0, 0, &pix, 0, 0, m_width, m_height );*/
164}
165
166void
167VKoPainter::blit( const KoRect &r )
168{
169 //kdDebug(38000) << "m_width : " << m_width << endl;
170 //kdDebug(38000) << "m_height : " << m_height << endl;
171 int x = KMAX( 0, int( r.x() ) );
172 int y = KMAX( 0, int( r.y() ) );
173 int width = KMIN( m_width, (unsigned int)KMAX( 0, int( r.x() + r.width() ) ) );
174 int height = KMIN( m_height, (unsigned int)KMAX( 0, int( r.y() + r.height() ) ) );
175 xlib_draw_rgb_32_image( m_target->handle(), gc, x, y, width - x, height - y,
176 XLIB_RGB_DITHER_NONE, m_buffer + (x * 4) + (y * m_width * 4), m_width * 4 );
177}
178
179void
180VKoPainter::clear()
181{
182 if( m_buffer )
183 memset( m_buffer, tqRgba( 255, 255, 255, 255 ), m_width * m_height * 4 );
184}
185
186void
187VKoPainter::clear( const TQColor &c )
188{
189 if( m_buffer )
190 memset( m_buffer, c.rgb(), m_width * m_height * 4 );
191}
192
193void
194VKoPainter::clear( const KoRect &r, const TQColor &c )
195{
196 unsigned int color = c.rgb();
197 int x = KMAX( 0, int( r.x() ) );
198 int y = KMAX( 0, int( r.y() ) );
199 int width = KMIN( m_width, (unsigned int)KMAX( 0, int( r.x() + r.width() ) ) );
200 int height = KMIN( m_height, (unsigned int)KMAX( 0, int( r.y() + r.height() ) ) );
201 if( m_buffer )
202 {
203 for( int i = y;i < height;i++)
204 memset( m_buffer + int( x * 4) + int( i * ( m_width * 4 ) ),
205 tqRgba( tqRed( color ), tqGreen( color ), tqBlue( color ), 100 ), int( width * 4 ) );
206 }
207}
208
209void
210VKoPainter::setWorldMatrix( const TQWMatrix &mat )
211{
212 m_matrix = mat;
213}
214
215void
216VKoPainter::setZoomFactor( double zoomFactor )
217{
218 m_zoomFactor = zoomFactor;
219}
220
221void
222VKoPainter::ensureSpace( unsigned int newindex )
223{
224 if( m_index == 0 )
225 {
226 if( !m_path )
227 m_path = art_new( ArtBpath, INITIAL_ALLOC );
228 m_alloccount = INITIAL_ALLOC;
229 }
230 else if( newindex > m_alloccount )
231 {
232 m_alloccount += ALLOC_INCREMENT;
233 m_path = art_renew( m_path, ArtBpath, m_alloccount );
234 }
235}
236
237void
238VKoPainter::moveTo( const KoPoint &p )
239{
240 ensureSpace( m_index + 1 );
241
242 m_path[ m_index ].code = ART_MOVETO;
243
244 m_path[ m_index ].x3 = p.x() * m_zoomFactor;
245 m_path[ m_index ].y3 = p.y() * m_zoomFactor;
246
247 m_index++;
248}
249
250void
251VKoPainter::lineTo( const KoPoint &p )
252{
253 ensureSpace( m_index + 1 );
254
255 m_path[ m_index ].code = ART_LINETO;
256 m_path[ m_index ].x3 = p.x() * m_zoomFactor;
257 m_path[ m_index ].y3 = p.y() * m_zoomFactor;
258
259 m_index++;
260}
261
262void
263VKoPainter::curveTo( const KoPoint &p1, const KoPoint &p2, const KoPoint &p3 )
264{
265 ensureSpace( m_index + 1 );
266
267 m_path[ m_index ].code = ART_CURVETO;
268 m_path[ m_index ].x1 = p1.x() * m_zoomFactor;
269 m_path[ m_index ].y1 = p1.y() * m_zoomFactor;
270 m_path[ m_index ].x2 = p2.x() * m_zoomFactor;
271 m_path[ m_index ].y2 = p2.y() * m_zoomFactor;
272 m_path[ m_index ].x3 = p3.x() * m_zoomFactor;
273 m_path[ m_index ].y3 = p3.y() * m_zoomFactor;
274
275 m_index++;
276}
277
278void
279VKoPainter::newPath()
280{
281 m_index = 0;
282}
283
284void
285VKoPainter::setFillRule( VFillRule fillRule )
286{
287 m_fillRule = fillRule;
288}
289
290void
291VKoPainter::fillPath()
292{
293 if( m_index == 0 ) return;
294
295 // find begin of last subpath
296 int find = -1;
297 for( int i = m_index - 1; i >= 0; i-- )
298 {
299 if( m_path[i].code == ART_MOVETO_OPEN || m_path[i].code == ART_MOVETO )
300 {
301 find = i;
302 break;
303 }
304 }
305
306 // for now, always close
307 if( find != -1 && ( m_path[ find ].x3 != m_path[ m_index - 1 ].x3 ||
308 m_path[ find ].y3 != m_path[ m_index - 1 ].y3 ) )
309 {
310 ensureSpace( m_index + 1 );
311
312 m_path[ m_index ].code = ART_LINETO;
313 m_path[ m_index ].x3 = m_path[ find ].x3;
314 m_path[ m_index ].y3 = m_path[ find ].y3;
315
316 m_index++;
317 m_path[ m_index ].code = ART_END;
318 }
319 else
320 m_path[ m_index++ ].code = ART_END;
321
322 if( m_fill && m_fill->type() != VFill::none )
323 {
324 ArtVpath *path = art_bez_path_to_vec( m_path , 0.25 );
325 drawVPath( path );
326 }
327
328 m_index--;
329}
330
331void
332VKoPainter::strokePath()
333{
334 if( m_index == 0 ) return;
335
336 if( m_stroke && m_stroke->lineWidth() == 0 )
337 return;
338 if( m_path[ m_index ].code != ART_END)
339 m_path[ m_index ].code = ART_END;
340
341 ArtVpath *path = art_bez_path_to_vec( m_path , 0.25 );
342
343 drawVPath( path );
344}
345
346void
347VKoPainter::setClipPath()
348{
349 ArtVpath *path;
350 path = art_bez_path_to_vec( m_path , 0.25 );
351 m_clipPaths.append( art_svp_from_vpath( path ) );
352 art_free( path );
353}
354
355void
356VKoPainter::resetClipPath()
357{
358 art_svp_free( m_clipPaths.current() );
359 m_clipPaths.remove();
360}
361
362void
363VKoPainter::setPen( const VStroke &stroke )
364{
365 delete m_stroke;
366 m_stroke = new VStroke;
367 *m_stroke = stroke;
368}
369
370void
371VKoPainter::setPen( const TQColor &c )
372{
373 delete m_stroke;
374 m_stroke = new VStroke;
375
376 float r = static_cast<float>( c.red() ) / 255.0;
377 float g = static_cast<float>( c.green() ) / 255.0;
378 float b = static_cast<float>( c.blue() ) / 255.0;
379
380 VColor color;
381 color.set( r, g, b );
382 m_stroke->setColor( color );
383}
384
385void
386VKoPainter::setPen( TQt::PenStyle style )
387{
388 if( style == TQt::NoPen )
389 {
390 delete m_stroke;
391 m_stroke = 0L;
392 }
393}
394
395void
396VKoPainter::setBrush( const TQColor &c )
397{
398 delete m_fill;
399 m_fill = new VFill;
400
401 float r = static_cast<float>( c.red() ) / 255.0;
402 float g = static_cast<float>( c.green() ) / 255.0;
403 float b = static_cast<float>( c.blue() ) / 255.0;
404
405 VColor color;
406 color.set( r, g, b );
407 m_fill->setColor( color );
408}
409
410void
411VKoPainter::setBrush( TQt::BrushStyle style )
412{
413 if( style == TQt::NoBrush )
414 {
415 delete m_fill;
416 m_fill = 0L;
417 }
418}
419
420void
421VKoPainter::setBrush( const VFill &fill )
422{
423 delete m_fill;
424 m_fill = new VFill;
425 *m_fill = fill;
426}
427
428void
429VKoPainter::save()
430{
431}
432
433void
434VKoPainter::restore()
435{
436}
437
438void
439VKoPainter::setRasterOp( TQt::RasterOp )
440{
441}
442
443void
444VKoPainter::clampToViewport( int &x0, int &y0, int &x1, int &y1 )
445{
446 // clamp to viewport
447 x0 = kMax( x0, 0 );
448 x0 = kMin( x0, int( m_width ) );
449 y0 = kMax( y0, 0 );
450 y0 = kMin( y0, int ( m_height ) );
451 x1 = kMax( x1, 0 );
452 x1 = kMin( x1, int( m_width ) );
453 y1 = kMax( y1, 0 );
454 y1 = kMin( y1, int( m_height ) );
455}
456
457void
458VKoPainter::clampToViewport( const ArtSVP &svp, int &x0, int &y0, int &x1, int &y1 )
459{
460 // get SVP bbox
461 ArtDRect bbox;
462 art_drect_svp( &bbox, &svp );
463 // Remove comments if we really decide for SVP bbox usage
464 //m_bbox = KoRect( bbox.x0, bbox.y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0 );
465
466 // clamp to viewport
467 x0 = int( bbox.x0 );
468 x0 = kMax( x0, 0 );
469 x0 = kMin( x0, int( m_width ) );
470 y0 = int( bbox.y0 );
471 y0 = kMax( y0, 0 );
472 y0 = kMin( y0, int ( m_height ) );
473 x1 = int( bbox.x1 ) + 1;
474 x1 = kMax( x1, 0 );
475 x1 = kMin( x1, int( m_width ) );
476 y1 = int( bbox.y1 ) + 1;
477 y1 = kMax( y1, 0 );
478 y1 = kMin( y1, int( m_height ) );
479}
480
481void
482VKoPainter::drawVPath( ArtVpath *vec )
483{
484 ArtSVP *strokeSvp = 0L;
485 ArtSVP *fillSvp = 0L;
486
487 // set up world matrix
488 double affine[6];
489 affine[0] = m_matrix.m11();
490 affine[1] = 0;//m_matrix.m12();
491 affine[2] = 0;//m_matrix.m21();
492 affine[3] = m_matrix.m22();
493 affine[4] = m_matrix.dx();
494 affine[5] = m_matrix.dy();
495 ArtVpath *temp = art_vpath_affine_transform( vec, affine );
496 art_free( vec );
497 vec = temp;
498
499 int af = 0;
500 int as = 0;
501 art_u32 fillColor = 0;
502
503 // filling
504 TQColor color;
505 if( m_fill && m_fill->type() != VFill::none )
506 {
507 color = m_fill->color();
508 af = tqRound( 255 * m_fill->color().opacity() );
509 fillColor = ( 0 << 24 ) | ( color.blue() << 16 ) | ( color.green() << 8 ) | color.red();
510
511 ArtSvpWriter *swr;
512 ArtSVP *temp;
513 temp = art_svp_from_vpath( vec );
514
515 if( m_fillRule == evenOdd )
516 swr = art_svp_writer_rewind_new( ART_WIND_RULE_ODDEVEN );
517 else
518 swr = art_svp_writer_rewind_new( ART_WIND_RULE_NONZERO );
519
520 art_svp_intersector( temp, swr );
521 fillSvp = art_svp_writer_rewind_reap( swr );
522
523 art_svp_free( temp );
524 }
525
526 art_u32 strokeColor = 0;
527 // stroke
528 if( m_stroke && m_stroke->type() != VStroke::none )
529 {
530 ArtPathStrokeCapType capStyle = ART_PATH_STROKE_CAP_BUTT;
531 ArtPathStrokeJoinType joinStyle = ART_PATH_STROKE_JOIN_MITER;
532 // TODO : non rgb support ?
533
534 color = m_stroke->color();
535 as = tqRound( 255 * m_stroke->color().opacity() );
536 strokeColor = ( 0 << 24 ) | ( color.blue() << 16 ) | ( color.green() << 8 ) | color.red();
537
538 double ratio = m_zoomFactor;//sqrt(pow(affine[0], 2) + pow(affine[3], 2)) / sqrt(2);
539 if( m_stroke->dashPattern().array().count() > 0 )
540 {
541 // there are dashes to be rendered
542 ArtVpathDash dash;
543 dash.offset = m_stroke->dashPattern().offset() * ratio;
544 dash.n_dash = m_stroke->dashPattern().array().count();
545 double *dashes = new double[ dash.n_dash ];
546 for( int i = 0; i < dash.n_dash; i++ )
547 dashes[i] = m_stroke->dashPattern().array()[i] * ratio;
548
549 dash.dash = dashes;
550 // get the dashed VPath and use that for the stroke render operation
551 ArtVpath *vec2 = art_vpath_dash( vec, &dash );
552 art_free( vec );
553
554 vec = vec2;
555 delete [] dashes;
556 }
557 // caps translation karbon -> art
558 if( m_stroke->lineCap() == VStroke::capRound )
559 capStyle = ART_PATH_STROKE_CAP_ROUND;
560 else if( m_stroke->lineCap() == VStroke::capSquare )
561 capStyle = ART_PATH_STROKE_CAP_SQUARE;
562
563 // join translation karbon -> art
564 if( m_stroke->lineJoin() == VStroke::joinRound )
565 joinStyle = ART_PATH_STROKE_JOIN_ROUND;
566 else if( m_stroke->lineJoin() == VStroke::joinBevel )
567 joinStyle = ART_PATH_STROKE_JOIN_BEVEL;
568
569 // zoom stroke width;
570 strokeSvp = art_svp_vpath_stroke( vec, joinStyle, capStyle, ratio * m_stroke->lineWidth(), m_stroke->miterLimit(), 0.25 );
571 }
572
573 int x0, y0, x1, y1;
574
575 // render the svp to the buffer
576 if( strokeSvp )
577 {
578 if( m_stroke && m_stroke->type() == VStroke::grad )
579 applyGradient( strokeSvp, false );
580 else if( m_stroke && m_stroke->type() == VStroke::patt )
581 applyPattern( strokeSvp, false );
582 else
583 {
584 clampToViewport( *strokeSvp, x0, y0, x1, y1 );
585 if( x0 != x1 && y0 != y1 )
586 art_rgb_svp_alpha_( strokeSvp, x0, y0, x1, y1, strokeColor, as, m_buffer + x0 * 4 + y0 * m_width * 4, m_width * 4, 0 );
587 }
588 art_svp_free( strokeSvp );
589 }
590
591 if( fillSvp )
592 {
593 if( m_fill && m_fill->type() == VFill::grad )
594 applyGradient( fillSvp, true );
595 else if( m_fill && m_fill->type() == VFill::patt )
596 applyPattern( fillSvp, true );
597 else
598 {
599 clampToViewport( *fillSvp, x0, y0, x1, y1 );
600 if( x0 != x1 && y0 != y1 )
601 art_rgb_svp_alpha_( fillSvp, x0, y0, x1, y1, fillColor, af, m_buffer + x0 * 4 + y0 * m_width * 4, m_width * 4, 0 );
602 }
603 art_svp_free( fillSvp );
604 }
605
606 //delete m_stroke;
607 //m_stroke = 0L;
608 //delete m_fill;
609 //m_fill = 0L;
610
611 art_free( vec );
612}
613
614void
615VKoPainter::applyPattern( ArtSVP *svp, bool fill )
616{
617 if(!svp) {
618 return;
619 }
620
621 int x0, y0, x1, y1;
622 clampToViewport( *svp, x0, y0, x1, y1 );
623
624 ArtRender *render = 0L;
625
626 VPattern pat = fill ? m_fill->pattern() : m_stroke->pattern();
627 if( !pat.isValid() ) {
628 pat.load( TDEGlobal::iconLoader()->iconPath( "karbon.png", -TDEIcon::SizeMedium ) ); }
629 if( !pat.isValid() ) {
630 pat = *(dynamic_cast<VPattern *>(KarbonFactory::rServer()->patterns().getFirst() )) ;}
631
632 ArtPattern *pattern = art_new( ArtPattern, 1 );
633
634 double dx = ( pat.vector().x() - pat.origin().x() ) * m_zoomFactor;
635 double dy = ( pat.vector().y() - pat.origin().y() ) * m_zoomFactor;
636
637 pattern->twidth = pat.tileWidth();
638 pattern->theight = pat.tileHeight();
639 pattern->buffer = pat.pixels();
640 pattern->opacity = fill ? short( m_fill->color().opacity() * 255.0 ) : short( m_stroke->color().opacity() * 255.0 );
641 pattern->angle = atan2( -dy, dx );
642
643 if( x0 != x1 && y0 != y1 )
644 {
645 render = art_render_new( x0, y0, x1, y1, m_buffer + 4 * int(x0) + m_width * 4 * int(y0), m_width * 4, 3, 8, ART_ALPHA_PREMUL, 0 );
646 art_render_svp( render, svp );
647 art_render_pattern( render, pattern, ART_FILTER_HYPER );
648 }
649
650 if( render )
651 art_render_invoke( render );
652 art_free( pattern );
653}
654
655void
656VKoPainter::applyGradient( ArtSVP *svp, bool fill )
657{
658 int x0, y0, x1, y1;
659 clampToViewport( *svp, x0, y0, x1, y1 );
660
661 ArtRender *render = 0L;
662
663 VGradient gradient = fill ? m_fill->gradient() : m_stroke->gradient();
664 float opa = fill ? m_fill->color().opacity() : m_stroke->color().opacity();
665
666 if( gradient.type() == VGradient::linear )
667 {
668 ArtGradientLinear *linear = art_new( ArtGradientLinear, 1 );
669
670 // TODO : make variable
671 if( gradient.repeatMethod() == VGradient::none )
672 linear->spread = ART_GRADIENT_PAD;
673 else if( gradient.repeatMethod() == VGradient::repeat )
674 linear->spread = ART_GRADIENT_REPEAT;
675 else if( gradient.repeatMethod() == VGradient::reflect )
676 linear->spread = ART_GRADIENT_REFLECT;
677
678 double _x1 = gradient.origin().x();
679 double _x2 = gradient.vector().x();
680 double _y2 = gradient.origin().y();
681 double _y1 = gradient.vector().y();
682
683 double dx = ( _x2 - _x1 ) * m_zoomFactor;
684 _y1 = m_matrix.m22() * _y1 + m_matrix.dy() / m_zoomFactor;
685 _y2 = m_matrix.m22() * _y2 + m_matrix.dy() / m_zoomFactor;
686 double dy = ( _y1 - _y2 ) * m_zoomFactor;
687 double scale = 1.0 / ( dx * dx + dy * dy );
688
689 linear->a = dx * scale;
690 linear->b = dy * scale;
691 linear->c = -( ( _x1 * m_zoomFactor + m_matrix.dx() ) * linear->a +
692 ( _y2 * m_zoomFactor ) * linear->b );
693
694 // get stop array
695 int offsets = -1;
696 linear->stops = buildStopArray( gradient, offsets );
697 linear->n_stops = offsets;
698
699 if( x0 != x1 && y0 != y1 && offsets >= 0 )
700 {
701 render = art_render_new( x0, y0, x1, y1, m_buffer + 4 * int(x0) + m_width * 4 * int(y0), m_width * 4, 3, 8, ART_ALPHA_PREMUL, 0 );
702 int opacity = int( opa * 255.0 );
703 art_render_svp( render, svp );
704 art_render_mask_solid (render, (opacity << 8) + opacity + (opacity >> 7));
705 art_karbon_render_gradient_linear( render, linear, ART_FILTER_NEAREST );
706 art_render_invoke( render );
707 }
708 art_free( linear->stops );
709 art_free( linear );
710 }
711 else if( gradient.type() == VGradient::radial )
712 {
713 ArtGradientRadial *radial = art_new( ArtGradientRadial, 1 );
714
715 // TODO : make variable
716 if( gradient.repeatMethod() == VGradient::none )
717 radial->spread = ART_GRADIENT_PAD;
718 else if( gradient.repeatMethod() == VGradient::repeat )
719 radial->spread = ART_GRADIENT_REPEAT;
720 else if( gradient.repeatMethod() == VGradient::reflect )
721 radial->spread = ART_GRADIENT_REFLECT;
722
723 radial->affine[0] = m_matrix.m11();
724 radial->affine[1] = m_matrix.m12();
725 radial->affine[2] = m_matrix.m21();
726 radial->affine[3] = m_matrix.m22();
727 radial->affine[4] = m_matrix.dx();
728 radial->affine[5] = m_matrix.dy();
729
730 double cx = gradient.origin().x() * m_zoomFactor;
731 double cy = gradient.origin().y() * m_zoomFactor;
732 double fx = gradient.focalPoint().x() * m_zoomFactor;
733 double fy = gradient.focalPoint().y() * m_zoomFactor;
734 double r = sqrt( pow( gradient.vector().x() - gradient.origin().x(), 2 ) +
735 pow( gradient.vector().y() - gradient.origin().y(), 2 ) );
736 r *= m_zoomFactor;
737
738 radial->fx = (fx - cx) / r;
739 radial->fy = (fy - cy) / r;
740
741 double aff1[6], aff2[6];
742 art_affine_scale( aff1, r, r);
743 art_affine_translate( aff2, cx, cy );
744 art_affine_multiply( aff1, aff1, aff2 );
745 art_affine_multiply( aff1, aff1, radial->affine );
746 art_affine_invert( radial->affine, aff1 );
747
748 // get stop array
749 int offsets = -1;
750 radial->stops = buildStopArray( gradient, offsets );
751 radial->n_stops = offsets;
752
753 if( x0 != x1 && y0 != y1 && offsets >= 0 )
754 {
755 render = art_render_new( x0, y0, x1, y1, m_buffer + 4 * x0 + m_width * 4 * y0, m_width * 4, 3, 8, ART_ALPHA_PREMUL, 0 );
756 int opacity = int( opa * 255.0 );
757 art_render_svp( render, svp );
758 art_render_mask_solid (render, (opacity << 8) + opacity + (opacity >> 7));
759 art_karbon_render_gradient_radial( render, radial, ART_FILTER_NEAREST );
760 art_render_invoke( render );
761 }
762 art_free( radial->stops );
763 art_free( radial );
764 }
765 else if( gradient.type() == VGradient::conic )
766 {
767 ArtGradientConical *conical = art_new( ArtGradientConical, 1 );
768
769 // TODO : make variable
770 if( gradient.repeatMethod() == VGradient::none )
771 conical->spread = ART_GRADIENT_PAD;
772 else if( gradient.repeatMethod() == VGradient::repeat )
773 conical->spread = ART_GRADIENT_REPEAT;
774 else if( gradient.repeatMethod() == VGradient::reflect )
775 conical->spread = ART_GRADIENT_REFLECT;
776
777 double cx = gradient.origin().x() * m_zoomFactor;
778 cx = m_matrix.m11() * cx + m_matrix.dx();
779 double cy = gradient.origin().y() * m_zoomFactor;
780 cy = m_matrix.m22() * cy + m_matrix.dy();
781 double r = sqrt( pow( gradient.vector().x() - gradient.origin().x(), 2 ) +
782 pow( gradient.vector().y() - gradient.origin().y(), 2 ) );
783 r *= m_zoomFactor;
784
785 conical->cx = cx;
786 conical->cy = cy;
787 conical->r = r;
788
789 // get stop array
790 int offsets = -1;
791 conical->stops = buildStopArray( gradient, offsets );
792 conical->n_stops = offsets;
793
794 if( x0 != x1 && y0 != y1 && offsets >= 0 )
795 {
796 render = art_render_new( x0, y0, x1, y1, m_buffer + 4 * x0 + m_width * 4 * y0, m_width * 4, 3, 8, ART_ALPHA_PREMUL, 0 );
797 int opacity = int( opa * 255.0 );
798 art_render_svp( render, svp );
799 art_render_mask_solid (render, (opacity << 8) + opacity + (opacity >> 7));
800 art_karbon_render_gradient_conical( render, conical, ART_FILTER_NEAREST );
801 art_render_invoke( render );
802 }
803 art_free( conical->stops );
804 art_free( conical );
805 }
806}
807
808ArtGradientStop *
809VKoPainter::buildStopArray( VGradient &gradient, int &offsets )
810{
811 // TODO : make this generic
812 TQPtrVector<VColorStop> colorStops = gradient.colorStops();
813 offsets = colorStops.count();
814
815 ArtGradientStop *stopArray = art_new( ArtGradientStop, offsets * 2 - 1 );
816
817 for( int offset = 0 ; offset < offsets ; offset++ )
818 {
819 double ramp = colorStops[ offset ]->rampPoint;
820 //double mid = colorStops[ offset ]->midPoint;
821 stopArray[ offset * 2 ].offset = ramp;
822
823 TQColor qStopColor = colorStops[ offset ]->color;
824 int r = tqRed( qStopColor.rgb() );
825 int g = tqGreen( qStopColor.rgb() );
826 int b = tqBlue( qStopColor.rgb() );
827 art_u32 rgba = (r << 24) | (g << 16) | (b << 8) | tqAlpha(qStopColor.rgb());
828 /* convert from separated to premultiplied alpha */
829 int a = int( colorStops[ offset]->color.opacity() * 255.0 );
830 r = (rgba >> 24) * a + 0x80;
831 r = (r + (r >> 8)) >> 8;
832 g = ((rgba >> 16) & 0xff) * a + 0x80;
833 g = (g + (g >> 8)) >> 8;
834 b = ((rgba >> 8) & 0xff) * a + 0x80;
835 b = (b + (b >> 8)) >> 8;
836 stopArray[ offset * 2 ].color[ 0 ] = ART_PIX_MAX_FROM_8(r);
837 stopArray[ offset * 2 ].color[ 1 ] = ART_PIX_MAX_FROM_8(g);
838 stopArray[ offset * 2 ].color[ 2 ] = ART_PIX_MAX_FROM_8(b);
839 stopArray[ offset * 2 ].color[ 3 ] = ART_PIX_MAX_FROM_8(a);
840
841 if( offset + 1 != offsets )
842 {
843 stopArray[ offset * 2 + 1 ].offset = ramp + ( colorStops[ offset + 1 ]->rampPoint - ramp ) * colorStops[ offset ]->midPoint;
844
845 TQColor qStopColor2 = colorStops[ offset + 1 ]->color;
846 rgba = int(r + ((tqRed(qStopColor2.rgb()) - r)) * 0.5) << 24 |
847 int(g + ((tqGreen(qStopColor2.rgb()) - g)) * 0.5) << 16 |
848 int(b + ((tqBlue(qStopColor2.rgb()) - b)) * 0.5) << 8 |
849 tqAlpha(qStopColor2.rgb());
850 /* convert from separated to premultiplied alpha */
851 int a = int( colorStops[ offset]->color.opacity() * 255.0 );
852 r = (rgba >> 24) * a + 0x80;
853 r = (r + (r >> 8)) >> 8;
854 g = ((rgba >> 16) & 0xff) * a + 0x80;
855 g = (g + (g >> 8)) >> 8;
856 b = ((rgba >> 8) & 0xff) * a + 0x80;
857 b = (b + (b >> 8)) >> 8;
858 stopArray[ offset * 2 + 1 ].color[ 0 ] = ART_PIX_MAX_FROM_8(r);
859 stopArray[ offset * 2 + 1 ].color[ 1 ] = ART_PIX_MAX_FROM_8(g);
860 stopArray[ offset * 2 + 1 ].color[ 2 ] = ART_PIX_MAX_FROM_8(b);
861 stopArray[ offset * 2 + 1 ].color[ 3 ] = ART_PIX_MAX_FROM_8(a);
862 }
863 }
864
865 offsets = offsets * 2 - 1;
866 return stopArray;
867}
868
869void
870VKoPainter::drawNode( const KoPoint& p, int width )
871{
872 if( !m_bDrawNodes ) return;
873
874 KoPoint _p( m_matrix.map( TQPoint( int( p.x() * m_zoomFactor ), int( p.y() * m_zoomFactor ) ) ) );
875 int x1 = int( _p.x() - width );
876 int x2 = int( _p.x() + width );
877 int y1 = int( _p.y() - width );
878 int y2 = int( _p.y() + width );
879
880 clampToViewport( x1, y1, x2, y2 );
881
882 int baseindex = 4 * x1 + ( m_width * 4 * y1 );
883
884 TQColor color = m_fill->color();
885 for( int i = 0; i < y2 - y1; i++ )
886 {
887 for( int j = 0; j < x2 - x1; j++ )
888 {
889 m_buffer[ baseindex + 4 * j + ( m_width * 4 * i ) ] = color.red();
890 m_buffer[ baseindex + 4 * j + ( m_width * 4 * i ) + 1 ] = color.green();
891 m_buffer[ baseindex + 4 * j + ( m_width * 4 * i ) + 2 ] = color.blue();
892 m_buffer[ baseindex + 4 * j + ( m_width * 4 * i ) + 3 ] = 0xFF;
893 }
894 }
895}
896
897void
898VKoPainter::drawImage( const TQImage &image, const TQWMatrix &affine )
899{
900 // set up world matrix
901 double affineresult[6];
902
903 affineresult[0] = affine.m11() * m_matrix.m11() * m_zoomFactor + affine.m12() * m_matrix.m21();
904 affineresult[1] = (affine.m11() * m_matrix.m12() + affine.m12() * m_matrix.m22() ) * m_zoomFactor;
905 affineresult[2] = (affine.m21() * m_matrix.m11() + affine.m22() * m_matrix.m21() ) * m_zoomFactor;
906 affineresult[3] = affine.m22() * m_matrix.m22() * m_zoomFactor + affine.m21() * m_matrix.m12();
907 affineresult[4] = m_matrix.dx() + affine.dx() * m_zoomFactor;
908 affineresult[5] = m_matrix.dy() - affine.dy() * m_zoomFactor;
909
910 //art_affine_scale( affineresult, m_zoomFactor, m_zoomFactor);
911 /*kdDebug(38000) << "affineresult[0] : " << affineresult[0] << endl;
912 kdDebug(38000) << "affineresult[1] : " << affineresult[1] << endl;
913 kdDebug(38000) << "affineresult[2] : " << affineresult[2] << endl;
914 kdDebug(38000) << "affineresult[3] : " << affineresult[3] << endl;
915 kdDebug(38000) << "affineresult[4] : " << affineresult[4] << endl;
916 kdDebug(38000) << "affineresult[5] : " << affineresult[5] << endl;
917 kdDebug(38000) << "m_matrix.dx() : " << m_matrix.dx() << endl;
918 kdDebug(38000) << "affine.dx() : " << affine.dx() << endl;
919 kdDebug(38000) << "image.height() : " << image.height() << endl;*/
920 art_rgba_affine( m_buffer, 0, 0, m_width, m_height, m_width * 4,
921 image.bits(), image.width(), image.height(), image.width() * 4,
922 affineresult, ART_FILTER_NEAREST, 0L );
923}
924
925void
926VKoPainter::drawRect( const KoRect &r )
927{
928 newPath();
929 moveTo( r.topLeft() );
930 lineTo( r.topRight() );
931 lineTo( r.bottomRight() );
932 lineTo( r.bottomLeft() );
933 lineTo( r.topLeft() );
934 fillPath();
935 strokePath();
936}
937
938void
939VKoPainter::drawRect( double x, double y, double w, double h )
940{
941 drawRect( KoRect( x, y, w, h ) );
942}
943
This class keeps track of color properties.
Definition vcolor.h:41
void set(float v1)
Sets the first color component.
Definition vcolor.h:91
Manages the fill of shapes.
Definition vfill.h:45
@ grad
solid fill
Definition vfill.h:51
@ patt
gradient fill
Definition vfill.h:52
Manages stroke properties.
Definition vstroke.h:49
@ patt
gradient as stroke
Definition vstroke.h:56
@ grad
solid stroke
Definition vstroke.h:55