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