00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "xamlimport.h"
00021 #include "color.h"
00022 #include <KoFilterChain.h>
00023 #include <kgenericfactory.h>
00024 #include <kdebug.h>
00025 #include <KoUnit.h>
00026 #include <KoGlobal.h>
00027 #include <shapes/vellipse.h>
00028 #include <shapes/vrectangle.h>
00029 #include <shapes/vpolygon.h>
00030 #include <commands/vtransformcmd.h>
00031 #include <core/vsegment.h>
00032 #include <core/vtext.h>
00033 #include <core/vglobal.h>
00034 #include <core/vgroup.h>
00035 #include <core/vimage.h>
00036 #include <core/vlayer.h>
00037 #include <qcolor.h>
00038 #include <qfile.h>
00039 #include <kfilterdev.h>
00040
00041 typedef KGenericFactory<XAMLImport, KoFilter> XAMLImportFactory;
00042 K_EXPORT_COMPONENT_FACTORY( libkarbonxamlimport, XAMLImportFactory( "kofficefilters" ) )
00043
00044 XAMLImport::XAMLImport(KoFilter *, const char *, const QStringList&) :
00045 KoFilter(),
00046 outdoc( "DOC" )
00047 {
00048 m_gc.setAutoDelete( true );
00049 }
00050
00051 XAMLImport::~XAMLImport()
00052 {
00053 }
00054
00055 KoFilter::ConversionStatus XAMLImport::convert(const QCString& from, const QCString& to)
00056 {
00057
00058 if( to != "application/x-karbon" || from != "image/wvg+xml" )
00059 return KoFilter::NotImplemented;
00060
00061
00062 QString strExt;
00063 QString fileIn ( m_chain->inputFile() );
00064 const int result=fileIn.findRev('.');
00065 if (result>=0)
00066 {
00067 strExt=fileIn.mid(result).lower();
00068 }
00069
00070 QString strMime;
00071 if ((strExt==".gz")
00072 ||(strExt==".wvgz"))
00073 strMime="application/x-gzip";
00074 else if (strExt==".bz2")
00075 strMime="application/x-bzip2";
00076 else
00077 strMime="text/plain";
00078
00079 kdDebug(30514) << "File extension: -" << strExt << "- Compression: " << strMime << endl;
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 const bool parsed=inpdoc.setContent( in, &errormessage, &line, &col );
00093 in->close();
00094 delete in;
00095 if ( ! parsed )
00096 {
00097 kdError(30514) << "Error while parsing file: "
00098 << "at line " << line << " column: " << col
00099 << " message: " << errormessage << endl;
00100
00101 return KoFilter::ParsingError;
00102 }
00103
00104
00105 convert();
00106
00107 KoStoreDevice* out = m_chain->storageFile( "root", KoStore::Write );
00108 if( !out )
00109 {
00110 kdError(30514) << "Unable to open output file!" << endl;
00111 return KoFilter::StorageCreationError;
00112 }
00113 QCString cstring = outdoc.toCString();
00114 out->writeBlock( cstring.data(), cstring.length() );
00115
00116 return KoFilter::OK;
00117 }
00118
00119 void
00120 XAMLImport::convert()
00121 {
00122 XAMLGraphicsContext *gc = new XAMLGraphicsContext;
00123 QDomElement docElem = inpdoc.documentElement();
00124 KoRect bbox( 0, 0, 550.0, 841.0 );
00125 double width = !docElem.attribute( "width" ).isEmpty() ? parseUnit( docElem.attribute( "width" ), true, false, bbox ) : 550.0;
00126 double height = !docElem.attribute( "height" ).isEmpty() ? parseUnit( docElem.attribute( "height" ), false, true, bbox ) : 841.0;
00127 m_document.setWidth( width );
00128 m_document.setHeight( height );
00129 m_outerRect = m_document.boundingBox();
00130
00131
00132 if( !docElem.attribute( "viewBox" ).isEmpty() )
00133 {
00134
00135 QString viewbox( docElem.attribute( "viewBox" ) );
00136 QStringList points = QStringList::split( ' ', viewbox.replace( ',', ' ').simplifyWhiteSpace() );
00137
00138 gc->matrix.scale( width / points[2].toFloat() , height / points[3].toFloat() );
00139 m_outerRect.setWidth( m_outerRect.width() * ( points[2].toFloat() / width ) );
00140 m_outerRect.setHeight( m_outerRect.height() * ( points[3].toFloat() / height ) );
00141 }
00142 m_gc.push( gc );
00143 parseGroup( 0L, docElem );
00144
00145 QWMatrix mat;
00146 mat.scale( 1, -1 );
00147 mat.translate( 0, -m_document.height() );
00148 VTransformCmd trafo( 0L, mat );
00149 trafo.visit( m_document );
00150 outdoc = m_document.saveXML();
00151 }
00152
00153 #define DPI 90
00154
00155 double
00156 XAMLImport::toPercentage( QString s )
00157 {
00158 if( s.endsWith( "%" ) )
00159 return s.remove( '%' ).toDouble();
00160 else
00161 return s.toDouble() * 100.0;
00162 }
00163
00164 double
00165 XAMLImport::fromPercentage( QString s )
00166 {
00167 if( s.endsWith( "%" ) )
00168 return s.remove( '%' ).toDouble() / 100.0;
00169 else
00170 return s.toDouble();
00171 }
00172
00173
00174 const char *
00175 getNumber( const char *ptr, double &number )
00176 {
00177 int integer, exponent;
00178 double decimal, frac;
00179 int sign, expsign;
00180
00181 exponent = 0;
00182 integer = 0;
00183 frac = 1.0;
00184 decimal = 0;
00185 sign = 1;
00186 expsign = 1;
00187
00188
00189 if(*ptr == '+')
00190 ptr++;
00191 else if(*ptr == '-')
00192 {
00193 ptr++;
00194 sign = -1;
00195 }
00196
00197
00198 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00199 integer = (integer * 10) + *(ptr++) - '0';
00200 if(*ptr == '.')
00201 {
00202 ptr++;
00203 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00204 decimal += (*(ptr++) - '0') * (frac *= 0.1);
00205 }
00206
00207 if(*ptr == 'e' || *ptr == 'E')
00208 {
00209 ptr++;
00210
00211
00212 if(*ptr == '+')
00213 ptr++;
00214 else if(*ptr == '-')
00215 {
00216 ptr++;
00217 expsign = -1;
00218 }
00219
00220 exponent = 0;
00221 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00222 {
00223 exponent *= 10;
00224 exponent += *ptr - '0';
00225 ptr++;
00226 }
00227 }
00228 number = integer + decimal;
00229 number *= sign * pow( (double)10, double( expsign * exponent ) );
00230
00231 return ptr;
00232 }
00233
00234
00235 double
00236 XAMLImport::parseUnit( const QString &unit, bool horiz, bool vert, KoRect bbox )
00237 {
00238
00239 double value = 0;
00240 const char *start = unit.latin1();
00241 if(!start) {
00242 return 0;
00243 }
00244 const char *end = getNumber( start, value );
00245
00246 if( uint( end - start ) < unit.length() )
00247 {
00248 if( unit.right( 2 ) == "pt" )
00249 value = ( value / 72.0 ) * DPI;
00250 else if( unit.right( 2 ) == "cm" )
00251 value = ( value / 2.54 ) * DPI;
00252 else if( unit.right( 2 ) == "pc" )
00253 value = ( value / 6.0 ) * DPI;
00254 else if( unit.right( 2 ) == "mm" )
00255 value = ( value / 25.4 ) * DPI;
00256 else if( unit.right( 2 ) == "in" )
00257 value = value * DPI;
00258 else if( unit.right( 2 ) == "pt" )
00259 value = ( value / 72.0 ) * DPI;
00260 else if( unit.right( 2 ) == "em" )
00261 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 ) );
00262 else if( unit.right( 1 ) == "%" )
00263 {
00264 if( horiz && vert )
00265 value = ( value / 100.0 ) * (sqrt( pow( bbox.width(), 2 ) + pow( bbox.height(), 2 ) ) / sqrt( 2.0 ) );
00266 else if( horiz )
00267 value = ( value / 100.0 ) * bbox.width();
00268 else if( vert )
00269 value = ( value / 100.0 ) * bbox.height();
00270 }
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 return value;
00285 }
00286
00287 QColor
00288 XAMLImport::parseColor( const QString &rgbColor )
00289 {
00290 int r, g, b;
00291 keywordToRGB( rgbColor, r, g, b );
00292 return QColor( r, g, b );
00293 }
00294
00295 void
00296 XAMLImport::parseColor( VColor &color, const QString &s )
00297 {
00298 if( s.startsWith( "rgb(" ) )
00299 {
00300 QString parse = s.stripWhiteSpace();
00301 QStringList colors = QStringList::split( ',', parse );
00302 QString r = colors[0].right( ( colors[0].length() - 4 ) );
00303 QString g = colors[1];
00304 QString b = colors[2].left( ( colors[2].length() - 1 ) );
00305
00306 if( r.contains( "%" ) )
00307 {
00308 r = r.left( r.length() - 1 );
00309 r = QString::number( int( ( double( 255 * r.toDouble() ) / 100.0 ) ) );
00310 }
00311
00312 if( g.contains( "%" ) )
00313 {
00314 g = g.left( g.length() - 1 );
00315 g = QString::number( int( ( double( 255 * g.toDouble() ) / 100.0 ) ) );
00316 }
00317
00318 if( b.contains( "%" ) )
00319 {
00320 b = b.left( b.length() - 1 );
00321 b = QString::number( int( ( double( 255 * b.toDouble() ) / 100.0 ) ) );
00322 }
00323
00324 QColor c( r.toInt(), g.toInt(), b.toInt() );
00325 color.set( c.red() / 255.0, c.green() / 255.0, c.blue() / 255.0 );
00326 }
00327 else
00328 {
00329 QString rgbColor = s.stripWhiteSpace();
00330 QColor c;
00331 if( rgbColor.startsWith( "#" ) )
00332 c.setNamedColor( rgbColor );
00333 else
00334 c = parseColor( rgbColor );
00335 color.set( c.red() / 255.0, c.green() / 255.0, c.blue() / 255.0 );
00336 }
00337 }
00338
00339 void
00340 XAMLImport::parseColorStops( VGradient *gradient, const QDomElement &e )
00341 {
00342 VColor c;
00343 for( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
00344 {
00345 QDomElement stop = n.toElement();
00346 if( stop.tagName() == "stop" )
00347 {
00348 float offset;
00349 QString temp = stop.attribute( "offset" );
00350 if( temp.contains( '%' ) )
00351 {
00352 temp = temp.left( temp.length() - 1 );
00353 offset = temp.toFloat() / 100.0;
00354 }
00355 else
00356 offset = temp.toFloat();
00357
00358 if( !stop.attribute( "stop-color" ).isEmpty() )
00359 parseColor( c, stop.attribute( "stop-color" ) );
00360 else
00361 {
00362
00363 QString style = stop.attribute( "style" ).simplifyWhiteSpace();
00364 QStringList substyles = QStringList::split( ';', style );
00365 for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
00366 {
00367 QStringList substyle = QStringList::split( ':', (*it) );
00368 QString command = substyle[0].stripWhiteSpace();
00369 QString params = substyle[1].stripWhiteSpace();
00370 if( command == "stop-color" )
00371 parseColor( c, params );
00372 if( command == "stop-opacity" )
00373 c.setOpacity( params.toDouble() );
00374 }
00375
00376 }
00377 if( !stop.attribute( "stop-opacity" ).isEmpty() )
00378 c.setOpacity( stop.attribute( "stop-opacity" ).toDouble() );
00379 gradient->addStop( c, offset, 0.5 );
00380 }
00381 }
00382 }
00383
00384 void
00385 XAMLImport::parseGradient( const QDomElement &e )
00386 {
00387 GradientHelper gradhelper;
00388 gradhelper.gradient.clearStops();
00389 gradhelper.gradient.setRepeatMethod( VGradient::none );
00390
00391 QString href = e.attribute( "xlink:href" ).mid( 1 );
00392 if( !href.isEmpty() )
00393 {
00394
00395 gradhelper.gradient = m_gradients[ href ].gradient;
00396 }
00397
00398 gradhelper.bbox = e.attribute( "gradientUnits" ) != "userSpaceOnUse";
00399
00400 if( e.tagName() == "linearGradient" )
00401 {
00402 if( gradhelper.bbox )
00403 {
00404 gradhelper.gradient.setOrigin( KoPoint( toPercentage( e.attribute( "x1", "0%" ) ), toPercentage( e.attribute( "y1", "0%" ) ) ) );
00405 gradhelper.gradient.setVector( KoPoint( toPercentage( e.attribute( "x2", "100%" ) ), toPercentage( e.attribute( "y2", "0%" ) ) ) );
00406 }
00407 else
00408 {
00409 gradhelper.gradient.setOrigin( KoPoint( e.attribute( "x1" ).toDouble(), e.attribute( "y1" ).toDouble() ) );
00410 gradhelper.gradient.setVector( KoPoint( e.attribute( "x2" ).toDouble(), e.attribute( "y2" ).toDouble() ) );
00411 }
00412 }
00413 else
00414 {
00415 if( gradhelper.bbox )
00416 {
00417 gradhelper.gradient.setOrigin( KoPoint( toPercentage( e.attribute( "cx", "50%" ) ), toPercentage( e.attribute( "cy", "50%" ) ) ) );
00418 gradhelper.gradient.setVector( KoPoint( toPercentage( e.attribute( "cx", "50%" ) ) + toPercentage( e.attribute( "r", "50%" ) ),
00419 toPercentage( e.attribute( "cy", "50%" ) ) ) );
00420 gradhelper.gradient.setFocalPoint( KoPoint( toPercentage( e.attribute( "fx", "50%" ) ), toPercentage( e.attribute( "fy", "50%" ) ) ) );
00421 }
00422 else
00423 {
00424 gradhelper.gradient.setOrigin( KoPoint( e.attribute( "cx" ).toDouble(), e.attribute( "cy" ).toDouble() ) );
00425 gradhelper.gradient.setFocalPoint( KoPoint( e.attribute( "fx" ).toDouble(), e.attribute( "fy" ).toDouble() ) );
00426 gradhelper.gradient.setVector( KoPoint( e.attribute( "cx" ).toDouble() + e.attribute( "r" ).toDouble(), e.attribute( "cy" ).toDouble() ) );
00427 }
00428 gradhelper.gradient.setType( VGradient::radial );
00429 }
00430
00431 QString spreadMethod = e.attribute( "spreadMethod" );
00432 if( !spreadMethod.isEmpty() )
00433 {
00434 if( spreadMethod == "reflect" )
00435 gradhelper.gradient.setRepeatMethod( VGradient::reflect );
00436 else if( spreadMethod == "repeat" )
00437 gradhelper.gradient.setRepeatMethod( VGradient::repeat );
00438 }
00439 parseColorStops( &gradhelper.gradient, e );
00440
00441 gradhelper.gradientTransform = VPath::parseTransform( e.attribute( "gradientTransform" ) );
00442 m_gradients.insert( e.attribute( "id" ), gradhelper );
00443 }
00444
00445 void
00446 XAMLImport::parsePA( VObject *obj, XAMLGraphicsContext *gc, const QString &command, const QString ¶ms )
00447 {
00448 VColor fillcolor = gc->fill.color();
00449 VColor strokecolor = gc->stroke.color();
00450
00451 if( command == "fill" )
00452 {
00453 if( params == "none" )
00454 gc->fill.setType( VFill::none );
00455 else if( params.startsWith( "url(" ) )
00456 {
00457 unsigned int start = params.find("#") + 1;
00458 unsigned int end = params.findRev(")");
00459 QString key = params.mid( start, end - start );
00460 gc->fill.gradient() = m_gradients[ key ].gradient;
00461 if( m_gradients[ key ].bbox )
00462 {
00463
00464 KoRect bbox = obj->boundingBox();
00465
00466
00467
00468
00469 double offsetx = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().origin().x() ), true, false, bbox );
00470 double offsety = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().origin().y() ), false, true, bbox );
00471 gc->fill.gradient().setOrigin( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) );
00472 offsetx = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().focalPoint().x() ), true, false, bbox );
00473 offsety = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().focalPoint().y() ), false, true, bbox );
00474 gc->fill.gradient().setFocalPoint( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) );
00475 offsetx = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().vector().x() ), true, false, bbox );
00476 offsety = parseUnit( QString( "%1%" ).arg( gc->fill.gradient().vector().y() ), false, true, bbox );
00477 gc->fill.gradient().setVector( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) );
00478
00479
00480
00481
00482
00483 }
00484 gc->fill.gradient().transform( m_gradients[ key ].gradientTransform );
00485 if( !m_gradients[ key ].bbox )
00486 gc->fill.gradient().transform( gc->matrix );
00487 gc->fill.setType( VFill::grad );
00488 }
00489 else
00490 {
00491 parseColor( fillcolor, params );
00492 gc->fill.setType( VFill::solid );
00493 }
00494 }
00495 else if( command == "fill-rule" )
00496 {
00497 if( params == "nonzero" )
00498 gc->fillRule = winding;
00499 else if( params == "evenodd" )
00500 gc->fillRule = evenOdd;
00501 }
00502 else if( command == "stroke" )
00503 {
00504 if( params == "none" )
00505 gc->stroke.setType( VStroke::none );
00506 else if( params.startsWith( "url(" ) )
00507 {
00508 unsigned int start = params.find("#") + 1;
00509 unsigned int end = params.findRev(")");
00510 QString key = params.mid( start, end - start );
00511 gc->stroke.gradient() = m_gradients[ key ].gradient;
00512 gc->stroke.gradient().transform( m_gradients[ key ].gradientTransform );
00513 gc->stroke.gradient().transform( gc->matrix );
00514 gc->stroke.setType( VStroke::grad );
00515 }
00516 else
00517 {
00518 parseColor( strokecolor, params );
00519 gc->stroke.setType( VStroke::solid );
00520 }
00521 }
00522 else if( command == "stroke-width" )
00523 gc->stroke.setLineWidth( parseUnit( params, true, true, m_outerRect ) );
00524 else if( command == "stroke-linejoin" )
00525 {
00526 if( params == "miter" )
00527 gc->stroke.setLineJoin( VStroke::joinMiter );
00528 else if( params == "round" )
00529 gc->stroke.setLineJoin( VStroke::joinRound );
00530 else if( params == "bevel" )
00531 gc->stroke.setLineJoin( VStroke::joinBevel );
00532 }
00533 else if( command == "stroke-linecap" )
00534 {
00535 if( params == "butt" )
00536 gc->stroke.setLineCap( VStroke::capButt );
00537 else if( params == "round" )
00538 gc->stroke.setLineCap( VStroke::capRound );
00539 else if( params == "square" )
00540 gc->stroke.setLineCap( VStroke::capSquare );
00541 }
00542 else if( command == "stroke-miterlimit" )
00543 gc->stroke.setMiterLimit( params.toFloat() );
00544 else if( command == "stroke-dasharray" )
00545 {
00546 QValueList<float> array;
00547 if(params != "none")
00548 {
00549 QStringList dashes = QStringList::split( ' ', params );
00550 for( QStringList::Iterator it = dashes.begin(); it != dashes.end(); ++it )
00551 array.append( (*it).toFloat() );
00552 }
00553 gc->stroke.dashPattern().setArray( array );
00554 }
00555 else if( command == "stroke-dashoffset" )
00556 gc->stroke.dashPattern().setOffset( params.toFloat() );
00557
00558 else if( command == "stroke-opacity" )
00559 strokecolor.setOpacity( fromPercentage( params ) );
00560 else if( command == "fill-opacity" )
00561 fillcolor.setOpacity( fromPercentage( params ) );
00562 else if( command == "opacity" )
00563 {
00564 fillcolor.setOpacity( fromPercentage( params ) );
00565 strokecolor.setOpacity( fromPercentage( params ) );
00566 }
00567 else if( command == "font-family" )
00568 {
00569 QString family = params;
00570 family.replace( '\'' , ' ' );
00571 gc->font.setFamily( family );
00572 }
00573 else if( command == "font-size" )
00574 {
00575 float pointSize = parseUnit( params );
00576 pointSize *= gc->matrix.m22() > 0 ? gc->matrix.m22() : -1.0 * gc->matrix.m22();
00577 gc->font.setPointSizeFloat( pointSize );
00578 }
00579 else if( command == "text-decoration" )
00580 {
00581 if( params == "line-through" )
00582 gc->font.setStrikeOut( true );
00583 else if( params == "underline" )
00584 gc->font.setUnderline( true );
00585 }
00586 if( gc->fill.type() != VFill::none )
00587 gc->fill.setColor( fillcolor, false );
00588
00589 gc->stroke.setColor( strokecolor );
00590 }
00591
00592 void
00593 XAMLImport::addGraphicContext()
00594 {
00595 XAMLGraphicsContext *gc = new XAMLGraphicsContext;
00596
00597 if( m_gc.current() )
00598 *gc = *( m_gc.current() );
00599 m_gc.push( gc );
00600 }
00601
00602 void
00603 XAMLImport::setupTransform( const QDomElement &e )
00604 {
00605 XAMLGraphicsContext *gc = m_gc.current();
00606
00607 QWMatrix mat = VPath::parseTransform( e.attribute( "transform" ) );
00608 gc->matrix = mat * gc->matrix;
00609 }
00610
00611 void
00612 XAMLImport::parseStyle( VObject *obj, const QDomElement &e )
00613 {
00614 XAMLGraphicsContext *gc = m_gc.current();
00615 if( !gc ) return;
00616
00617
00618 if( !e.attribute( "fill" ).isEmpty() )
00619 parsePA( obj, gc, "fill", e.attribute( "fill" ) );
00620 if( !e.attribute( "fill-rule" ).isEmpty() )
00621 parsePA( obj, gc, "fill-rule", e.attribute( "fill-rule" ) );
00622 if( !e.attribute( "stroke" ).isEmpty() )
00623 parsePA( obj, gc, "stroke", e.attribute( "stroke" ) );
00624 if( !e.attribute( "stroke-width" ).isEmpty() )
00625 parsePA( obj, gc, "stroke-width", e.attribute( "stroke-width" ) );
00626 if( !e.attribute( "stroke-linejoin" ).isEmpty() )
00627 parsePA( obj, gc, "stroke-linejoin", e.attribute( "stroke-linejoin" ) );
00628 if( !e.attribute( "stroke-linecap" ).isEmpty() )
00629 parsePA( obj, gc, "stroke-linecap", e.attribute( "stroke-linecap" ) );
00630 if( !e.attribute( "stroke-dasharray" ).isEmpty() )
00631 parsePA( obj, gc, "stroke-dasharray", e.attribute( "stroke-dasharray" ) );
00632 if( !e.attribute( "stroke-dashoffset" ).isEmpty() )
00633 parsePA( obj, gc, "stroke-dashoffset", e.attribute( "stroke-dashoffset" ) );
00634 if( !e.attribute( "stroke-opacity" ).isEmpty() )
00635 parsePA( obj, gc, "stroke-opacity", e.attribute( "stroke-opacity" ) );
00636 if( !e.attribute( "stroke-miterlimit" ).isEmpty() )
00637 parsePA( obj, gc, "stroke-miterlimit", e.attribute( "stroke-miterlimit" ) );
00638 if( !e.attribute( "fill-opacity" ).isEmpty() )
00639 parsePA( obj, gc, "fill-opacity", e.attribute( "fill-opacity" ) );
00640 if( !e.attribute( "opacity" ).isEmpty() )
00641 parsePA( obj, gc, "opacity", e.attribute( "opacity" ) );
00642
00643
00644 QString style = e.attribute( "style" ).simplifyWhiteSpace();
00645 QStringList substyles = QStringList::split( ';', style );
00646 for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
00647 {
00648 QStringList substyle = QStringList::split( ':', (*it) );
00649 QString command = substyle[0].stripWhiteSpace();
00650 QString params = substyle[1].stripWhiteSpace();
00651 parsePA( obj, gc, command, params );
00652 }
00653
00654 obj->setFill( gc->fill );
00655 if( dynamic_cast<VPath *>( obj ) )
00656 dynamic_cast<VPath *>( obj )->setFillRule( gc->fillRule );
00657
00658 double lineWidth = gc->stroke.lineWidth();
00659 gc->stroke.setLineWidth( lineWidth * sqrt( pow( m_gc.current()->matrix.m11(), 2 ) + pow( m_gc.current()->matrix.m22(), 2 ) ) / sqrt( 2.0 ) );
00660 obj->setStroke( gc->stroke );
00661 gc->stroke.setLineWidth( lineWidth );
00662 }
00663
00664 void
00665 XAMLImport::parseFont( const QDomElement &e )
00666 {
00667 XAMLGraphicsContext *gc = m_gc.current();
00668 if( !gc ) return;
00669
00670 if( ! e.attribute( "font-family" ).isEmpty() )
00671 parsePA( 0L, m_gc.current(), "font-family", e.attribute( "font-family" ) );
00672 if( ! e.attribute( "font-size" ).isEmpty() )
00673 parsePA( 0L, m_gc.current(), "font-size", e.attribute( "font-size" ) );
00674 if( ! e.attribute( "text-decoration" ).isEmpty() )
00675 parsePA( 0L, m_gc.current(), "text-decoration", e.attribute( "text-decoration" ) );
00676 }
00677
00678 void
00679 XAMLImport::parseGroup( VGroup *grp, const QDomElement &e )
00680 {
00681 bool isDef = false;
00682 if( e.tagName() == "defs" )
00683 isDef = true;
00684
00685 for( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
00686 {
00687 QDomElement b = n.toElement();
00688 if( b.isNull() ) continue;
00689 VObject *obj = 0L;
00690 if( b.tagName() == "g" )
00691 {
00692 VGroup *group;
00693 if ( grp )
00694 group = new VGroup( grp );
00695 else
00696 group = new VGroup( &m_document );
00697
00698 addGraphicContext();
00699 setupTransform( b );
00700 parseStyle( group, b );
00701 parseFont( b );
00702 parseGroup( group, b );
00703
00704
00705 if( !b.attribute("id").isEmpty() )
00706 group->setName( b.attribute("id") );
00707 if( grp )
00708 grp->append( group );
00709 else
00710 m_document.append( group );
00711 delete( m_gc.pop() );
00712 continue;
00713 }
00714 if( b.tagName() == "defs" )
00715 {
00716 parseGroup( 0L, b );
00717 continue;
00718 }
00719 else if( b.tagName() == "linearGradient" || b.tagName() == "radialGradient" )
00720 {
00721 parseGradient( b );
00722 continue;
00723 }
00724 else if( b.tagName() == "rect" ||
00725 b.tagName() == "ellipse" ||
00726 b.tagName() == "circle" ||
00727 b.tagName() == "line" ||
00728 b.tagName() == "polyline" ||
00729 b.tagName() == "polygon" ||
00730 b.tagName() == "path" ||
00731 b.tagName() == "image" )
00732 {
00733 if (!isDef)
00734 obj = createObject( b );
00735 else
00736 m_paths.insert( b.attribute( "id" ), b );
00737 }
00738 else if( b.tagName() == "text" )
00739 {
00740 if( isDef )
00741 m_paths.insert( b.attribute( "id" ), b );
00742 else
00743 createText( grp, b );
00744 }
00745 else if( b.tagName() == "use" )
00746 {
00747 double tx = b.attribute( "x" ).toDouble();
00748 double ty = b.attribute( "y" ).toDouble();
00749
00750 if( !b.attribute( "xlink:href" ).isEmpty() )
00751 {
00752 QString params = b.attribute( "xlink:href" );
00753 unsigned int start = params.find("#") + 1;
00754 unsigned int end = params.findRev(")");
00755 QString key = params.mid( start, end - start );
00756 if(m_paths.contains(key))
00757 {
00758 QDomElement a = m_paths[key];
00759 obj = createObject( a );
00760 m_gc.current()->matrix.translate(tx,ty);
00761 parsePA( grp, m_gc.current(), "fill", b.attribute( "fill" ) );
00762 }
00763 }
00764 }
00765 if( !obj ) continue;
00766 VTransformCmd trafo( 0L, m_gc.current()->matrix );
00767 trafo.visit( *obj );
00768 parseStyle( obj, b );
00769
00770 if( !b.attribute("id").isEmpty() )
00771 obj->setName( b.attribute("id") );
00772 if( grp )
00773 grp->append( obj );
00774 else
00775 m_document.append( obj );
00776 delete( m_gc.pop() );
00777 }
00778 }
00779
00780 VObject* XAMLImport::findObject( const QString &name, VGroup* group )
00781 {
00782 if( ! group )
00783 return 0L;
00784
00785 VObjectListIterator itr = group->objects();
00786
00787 for( uint objcount = 1; itr.current(); ++itr, objcount++ )
00788 if( itr.current()->state() != VObject::deleted )
00789 {
00790 if( itr.current()->name() == name )
00791 return itr.current();
00792
00793 if( dynamic_cast<VGroup *>( itr.current() ) )
00794 {
00795 VObject *obj = findObject( name, dynamic_cast<VGroup *>( itr.current() ) );
00796 if( obj )
00797 return obj;
00798 }
00799 }
00800
00801 return 0L;
00802 }
00803
00804 VObject* XAMLImport::findObject( const QString &name )
00805 {
00806 QPtrVector<VLayer> vector;
00807 m_document.layers().toVector( &vector );
00808 for( int i = vector.count() - 1; i >= 0; i-- )
00809 {
00810 if ( vector[i]->state() != VObject::deleted )
00811 {
00812 VObject* obj = findObject( name, dynamic_cast<VGroup *>( vector[i] ) );
00813 if( obj )
00814 return obj;
00815 }
00816 }
00817
00818 return 0L;
00819 }
00820
00821 void XAMLImport::createText( VGroup *grp, const QDomElement &b )
00822 {
00823 VText *text = 0L;
00824 QString content;
00825 VSubpath base( 0L );
00826 VPath *path = 0L;
00827
00828 addGraphicContext();
00829 setupTransform( b );
00830 VTransformCmd trafo( 0L, m_gc.current()->matrix );
00831
00832 parseFont( b );
00833
00834 if( b.hasChildNodes() )
00835 {
00836 if( base.isEmpty() && ! b.attribute( "x" ).isEmpty() && ! b.attribute( "y" ).isEmpty() )
00837 {
00838 double x = parseUnit( b.attribute( "x" ) );
00839 double y = parseUnit( b.attribute( "y" ) );
00840 base.moveTo( KoPoint( x, y ) );
00841 base.lineTo( KoPoint( x + 10, y ) );
00842 }
00843
00844 for( QDomNode n = b.firstChild(); !n.isNull(); n = n.nextSibling() )
00845 {
00846 QDomElement e = n.toElement();
00847 if( e.isNull() )
00848 {
00849 content += n.toCharacterData().data();
00850 }
00851 else if( e.tagName() == "textPath" )
00852 {
00853 if( e.attribute( "xlink:href" ).isEmpty() )
00854 continue;
00855
00856 QString uri = e.attribute( "xlink:href" );
00857 unsigned int start = uri.find("#") + 1;
00858 unsigned int end = uri.findRev(")");
00859 QString key = uri.mid( start, end - start );
00860 if( ! m_paths.contains(key) )
00861 {
00862 VObject* obj = findObject( key );
00863 if( obj )
00864 path = dynamic_cast<VPath*>( obj );
00865 }
00866 else
00867 {
00868 QDomElement p = m_paths[key];
00869 path = dynamic_cast<VPath*>( createObject( p ) );
00870 if( path )
00871 path->setState( VObject::deleted );
00872 }
00873 if( ! path )
00874 continue;
00875 base = *path->paths().getFirst();
00876 content += e.text();
00877 }
00878 else if( e.tagName() == "tspan" )
00879 {
00880
00881
00882 content += e.text();
00883 if( base.isEmpty() && ! e.attribute( "x" ).isEmpty() && ! e.attribute( "y" ).isEmpty() )
00884 {
00885 QStringList posX = QStringList::split( ", ", e.attribute( "x" ) );
00886 QStringList posY = QStringList::split( ", ", e.attribute( "y" ) );
00887 if( posX.count() && posY.count() )
00888 {
00889 double x = parseUnit( posX.first() );
00890 double y = parseUnit( posY.first() );
00891 base.moveTo( KoPoint( x, y ) );
00892 base.lineTo( KoPoint( x + 10, y ) );
00893 }
00894 }
00895 }
00896 else if( e.tagName() == "tref" )
00897 {
00898 if( e.attribute( "xlink:href" ).isEmpty() )
00899 continue;
00900
00901 QString uri = e.attribute( "xlink:href" );
00902 unsigned int start = uri.find("#") + 1;
00903 unsigned int end = uri.findRev(")");
00904 QString key = uri.mid( start, end - start );
00905
00906 if( ! m_paths.contains(key) )
00907 {
00908 VObject* obj = findObject( key );
00909 if( obj )
00910 content += dynamic_cast<VText*>( obj )->text();
00911 }
00912 else
00913 {
00914 QDomElement p = m_paths[key];
00915 content += p.text();
00916 }
00917 }
00918 else
00919 continue;
00920 }
00921 text = new VText( m_gc.current()->font, base, VText::Above, VText::Left, content.simplifyWhiteSpace() );
00922 }
00923 else
00924 {
00925 VSubpath base( 0L );
00926 double x = parseUnit( b.attribute( "x" ) );
00927 double y = parseUnit( b.attribute( "y" ) );
00928 base.moveTo( KoPoint( x, y ) );
00929 base.lineTo( KoPoint( x + 10, y ) );
00930 text = new VText( m_gc.current()->font, base, VText::Above, VText::Left, b.text().simplifyWhiteSpace() );
00931 }
00932
00933 if( text )
00934 {
00935 text->setParent( &m_document );
00936
00937 parseStyle( text, b );
00938 trafo.visit( *text );
00939
00940 if( !b.attribute("id").isEmpty() )
00941 text->setName( b.attribute("id") );
00942
00943 if( grp )
00944 grp->append( text );
00945 else
00946 m_document.append( text );
00947 }
00948 delete( m_gc.pop() );
00949 }
00950
00951 VObject* XAMLImport::createObject( const QDomElement &b )
00952 {
00953 if( b.tagName() == "rect" )
00954 {
00955 addGraphicContext();
00956 double x = parseUnit( b.attribute( "x" ), true, false, m_outerRect );
00957 double y = parseUnit( b.attribute( "y" ), false, true, m_outerRect );
00958 double width = parseUnit( b.attribute( "width" ), true, false, m_outerRect );
00959 double height = parseUnit( b.attribute( "height" ), false, true, m_outerRect );
00960 setupTransform( b );
00961 return new VRectangle( 0L, KoPoint( x, height + y ) , width, height );
00962 }
00963 else if( b.tagName() == "ellipse" )
00964 {
00965 addGraphicContext();
00966 setupTransform( b );
00967 double rx = parseUnit( b.attribute( "rx" ) );
00968 double ry = parseUnit( b.attribute( "ry" ) );
00969 double left = parseUnit( b.attribute( "cx" ) ) - rx;
00970 double top = parseUnit( b.attribute( "cy" ) ) - ry;
00971 return new VEllipse( 0L, KoPoint( left, top ), rx * 2.0, ry * 2.0 );
00972 }
00973 else if( b.tagName() == "circle" )
00974 {
00975 addGraphicContext();
00976 setupTransform( b );
00977 double r = parseUnit( b.attribute( "r" ) );
00978 double left = parseUnit( b.attribute( "cx" ) ) - r;
00979 double top = parseUnit( b.attribute( "cy" ) ) - r;
00980 return new VEllipse( 0L, KoPoint( left, top ), r * 2.0, r * 2.0 );
00981 }
00982 else if( b.tagName() == "line" )
00983 {
00984 addGraphicContext();
00985 setupTransform( b );
00986 VPath *path = new VPath( &m_document );
00987 double x1 = b.attribute( "x1" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x1" ) );
00988 double y1 = b.attribute( "y1" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y1" ) );
00989 double x2 = b.attribute( "x2" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x2" ) );
00990 double y2 = b.attribute( "y2" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y2" ) );
00991 path->moveTo( KoPoint( x1, y1 ) );
00992 path->lineTo( KoPoint( x2, y2 ) );
00993 return path;
00994 }
00995 else if( b.tagName() == "polyline" || b.tagName() == "polygon" )
00996 {
00997 addGraphicContext();
00998 setupTransform( b );
00999 VPath *path = new VPath( &m_document );
01000 bool bFirst = true;
01001
01002 QString points = b.attribute( "points" ).simplifyWhiteSpace();
01003 points.replace( ',', ' ' );
01004 points.remove( '\r' );
01005 points.remove( '\n' );
01006 QStringList pointList = QStringList::split( ' ', points );
01007 for( QStringList::Iterator it = pointList.begin(); it != pointList.end(); ++it)
01008 {
01009 KoPoint point;
01010 point.setX( (*it).toDouble() );
01011 point.setY( (*it).toDouble() );
01012 if( bFirst )
01013 {
01014 path->moveTo( point );
01015 bFirst = false;
01016 }
01017 else
01018 path->lineTo( point );
01019 }
01020 if( b.tagName() == "polygon" ) path->close();
01021 return path;
01022 }
01023 else if( b.tagName() == "path" )
01024 {
01025 addGraphicContext();
01026 setupTransform( b );
01027 VPath *path = new VPath( &m_document );
01028 path->loadSvgPath( b.attribute( "d" ) );
01029 return path;
01030 }
01031 else if( b.tagName() == "image" )
01032 {
01033 addGraphicContext();
01034 setupTransform( b );
01035 QString fname = b.attribute("xlink:href");
01036 return new VImage( 0L, fname );
01037 }
01038
01039 return 0L;
01040 }
01041
01042 #include <xamlimport.moc>