00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <svgimport.h>
00021 #include "color.h"
00022 #include <KoFilterChain.h>
00023 #include <KoPageLayout.h>
00024 #include <kgenericfactory.h>
00025 #include <kdebug.h>
00026 #include <KoUnit.h>
00027 #include <KoGlobal.h>
00028 #include <shapes/vellipse.h>
00029 #include <shapes/vrectangle.h>
00030 #include <shapes/vpolygon.h>
00031 #include <commands/vtransformcmd.h>
00032 #include <core/vsegment.h>
00033 #include <core/vtext.h>
00034 #include <core/vglobal.h>
00035 #include <core/vgroup.h>
00036 #include <core/vimage.h>
00037 #include <core/vlayer.h>
00038 #include <qcolor.h>
00039 #include <qfile.h>
00040 #include <kfilterdev.h>
00041
00042 typedef KGenericFactory<SvgImport, KoFilter> SvgImportFactory;
00043 K_EXPORT_COMPONENT_FACTORY( libkarbonsvgimport, SvgImportFactory( "kofficefilters" ) )
00044
00045 SvgImport::SvgImport(KoFilter *, const char *, const QStringList&) :
00046 KoFilter(),
00047 outdoc( "DOC" )
00048 {
00049 m_gc.setAutoDelete( true );
00050 }
00051
00052 SvgImport::~SvgImport()
00053 {
00054 }
00055
00056 KoFilter::ConversionStatus SvgImport::convert(const QCString& from, const QCString& to)
00057 {
00058
00059 if( to != "application/x-karbon" || from != "image/svg+xml" )
00060 return KoFilter::NotImplemented;
00061
00062
00063 QString strExt;
00064 QString fileIn ( m_chain->inputFile() );
00065 const int result=fileIn.findRev('.');
00066 if (result>=0)
00067 strExt=fileIn.mid(result).lower();
00068
00069 QString strMime;
00070 if ((strExt==".gz")
00071 ||(strExt==".svgz"))
00072 strMime="application/x-gzip";
00073 else if (strExt==".bz2")
00074 strMime="application/x-bzip2";
00075 else
00076 strMime="text/plain";
00077
00078
00079
00080 QIODevice* in = KFilterDev::deviceForFile(fileIn,strMime);
00081
00082 if (!in->open(IO_ReadOnly))
00083 {
00084 kdError(30514) << "Cannot open file! Aborting!" << endl;
00085 delete in;
00086 return KoFilter::FileNotFound;
00087 }
00088
00089 int line, col;
00090 QString errormessage;
00091
00092 const bool parsed=inpdoc.setContent( in, &errormessage, &line, &col );
00093
00094 in->close();
00095 delete in;
00096
00097 if ( ! parsed )
00098 {
00099 kdError(30514) << "Error while parsing file: "
00100 << "at line " << line << " column: " << col
00101 << " message: " << errormessage << endl;
00102
00103 return KoFilter::ParsingError;
00104 }
00105
00106
00107 convert();
00108
00109 QDomElement paper = outdoc.createElement( "PAPER" );
00110 outdoc.documentElement().appendChild( paper );
00111 paper.setAttribute( "format", PG_CUSTOM );
00112 paper.setAttribute( "width", m_document.width() );
00113 paper.setAttribute( "height", m_document.height() );
00114
00115 KoStoreDevice* out = m_chain->storageFile( "root", KoStore::Write );
00116 if( !out )
00117 {
00118 kdError(30514) << "Unable to open output file!" << endl;
00119 return KoFilter::StorageCreationError;
00120 }
00121 QCString cstring = outdoc.toCString();
00122 out->writeBlock( cstring.data(), cstring.length() );
00123
00124 return KoFilter::OK;
00125 }
00126
00127 void SvgImport::convert()
00128 {
00129 SvgGraphicsContext *gc = new SvgGraphicsContext;
00130 QDomElement docElem = inpdoc.documentElement();
00131 KoRect bbox( 0, 0, 550.0, 841.0 );
00132 double width = !docElem.attribute( "width" ).isEmpty() ? parseUnit( docElem.attribute( "width" ), true, false, bbox ) : 550.0;
00133 double height = !docElem.attribute( "height" ).isEmpty() ? parseUnit( docElem.attribute( "height" ), false, true, bbox ) : 841.0;
00134 m_document.setWidth( width );
00135 m_document.setHeight( height );
00136
00137 m_outerRect = m_document.boundingBox();
00138
00139
00140
00141 if( !docElem.attribute( "viewBox" ).isEmpty() )
00142 {
00143
00144 QString viewbox( docElem.attribute( "viewBox" ) );
00145 QStringList points = QStringList::split( ' ', viewbox.replace( ',', ' ').simplifyWhiteSpace() );
00146
00147 gc->matrix.scale( width / points[2].toFloat() , height / points[3].toFloat() );
00148 m_outerRect.setWidth( m_outerRect.width() * ( points[2].toFloat() / width ) );
00149 m_outerRect.setHeight( m_outerRect.height() * ( points[3].toFloat() / height ) );
00150 }
00151
00152 m_gc.push( gc );
00153 parseGroup( 0L, docElem );
00154
00155 QWMatrix mat;
00156 mat.scale( 1, -1 );
00157 mat.translate( 0, -m_document.height() );
00158 VTransformCmd trafo( 0L, mat );
00159 trafo.visit( m_document );
00160 outdoc = m_document.saveXML();
00161 }
00162
00163 #define DPI 90
00164
00165
00166
00167
00168 double SvgImport::toPercentage( QString s )
00169 {
00170 if( s.endsWith( "%" ) )
00171 return s.remove( '%' ).toDouble();
00172 else
00173 return s.toDouble() * 100.0;
00174 }
00175
00176 double SvgImport::fromPercentage( QString s )
00177 {
00178 if( s.endsWith( "%" ) )
00179 return s.remove( '%' ).toDouble() / 100.0;
00180 else
00181 return s.toDouble();
00182 }
00183
00184 double SvgImport::getScalingFromMatrix( QWMatrix &matrix )
00185 {
00186 double xscale = matrix.m11() + matrix.m12();
00187 double yscale = matrix.m22() + matrix.m21();
00188 return sqrt( xscale*xscale + yscale*yscale ) / sqrt( 2.0 );
00189 }
00190
00191
00192 const char * getNumber( const char *ptr, double &number )
00193 {
00194 int integer, exponent;
00195 double decimal, frac;
00196 int sign, expsign;
00197
00198 exponent = 0;
00199 integer = 0;
00200 frac = 1.0;
00201 decimal = 0;
00202 sign = 1;
00203 expsign = 1;
00204
00205
00206 if(*ptr == '+')
00207 ptr++;
00208 else if(*ptr == '-')
00209 {
00210 ptr++;
00211 sign = -1;
00212 }
00213
00214
00215 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00216 integer = (integer * 10) + *(ptr++) - '0';
00217 if(*ptr == '.')
00218 {
00219 ptr++;
00220 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00221 decimal += (*(ptr++) - '0') * (frac *= 0.1);
00222 }
00223
00224 if(*ptr == 'e' || *ptr == 'E')
00225 {
00226 ptr++;
00227
00228
00229 if(*ptr == '+')
00230 ptr++;
00231 else if(*ptr == '-')
00232 {
00233 ptr++;
00234 expsign = -1;
00235 }
00236
00237 exponent = 0;
00238 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00239 {
00240 exponent *= 10;
00241 exponent += *ptr - '0';
00242 ptr++;
00243 }
00244 }
00245 number = integer + decimal;
00246 number *= sign * pow( (double)10, double( expsign * exponent ) );
00247
00248 return ptr;
00249 }
00250
00251 void SvgImport::addGraphicContext()
00252 {
00253 SvgGraphicsContext *gc = new SvgGraphicsContext;
00254
00255 if( m_gc.current() )
00256 *gc = *( m_gc.current() );
00257 m_gc.push( gc );
00258 }
00259
00260 void SvgImport::setupTransform( const QDomElement &e )
00261 {
00262 SvgGraphicsContext *gc = m_gc.current();
00263
00264 QWMatrix mat = VPath::parseTransform( e.attribute( "transform" ) );
00265 gc->matrix = mat * gc->matrix;
00266 }
00267
00268 VObject* SvgImport::findObject( const QString &name, VGroup* group )
00269 {
00270 if( ! group )
00271 return 0L;
00272
00273 VObjectListIterator itr = group->objects();
00274
00275 for( uint objcount = 1; itr.current(); ++itr, objcount++ )
00276 if( itr.current()->state() != VObject::deleted )
00277 {
00278 if( itr.current()->name() == name )
00279 return itr.current();
00280
00281 if( dynamic_cast<VGroup *>( itr.current() ) )
00282 {
00283 VObject *obj = findObject( name, dynamic_cast<VGroup *>( itr.current() ) );
00284 if( obj )
00285 return obj;
00286 }
00287 }
00288
00289 return 0L;
00290 }
00291
00292 VObject* SvgImport::findObject( const QString &name )
00293 {
00294 QPtrVector<VLayer> vector;
00295 m_document.layers().toVector( &vector );
00296 for( int i = vector.count() - 1; i >= 0; i-- )
00297 {
00298 if ( vector[i]->state() != VObject::deleted )
00299 {
00300 VObject* obj = findObject( name, dynamic_cast<VGroup *>( vector[i] ) );
00301 if( obj )
00302 return obj;
00303 }
00304 }
00305
00306 return 0L;
00307 }
00308
00309 SvgImport::GradientHelper* SvgImport::findGradient( const QString &id, const QString &href)
00310 {
00311
00312 if( m_gradients.contains( id ) )
00313 return &m_gradients[ id ];
00314
00315
00316 if( !m_defs.contains( id ) )
00317 return 0L;
00318
00319 QDomElement e = m_defs[ id ];
00320 if(e.childNodes().count() == 0)
00321 {
00322 QString mhref = e.attribute("xlink:href").mid(1);
00323
00324 if(m_defs.contains(mhref))
00325 return findGradient(mhref, id);
00326 else
00327 return 0L;
00328 }
00329 else
00330 {
00331
00332 parseGradient( m_defs[ id ], m_defs[ href ] );
00333 }
00334
00335
00336 QString n;
00337 if(href.isEmpty())
00338 n = id;
00339 else
00340 n = href;
00341
00342 if( m_gradients.contains( n ) )
00343 return &m_gradients[ n ];
00344 else
00345 return 0L;
00346 }
00347
00348 QDomElement SvgImport::mergeStyles( const QDomElement &referencedBy, const QDomElement &referencedElement )
00349 {
00350
00351 QDomElement e = referencedElement;
00352
00353
00354 if( !referencedBy.attribute( "color" ).isEmpty() )
00355 e.setAttribute( "color", referencedBy.attribute( "color" ) );
00356 if( !referencedBy.attribute( "fill" ).isEmpty() )
00357 e.setAttribute( "fill", referencedBy.attribute( "fill" ) );
00358 if( !referencedBy.attribute( "fill-rule" ).isEmpty() )
00359 e.setAttribute( "fill-rule", referencedBy.attribute( "fill-rule" ) );
00360 if( !referencedBy.attribute( "stroke" ).isEmpty() )
00361 e.setAttribute( "stroke", referencedBy.attribute( "stroke" ) );
00362 if( !referencedBy.attribute( "stroke-width" ).isEmpty() )
00363 e.setAttribute( "stroke-width", referencedBy.attribute( "stroke-width" ) );
00364 if( !referencedBy.attribute( "stroke-linejoin" ).isEmpty() )
00365 e.setAttribute( "stroke-linejoin", referencedBy.attribute( "stroke-linejoin" ) );
00366 if( !referencedBy.attribute( "stroke-linecap" ).isEmpty() )
00367 e.setAttribute( "stroke-linecap", referencedBy.attribute( "stroke-linecap" ) );
00368 if( !referencedBy.attribute( "stroke-dasharray" ).isEmpty() )
00369 e.setAttribute( "stroke-dasharray", referencedBy.attribute( "stroke-dasharray" ) );
00370 if( !referencedBy.attribute( "stroke-dashoffset" ).isEmpty() )
00371 e.setAttribute( "stroke-dashoffset", referencedBy.attribute( "stroke-dashoffset" ) );
00372 if( !referencedBy.attribute( "stroke-opacity" ).isEmpty() )
00373 e.setAttribute( "stroke-opacity", referencedBy.attribute( "stroke-opacity" ) );
00374 if( !referencedBy.attribute( "stroke-miterlimit" ).isEmpty() )
00375 e.setAttribute( "stroke-miterlimit", referencedBy.attribute( "stroke-miterlimit" ) );
00376 if( !referencedBy.attribute( "fill-opacity" ).isEmpty() )
00377 e.setAttribute( "fill-opacity", referencedBy.attribute( "fill-opacity" ) );
00378 if( !referencedBy.attribute( "opacity" ).isEmpty() )
00379 e.setAttribute( "opacity", referencedBy.attribute( "opacity" ) );
00380
00381
00382
00383 return e;
00384 }
00385
00386
00387
00388
00389
00390 double SvgImport::parseUnit( const QString &unit, bool horiz, bool vert, KoRect bbox )
00391 {
00392
00393 double value = 0;
00394 const char *start = unit.latin1();
00395 if(!start) {
00396 return 0;
00397 }
00398 const char *end = getNumber( start, value );
00399
00400 if( uint( end - start ) < unit.length() )
00401 {
00402 if( unit.right( 2 ) == "pt" )
00403 value = ( value / 72.0 ) * DPI;
00404 else if( unit.right( 2 ) == "cm" )
00405 value = ( value / 2.54 ) * DPI;
00406 else if( unit.right( 2 ) == "pc" )
00407 value = ( value / 6.0 ) * DPI;
00408 else if( unit.right( 2 ) == "mm" )
00409 value = ( value / 25.4 ) * DPI;
00410 else if( unit.right( 2 ) == "in" )
00411 value = value * DPI;
00412 else if( unit.right( 2 ) == "pt" )
00413 value = ( value / 72.0 ) * DPI;
00414 else if( unit.right( 2 ) == "em" )
00415 value = value * m_gc.current()->font.pointSize() / ( sqrt( pow( m_gc.current()->matrix.m11(), 2 ) + pow( m_gc.current()->matrix.m22(), 2 ) ) / sqrt( 2.0 ) );
00416 else if( unit.right( 1 ) == "%" )
00417 {
00418 if( horiz && vert )
00419 value = ( value / 100.0 ) * (sqrt( pow( bbox.width(), 2 ) + pow( bbox.height(), 2 ) ) / sqrt( 2.0 ) );
00420 else if( horiz )
00421 value = ( value / 100.0 ) * bbox.width();
00422 else if( vert )
00423 value = ( value / 100.0 ) * bbox.height();
00424 }
00425 }
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438 return value;
00439 }
00440
00441 QColor SvgImport::parseColor( const QString &rgbColor )
00442 {
00443 int r, g, b;
00444 keywordToRGB( rgbColor, r, g, b );
00445 return QColor( r, g, b );
00446 }
00447
00448 void SvgImport::parseColor( VColor &color, const QString &s )
00449 {
00450 if( s.startsWith( "rgb(" ) )
00451 {
00452 QString parse = s.stripWhiteSpace();
00453 QStringList colors = QStringList::split( ',', parse );
00454 QString r = colors[0].right( ( colors[0].length() - 4 ) );
00455 QString g = colors[1];
00456 QString b = colors[2].left( ( colors[2].length() - 1 ) );
00457
00458 if( r.contains( "%" ) )
00459 {
00460 r = r.left( r.length() - 1 );
00461 r = QString::number( int( ( double( 255 * r.toDouble() ) / 100.0 ) ) );
00462 }
00463
00464 if( g.contains( "%" ) )
00465 {
00466 g = g.left( g.length() - 1 );
00467 g = QString::number( int( ( double( 255 * g.toDouble() ) / 100.0 ) ) );
00468 }
00469
00470 if( b.contains( "%" ) )
00471 {
00472 b = b.left( b.length() - 1 );
00473 b = QString::number( int( ( double( 255 * b.toDouble() ) / 100.0 ) ) );
00474 }
00475
00476 QColor c( r.toInt(), g.toInt(), b.toInt() );
00477 color.set( c.red() / 255.0, c.green() / 255.0, c.blue() / 255.0 );
00478 }
00479 else if( s == "currentColor" )
00480 {
00481 SvgGraphicsContext *gc = m_gc.current();
00482 color = gc->color;
00483 }
00484 else
00485 {
00486 QString rgbColor = s.stripWhiteSpace();
00487 QColor c;
00488 if( rgbColor.startsWith( "#" ) )
00489 c.setNamedColor( rgbColor );
00490 else
00491 c = parseColor( rgbColor );
00492 color.set( c.red() / 255.0, c.green() / 255.0, c.blue() / 255.0 );
00493 }
00494 }
00495
00496 void SvgImport::parseColorStops( VGradient *gradient, const QDomElement &e )
00497 {
00498 VColor c;
00499 for( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
00500 {
00501 QDomElement stop = n.toElement();
00502 if( stop.tagName() == "stop" )
00503 {
00504 float offset;
00505 QString temp = stop.attribute( "offset" );
00506 if( temp.contains( '%' ) )
00507 {
00508 temp = temp.left( temp.length() - 1 );
00509 offset = temp.toFloat() / 100.0;
00510 }
00511 else
00512 offset = temp.toFloat();
00513
00514 if( !stop.attribute( "stop-color" ).isEmpty() )
00515 parseColor( c, stop.attribute( "stop-color" ) );
00516 else
00517 {
00518
00519 QString style = stop.attribute( "style" ).simplifyWhiteSpace();
00520 QStringList substyles = QStringList::split( ';', style );
00521 for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
00522 {
00523 QStringList substyle = QStringList::split( ':', (*it) );
00524 QString command = substyle[0].stripWhiteSpace();
00525 QString params = substyle[1].stripWhiteSpace();
00526 if( command == "stop-color" )
00527 parseColor( c, params );
00528 if( command == "stop-opacity" )
00529 c.setOpacity( params.toDouble() );
00530 }
00531
00532 }
00533 if( !stop.attribute( "stop-opacity" ).isEmpty() )
00534 c.setOpacity( stop.attribute( "stop-opacity" ).toDouble() );
00535 gradient->addStop( c, offset, 0.5 );
00536 }
00537 }
00538 }
00539
00540 void SvgImport::parseGradient( const QDomElement &e , const QDomElement &referencedBy)
00541 {
00542
00543
00544
00545
00546
00547
00548 SvgGraphicsContext *gc = m_gc.current();
00549 if( !gc ) return;
00550
00551 GradientHelper gradhelper;
00552 gradhelper.gradient.clearStops();
00553 gradhelper.gradient.setRepeatMethod( VGradient::none );
00554
00555 if(e.childNodes().count() == 0)
00556 {
00557 QString href = e.attribute("xlink:href").mid(1);
00558
00559 if(href.isEmpty())
00560 {
00561
00562 return;
00563 }
00564 else
00565 {
00566
00567 GradientHelper *pGrad = findGradient( href );
00568 if( pGrad )
00569 gradhelper = *pGrad;
00570 }
00571 }
00572
00573
00574 QDomElement b;
00575 if( !referencedBy.isNull() )
00576 b = referencedBy;
00577 else
00578 b = e;
00579
00580 QString id = b.attribute("id");
00581 if( !id.isEmpty() )
00582 {
00583
00584 if( m_gradients.find( id ) != m_gradients.end() )
00585 gradhelper.gradient = m_gradients[ id ].gradient;
00586 }
00587
00588 gradhelper.bbox = b.attribute( "gradientUnits" ) != "userSpaceOnUse";
00589
00590
00591 VColor c = m_gc.current()->color;
00592
00593 if( !b.attribute( "color" ).isEmpty() )
00594 {
00595 parseColor( c, b.attribute( "color" ) );
00596 }
00597 else
00598 {
00599
00600 QString style = b.attribute( "style" ).simplifyWhiteSpace();
00601 QStringList substyles = QStringList::split( ';', style );
00602 for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
00603 {
00604 QStringList substyle = QStringList::split( ':', (*it) );
00605 QString command = substyle[0].stripWhiteSpace();
00606 QString params = substyle[1].stripWhiteSpace();
00607 if( command == "color" )
00608 parseColor( c, params );
00609 }
00610 }
00611 m_gc.current()->color = c;
00612
00613 if( b.tagName() == "linearGradient" )
00614 {
00615 if( gradhelper.bbox )
00616 {
00617 gradhelper.gradient.setOrigin( KoPoint( toPercentage( b.attribute( "x1", "0%" ) ), toPercentage( b.attribute( "y1", "0%" ) ) ) );
00618 gradhelper.gradient.setVector( KoPoint( toPercentage( b.attribute( "x2", "100%" ) ), toPercentage( b.attribute( "y2", "0%" ) ) ) );
00619 }
00620 else
00621 {
00622 gradhelper.gradient.setOrigin( KoPoint( b.attribute( "x1" ).toDouble(), b.attribute( "y1" ).toDouble() ) );
00623 gradhelper.gradient.setVector( KoPoint( b.attribute( "x2" ).toDouble(), b.attribute( "y2" ).toDouble() ) );
00624 }
00625 gradhelper.gradient.setType( VGradient::linear );
00626 }
00627 else
00628 {
00629 if( gradhelper.bbox )
00630 {
00631 gradhelper.gradient.setOrigin( KoPoint( toPercentage( b.attribute( "cx", "50%" ) ), toPercentage( b.attribute( "cy", "50%" ) ) ) );
00632 gradhelper.gradient.setVector( KoPoint( toPercentage( b.attribute( "cx", "50%" ) ) + toPercentage( b.attribute( "r", "50%" ) ), toPercentage( b.attribute( "cy", "50%" ) ) ) );
00633 gradhelper.gradient.setFocalPoint( KoPoint( toPercentage( b.attribute( "fx", "50%" ) ), toPercentage( b.attribute( "fy", "50%" ) ) ) );
00634 }
00635 else
00636 {
00637 gradhelper.gradient.setOrigin( KoPoint( b.attribute( "cx" ).toDouble(), b.attribute( "cy" ).toDouble() ) );
00638 gradhelper.gradient.setFocalPoint( KoPoint( b.attribute( "fx" ).toDouble(), b.attribute( "fy" ).toDouble() ) );
00639 gradhelper.gradient.setVector( KoPoint( b.attribute( "cx" ).toDouble() + b.attribute( "r" ).toDouble(), b.attribute( "cy" ).toDouble() ) );
00640 }
00641 gradhelper.gradient.setType( VGradient::radial );
00642 }
00643
00644 QString spreadMethod = b.attribute( "spreadMethod" );
00645 if( !spreadMethod.isEmpty() )
00646 {
00647 if( spreadMethod == "reflect" )
00648 gradhelper.gradient.setRepeatMethod( VGradient::reflect );
00649 else if( spreadMethod == "repeat" )
00650 gradhelper.gradient.setRepeatMethod( VGradient::repeat );
00651 else
00652 gradhelper.gradient.setRepeatMethod( VGradient::none );
00653 }
00654 else
00655 gradhelper.gradient.setRepeatMethod( VGradient::none );
00656
00657
00658
00659 parseColorStops( &gradhelper.gradient, e );
00660
00661 gradhelper.gradientTransform = VPath::parseTransform( b.attribute( "gradientTransform" ) );
00662 m_gradients.insert( b.attribute( "id" ), gradhelper );
00663 }
00664
00665 void SvgImport::parsePA( VObject *obj, SvgGraphicsContext *gc, const QString &command, const QString ¶ms )
00666 {
00667 VColor fillcolor = gc->fill.color();
00668 VColor strokecolor = gc->stroke.color();
00669
00670 if( params == "inherit" ) return;
00671
00672 if( command == "fill" )
00673 {
00674 if( params == "none" )
00675 gc->fill.setType( VFill::none );
00676 else if( params.startsWith( "url(" ) )
00677 {
00678 unsigned int start = params.find("#") + 1;
00679 unsigned int end = params.findRev(")");
00680 QString key = params.mid( start, end - start );
00681 GradientHelper *gradHelper = findGradient( key );
00682 if( gradHelper )
00683 {
00684 gc->fill.gradient() = gradHelper->gradient;
00685
00686 if( gradHelper->bbox )
00687 {
00688
00689 KoRect bbox = obj->boundingBox();
00690
00691
00692
00693
00694 double offsetx = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().origin().x() ), true, false, bbox );
00695 double offsety = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().origin().y() ), false, true, bbox );
00696 gc->fill.gradient().setOrigin( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) );
00697 if(gc->fill.gradient().type() == VGradient::radial)
00698 {
00699 offsetx = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().focalPoint().x() ), true, false, bbox );
00700 offsety = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().focalPoint().y() ), false, true, bbox );
00701 gc->fill.gradient().setFocalPoint( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) );
00702 }
00703 offsetx = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().vector().x() ), true, false, bbox );
00704 offsety = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().vector().y() ), false, true, bbox );
00705 gc->fill.gradient().setVector( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) );
00706
00707
00708
00709
00710
00711 }
00712 gc->fill.gradient().transform( gradHelper->gradientTransform );
00713
00714 if( !gradHelper->bbox )
00715 gc->fill.gradient().transform( gc->matrix );
00716
00717 gc->fill.setType( VFill::grad );
00718 }
00719 else
00720 gc->fill.setType( VFill::none );
00721 }
00722 else
00723 {
00724 parseColor( fillcolor, params );
00725 gc->fill.setType( VFill::solid );
00726 }
00727 }
00728 else if( command == "fill-rule" )
00729 {
00730 if( params == "nonzero" )
00731 gc->fillRule = winding;
00732 else if( params == "evenodd" )
00733 gc->fillRule = evenOdd;
00734 }
00735 else if( command == "stroke" )
00736 {
00737 if( params == "none" )
00738 gc->stroke.setType( VStroke::none );
00739 else if( params.startsWith( "url(" ) )
00740 {
00741 unsigned int start = params.find("#") + 1;
00742 unsigned int end = params.findRev(")");
00743 QString key = params.mid( start, end - start );
00744
00745 GradientHelper *gradHelper = findGradient( key );
00746 if( gradHelper )
00747 {
00748 gc->stroke.gradient() = gradHelper->gradient;
00749 gc->stroke.gradient().transform( gradHelper->gradientTransform );
00750 gc->stroke.gradient().transform( gc->matrix );
00751 gc->stroke.setType( VStroke::grad );
00752 }
00753 else
00754 gc->stroke.setType( VStroke::none );
00755 }
00756 else
00757 {
00758 parseColor( strokecolor, params );
00759 gc->stroke.setType( VStroke::solid );
00760 }
00761 }
00762 else if( command == "stroke-width" )
00763 gc->stroke.setLineWidth( parseUnit( params, true, true, m_outerRect ) );
00764 else if( command == "stroke-linejoin" )
00765 {
00766 if( params == "miter" )
00767 gc->stroke.setLineJoin( VStroke::joinMiter );
00768 else if( params == "round" )
00769 gc->stroke.setLineJoin( VStroke::joinRound );
00770 else if( params == "bevel" )
00771 gc->stroke.setLineJoin( VStroke::joinBevel );
00772 }
00773 else if( command == "stroke-linecap" )
00774 {
00775 if( params == "butt" )
00776 gc->stroke.setLineCap( VStroke::capButt );
00777 else if( params == "round" )
00778 gc->stroke.setLineCap( VStroke::capRound );
00779 else if( params == "square" )
00780 gc->stroke.setLineCap( VStroke::capSquare );
00781 }
00782 else if( command == "stroke-miterlimit" )
00783 gc->stroke.setMiterLimit( params.toFloat() );
00784 else if( command == "stroke-dasharray" )
00785 {
00786 QValueList<float> array;
00787 if(params != "none")
00788 {
00789 QStringList dashes = QStringList::split( ' ', params );
00790 for( QStringList::Iterator it = dashes.begin(); it != dashes.end(); ++it )
00791 array.append( (*it).toFloat() );
00792 }
00793 gc->stroke.dashPattern().setArray( array );
00794 }
00795 else if( command == "stroke-dashoffset" )
00796 gc->stroke.dashPattern().setOffset( params.toFloat() );
00797
00798 else if( command == "stroke-opacity" )
00799 strokecolor.setOpacity( fromPercentage( params ) );
00800 else if( command == "fill-opacity" )
00801 fillcolor.setOpacity( fromPercentage( params ) );
00802 else if( command == "opacity" )
00803 {
00804 fillcolor.setOpacity( fromPercentage( params ) );
00805 strokecolor.setOpacity( fromPercentage( params ) );
00806 }
00807 else if( command == "font-family" )
00808 {
00809 QString family = params;
00810 family.replace( '\'' , ' ' );
00811 gc->font.setFamily( family );
00812 }
00813 else if( command == "font-size" )
00814 {
00815 float pointSize = parseUnit( params );
00816 gc->font.setPointSizeFloat( pointSize * getScalingFromMatrix( gc->matrix ) );
00817 }
00818 else if( command == "font-weight" )
00819 {
00820 int weight = QFont::Normal;
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830 if( params == "bold" )
00831 weight = QFont::Bold;
00832 else if( params == "lighter" )
00833 {
00834 weight = gc->font.weight();
00835 if( weight <= 17 )
00836 weight = 1;
00837 else if( weight <= 33 )
00838 weight = 17;
00839 else if( weight <= 50 )
00840 weight = 33;
00841 else if( weight <= 58 )
00842 weight = 50;
00843 else if( weight <= 66 )
00844 weight = 58;
00845 else if( weight <= 75 )
00846 weight = 66;
00847 else if( weight <= 87 )
00848 weight = 75;
00849 else if( weight <= 99 )
00850 weight = 87;
00851 }
00852 else if( params == "bolder" )
00853 {
00854 weight = gc->font.weight();
00855 if( weight >= 87 )
00856 weight = 99;
00857 else if( weight >= 75 )
00858 weight = 87;
00859 else if( weight >= 66 )
00860 weight = 75;
00861 else if( weight >= 58 )
00862 weight = 66;
00863 else if( weight >= 50 )
00864 weight = 58;
00865 else if( weight >= 33 )
00866 weight = 50;
00867 else if( weight >= 17 )
00868 weight = 50;
00869 else if( weight >= 1 )
00870 weight = 17;
00871 }
00872 else
00873 {
00874 bool ok;
00875
00876 weight = params.toInt( &ok, 10 );
00877
00878 if( !ok )
00879 return;
00880
00881 switch( weight )
00882 {
00883 case 100: weight = 1; break;
00884 case 200: weight = 17; break;
00885 case 300: weight = 33; break;
00886 case 400: weight = 50; break;
00887 case 500: weight = 58; break;
00888 case 600: weight = 66; break;
00889 case 700: weight = 75; break;
00890 case 800: weight = 87; break;
00891 case 900: weight = 99; break;
00892 }
00893 }
00894 gc->font.setWeight( weight );
00895 }
00896 else if( command == "text-decoration" )
00897 {
00898 if( params == "line-through" )
00899 gc->font.setStrikeOut( true );
00900 else if( params == "underline" )
00901 gc->font.setUnderline( true );
00902 }
00903 else if( command == "color" )
00904 {
00905 VColor color;
00906 parseColor( color, params );
00907 gc->color = color;
00908 }
00909 if( gc->fill.type() != VFill::none )
00910 gc->fill.setColor( fillcolor, false );
00911
00912 gc->stroke.setColor( strokecolor );
00913 }
00914
00915 void SvgImport::parseStyle( VObject *obj, const QDomElement &e )
00916 {
00917 SvgGraphicsContext *gc = m_gc.current();
00918 if( !gc ) return;
00919
00920
00921 if( !e.attribute( "color" ).isEmpty() )
00922 parsePA( obj, gc, "color", e.attribute( "color" ) );
00923 if( !e.attribute( "fill" ).isEmpty() )
00924 parsePA( obj, gc, "fill", e.attribute( "fill" ) );
00925 if( !e.attribute( "fill-rule" ).isEmpty() )
00926 parsePA( obj, gc, "fill-rule", e.attribute( "fill-rule" ) );
00927 if( !e.attribute( "stroke" ).isEmpty() )
00928 parsePA( obj, gc, "stroke", e.attribute( "stroke" ) );
00929 if( !e.attribute( "stroke-width" ).isEmpty() )
00930 parsePA( obj, gc, "stroke-width", e.attribute( "stroke-width" ) );
00931 if( !e.attribute( "stroke-linejoin" ).isEmpty() )
00932 parsePA( obj, gc, "stroke-linejoin", e.attribute( "stroke-linejoin" ) );
00933 if( !e.attribute( "stroke-linecap" ).isEmpty() )
00934 parsePA( obj, gc, "stroke-linecap", e.attribute( "stroke-linecap" ) );
00935 if( !e.attribute( "stroke-dasharray" ).isEmpty() )
00936 parsePA( obj, gc, "stroke-dasharray", e.attribute( "stroke-dasharray" ) );
00937 if( !e.attribute( "stroke-dashoffset" ).isEmpty() )
00938 parsePA( obj, gc, "stroke-dashoffset", e.attribute( "stroke-dashoffset" ) );
00939 if( !e.attribute( "stroke-opacity" ).isEmpty() )
00940 parsePA( obj, gc, "stroke-opacity", e.attribute( "stroke-opacity" ) );
00941 if( !e.attribute( "stroke-miterlimit" ).isEmpty() )
00942 parsePA( obj, gc, "stroke-miterlimit", e.attribute( "stroke-miterlimit" ) );
00943 if( !e.attribute( "fill-opacity" ).isEmpty() )
00944 parsePA( obj, gc, "fill-opacity", e.attribute( "fill-opacity" ) );
00945 if( !e.attribute( "opacity" ).isEmpty() )
00946 parsePA( obj, gc, "opacity", e.attribute( "opacity" ) );
00947
00948
00949 QString style = e.attribute( "style" ).simplifyWhiteSpace();
00950 QStringList substyles = QStringList::split( ';', style );
00951 for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
00952 {
00953 QStringList substyle = QStringList::split( ':', (*it) );
00954 QString command = substyle[0].stripWhiteSpace();
00955 QString params = substyle[1].stripWhiteSpace();
00956 parsePA( obj, gc, command, params );
00957 }
00958
00959 if(!obj)
00960 return;
00961
00962 obj->setFill( gc->fill );
00963 if( dynamic_cast<VPath *>( obj ) )
00964 dynamic_cast<VPath *>( obj )->setFillRule( gc->fillRule );
00965
00966 double lineWidth = gc->stroke.lineWidth();
00967 gc->stroke.setLineWidth( lineWidth * getScalingFromMatrix( gc->matrix ) );
00968 obj->setStroke( gc->stroke );
00969 gc->stroke.setLineWidth( lineWidth );
00970 }
00971
00972 void SvgImport::parseFont( const QDomElement &e )
00973 {
00974 SvgGraphicsContext *gc = m_gc.current();
00975 if( !gc ) return;
00976
00977 if( ! e.attribute( "font-family" ).isEmpty() )
00978 parsePA( 0L, m_gc.current(), "font-family", e.attribute( "font-family" ) );
00979 if( ! e.attribute( "font-size" ).isEmpty() )
00980 parsePA( 0L, m_gc.current(), "font-size", e.attribute( "font-size" ) );
00981 if( ! e.attribute( "font-weight" ).isEmpty() )
00982 parsePA( 0L, m_gc.current(), "font-weight", e.attribute( "font-weight" ) );
00983 if( ! e.attribute( "text-decoration" ).isEmpty() )
00984 parsePA( 0L, m_gc.current(), "text-decoration", e.attribute( "text-decoration" ) );
00985 }
00986
00987 void SvgImport::parseUse( VGroup *grp, const QDomElement &e )
00988 {
00989 QString id = e.attribute( "xlink:href" );
00990
00991 if( !id.isEmpty() )
00992 {
00993 addGraphicContext();
00994 setupTransform( e );
00995
00996 QString key = id.mid( 1 );
00997
00998 if( !e.attribute( "x" ).isEmpty() && !e.attribute( "y" ).isEmpty() )
00999 {
01000 double tx = e.attribute( "x" ).toDouble();
01001 double ty = e.attribute( "y" ).toDouble();
01002
01003 m_gc.current()->matrix.translate(tx,ty);
01004 }
01005
01006 if(m_defs.contains(key))
01007 {
01008 QDomElement a = m_defs[key];
01009 if(a.tagName() == "g" || a.tagName() == "a")
01010 parseGroup( grp, a);
01011 else
01012 {
01013
01014
01015
01016 createObject( grp, a, VObject::normal, mergeStyles(e, a) );
01017 }
01018 }
01019 delete( m_gc.pop() );
01020 }
01021 }
01022
01023 void SvgImport::parseGroup( VGroup *grp, const QDomElement &e )
01024 {
01025 for( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
01026 {
01027 QDomElement b = n.toElement();
01028 if( b.isNull() ) continue;
01029
01030
01031 if( b.tagName() == "g" || b.tagName() == "a" )
01032 {
01033 VGroup *group;
01034 if ( grp )
01035 group = new VGroup( grp );
01036 else
01037 group = new VGroup( &m_document );
01038
01039 addGraphicContext();
01040 setupTransform( b );
01041 parseStyle( group, b );
01042 parseFont( b );
01043 parseGroup( group, b );
01044
01045
01046 if( !b.attribute("id").isEmpty() )
01047 group->setName( b.attribute("id") );
01048 if( grp )
01049 grp->append( group );
01050 else
01051 m_document.append( group );
01052 delete( m_gc.pop() );
01053 continue;
01054 }
01055 if( b.tagName() == "defs" )
01056 {
01057 parseDefs( b );
01058 continue;
01059 }
01060 else if( b.tagName() == "linearGradient" || b.tagName() == "radialGradient" )
01061 {
01062 parseGradient( b );
01063 continue;
01064 }
01065 if( b.tagName() == "rect" ||
01066 b.tagName() == "ellipse" ||
01067 b.tagName() == "circle" ||
01068 b.tagName() == "line" ||
01069 b.tagName() == "polyline" ||
01070 b.tagName() == "polygon" ||
01071 b.tagName() == "path" ||
01072 b.tagName() == "image" )
01073 {
01074 createObject( grp, b );
01075 continue;
01076 }
01077 else if( b.tagName() == "text" )
01078 {
01079 createText( grp, b );
01080 continue;
01081 }
01082 else if( b.tagName() == "use" )
01083 {
01084 parseUse( grp, b );
01085 continue;
01086 }
01087 }
01088 }
01089
01090 void SvgImport::parseDefs( const QDomElement &e )
01091 {
01092 for( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
01093 {
01094 QDomElement b = n.toElement();
01095 if( b.isNull() ) continue;
01096
01097 QString definition = b.attribute( "id" );
01098 if( !definition.isEmpty() )
01099 {
01100 if( !m_defs.contains( definition ) )
01101 m_defs.insert( definition, b );
01102 }
01103 }
01104 }
01105
01106
01107
01108
01109
01110 void SvgImport::createText( VGroup *grp, const QDomElement &b )
01111 {
01112 const double pathLength = 10.0;
01113
01114 VText *text = 0L;
01115 QString content;
01116 QString anchor;
01117 VSubpath base( 0L );
01118 VPath *path = 0L;
01119 double offset = 0.0;
01120
01121 addGraphicContext();
01122 setupTransform( b );
01123
01124 parseFont( b );
01125
01126 if( ! b.attribute( "text-anchor" ).isEmpty() )
01127 anchor = b.attribute( "text-anchor" );
01128
01129 if( b.hasChildNodes() )
01130 {
01131 if( base.isEmpty() && ! b.attribute( "x" ).isEmpty() && ! b.attribute( "y" ).isEmpty() )
01132 {
01133 double x = parseUnit( b.attribute( "x" ) );
01134 double y = parseUnit( b.attribute( "y" ) );
01135 base.moveTo( KoPoint( x, y ) );
01136 base.lineTo( KoPoint( x + pathLength, y ) );
01137 }
01138
01139 for( QDomNode n = b.firstChild(); !n.isNull(); n = n.nextSibling() )
01140 {
01141 QDomElement e = n.toElement();
01142 if( e.isNull() )
01143 {
01144 content += n.toCharacterData().data();
01145 }
01146 else if( e.tagName() == "textPath" )
01147 {
01148 if( e.attribute( "xlink:href" ).isEmpty() )
01149 continue;
01150
01151 QString key = e.attribute( "xlink:href" ).mid( 1 );
01152 if( ! m_defs.contains(key) )
01153 {
01154
01155 VObject* obj = findObject( key );
01156
01157 if( ! obj )
01158 obj = findObject( key, grp );
01159 if( obj )
01160 path = dynamic_cast<VPath*>( obj );
01161 }
01162 else
01163 {
01164 QDomElement p = m_defs[key];
01165 createObject( grp, p, VObject::deleted);
01166 }
01167 if( ! path )
01168 continue;
01169 base = *path->paths().getFirst();
01170 content += e.text();
01171
01172 if( ! e.attribute( "startOffset" ).isEmpty() )
01173 {
01174 QString start = e.attribute( "startOffset" );
01175 if( start.endsWith( "%" ) )
01176 offset = 0.01 * start.remove( '%' ).toDouble();
01177 else
01178 {
01179 float pathLength = 0;
01180 VSubpathIterator pIt( base );
01181
01182 for( ; pIt.current(); ++pIt )
01183 pathLength += pIt.current()->length();
01184
01185 if( pathLength > 0.0 )
01186 offset = start.toDouble() / pathLength;
01187 }
01188 }
01189 }
01190 else if( e.tagName() == "tspan" )
01191 {
01192
01193
01194 content += e.text();
01195 if( base.isEmpty() && ! e.attribute( "x" ).isEmpty() && ! e.attribute( "y" ).isEmpty() )
01196 {
01197 QStringList posX = QStringList::split( ", ", e.attribute( "x" ) );
01198 QStringList posY = QStringList::split( ", ", e.attribute( "y" ) );
01199 if( posX.count() && posY.count() )
01200 {
01201 double x = parseUnit( posX.first() );
01202 double y = parseUnit( posY.first() );
01203 base.moveTo( KoPoint( x, y ) );
01204 base.lineTo( KoPoint( x + pathLength, y ) );
01205 }
01206 }
01207 }
01208 else if( e.tagName() == "tref" )
01209 {
01210 if( e.attribute( "xlink:href" ).isEmpty() )
01211 continue;
01212
01213 QString key = e.attribute( "xlink:href" ).mid( 1 );
01214 if( ! m_defs.contains(key) )
01215 {
01216
01217 VObject* obj = findObject( key );
01218
01219 if( ! obj )
01220 obj = findObject( key, grp );
01221 if( obj )
01222 content += dynamic_cast<VText*>( obj )->text();
01223 }
01224 else
01225 {
01226 QDomElement p = m_defs[key];
01227 content += p.text();
01228 }
01229 }
01230 else
01231 continue;
01232
01233 if( ! e.attribute( "text-anchor" ).isEmpty() )
01234 anchor = e.attribute( "text-anchor" );
01235 }
01236 text = new VText( m_gc.current()->font, base, VText::Above, VText::Left, content.simplifyWhiteSpace() );
01237 }
01238 else
01239 {
01240 VSubpath base( 0L );
01241 double x = parseUnit( b.attribute( "x" ) );
01242 double y = parseUnit( b.attribute( "y" ) );
01243 base.moveTo( KoPoint( x, y ) );
01244 base.lineTo( KoPoint( x + pathLength, y ) );
01245 text = new VText( m_gc.current()->font, base, VText::Above, VText::Left, b.text().simplifyWhiteSpace() );
01246 }
01247
01248 if( text )
01249 {
01250 text->setParent( &m_document );
01251
01252 parseStyle( text, b );
01253
01254 text->setFont( m_gc.current()->font );
01255
01256 VTransformCmd trafo( 0L, m_gc.current()->matrix );
01257 trafo.visit( *text );
01258
01259 if( !b.attribute("id").isEmpty() )
01260 text->setName( b.attribute("id") );
01261
01262 if( anchor == "middle" )
01263 text->setAlignment( VText::Center );
01264 else if( anchor == "end" )
01265 text->setAlignment( VText::Right );
01266
01267 if( offset > 0.0 )
01268 text->setOffset( offset );
01269
01270 if( grp )
01271 grp->append( text );
01272 else
01273 m_document.append( text );
01274 }
01275
01276 delete( m_gc.pop() );
01277 }
01278
01279 void SvgImport::createObject( VGroup *grp, const QDomElement &b, const VObject::VState state, const QDomElement &style )
01280 {
01281 VObject *obj = 0L;
01282
01283 addGraphicContext();
01284 setupTransform( b );
01285
01286 if( b.tagName() == "rect" )
01287 {
01288 double x = parseUnit( b.attribute( "x" ), true, false, m_outerRect );
01289 double y = parseUnit( b.attribute( "y" ), false, true, m_outerRect );
01290 double width = parseUnit( b.attribute( "width" ), true, false, m_outerRect );
01291 double height = parseUnit( b.attribute( "height" ), false, true, m_outerRect );
01292 obj = new VRectangle( 0L, KoPoint( x, height + y ) , width, height );
01293 }
01294 else if( b.tagName() == "ellipse" )
01295 {
01296 double rx = parseUnit( b.attribute( "rx" ) );
01297 double ry = parseUnit( b.attribute( "ry" ) );
01298 double left = parseUnit( b.attribute( "cx" ) ) - rx;
01299 double top = parseUnit( b.attribute( "cy" ) ) - ry;
01300 obj = new VEllipse( 0L, KoPoint( left, top ), rx * 2.0, ry * 2.0 );
01301 }
01302 else if( b.tagName() == "circle" )
01303 {
01304 double r = parseUnit( b.attribute( "r" ) );
01305 double left = parseUnit( b.attribute( "cx" ) ) - r;
01306 double top = parseUnit( b.attribute( "cy" ) ) - r;
01307 obj = new VEllipse( 0L, KoPoint( left, top ), r * 2.0, r * 2.0 );
01308 }
01309 else if( b.tagName() == "line" )
01310 {
01311 VPath *path = new VPath( &m_document );
01312 double x1 = b.attribute( "x1" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x1" ) );
01313 double y1 = b.attribute( "y1" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y1" ) );
01314 double x2 = b.attribute( "x2" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x2" ) );
01315 double y2 = b.attribute( "y2" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y2" ) );
01316 path->moveTo( KoPoint( x1, y1 ) );
01317 path->lineTo( KoPoint( x2, y2 ) );
01318 obj = path;
01319 }
01320 else if( b.tagName() == "polyline" || b.tagName() == "polygon" )
01321 {
01322 VPath *path = new VPath( &m_document );
01323 bool bFirst = true;
01324
01325 QString points = b.attribute( "points" ).simplifyWhiteSpace();
01326 points.replace( ',', ' ' );
01327 points.remove( '\r' );
01328 points.remove( '\n' );
01329 QStringList pointList = QStringList::split( ' ', points );
01330 for( QStringList::Iterator it = pointList.begin(); it != pointList.end(); ++it)
01331 {
01332 KoPoint point;
01333 point.setX( (*it).toDouble() );
01334 ++it;
01335 point.setY( (*it).toDouble() );
01336 if( bFirst )
01337 {
01338 path->moveTo( point );
01339 bFirst = false;
01340 }
01341 else
01342 path->lineTo( point );
01343 }
01344 if( b.tagName() == "polygon" ) path->close();
01345 obj = path;
01346 }
01347 else if( b.tagName() == "path" )
01348 {
01349 VPath *path = new VPath( &m_document );
01350 path->loadSvgPath( b.attribute( "d" ) );
01351 obj = path;
01352 }
01353 else if( b.tagName() == "image" )
01354 {
01355 QString fname = b.attribute("xlink:href");
01356 obj = new VImage( 0L, fname );
01357 }
01358
01359 if( !obj )
01360 return;
01361
01362 if (state != VObject::normal)
01363 obj->setState(state);
01364
01365 VTransformCmd trafo( 0L, m_gc.current()->matrix );
01366 trafo.visit( *obj );
01367
01368 if( !style.isNull() )
01369 parseStyle( obj, style );
01370 else
01371 parseStyle( obj, b );
01372
01373
01374 if( !b.attribute("id").isEmpty() )
01375 obj->setName( b.attribute("id") );
01376 if( grp )
01377 grp->append( obj );
01378 else
01379 m_document.append( obj );
01380
01381 delete( m_gc.pop() );
01382 }
01383
01384 #include <svgimport.moc>