/* This file is part of the KDE project Copyright (C) 2002, 2003, The Karbon Developers This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "xamlimport.h" #include "color.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef KGenericFactory XAMLImportFactory; K_EXPORT_COMPONENT_FACTORY( libkarbonxamlimport, XAMLImportFactory( "kofficefilters" ) ) XAMLImport::XAMLImport(KoFilter *, const char *, const TQStringList&) : KoFilter(), outdoc( "DOC" ) { m_gc.setAutoDelete( true ); } XAMLImport::~XAMLImport() { } KoFilter::ConversionStatus XAMLImport::convert(const TQCString& from, const TQCString& to) { // check for proper conversion if( to != "application/x-karbon" || from != "image/wvg+xml" ) return KoFilter::NotImplemented; //Find the last extension TQString strExt; TQString fileIn ( m_chain->inputFile() ); const int result=fileIn.findRev('.'); if (result>=0) { strExt=fileIn.mid(result).lower(); } TQString strMime; // Mime type of the compressor if ((strExt==".gz") //in case of .svg.gz (logical extension) ||(strExt==".wvgz")) //in case of .svgz (extension used prioritary) strMime="application/x-gzip"; // Compressed with gzip else if (strExt==".bz2") //in case of .svg.bz2 (logical extension) strMime="application/x-bzip2"; // Compressed with bzip2 else strMime="text/plain"; kdDebug(30514) << "File extension: -" << strExt << "- Compression: " << strMime << endl; TQIODevice* in = KFilterDev::deviceForFile(fileIn,strMime); if (!in->open(IO_ReadOnly)) { kdError(30514) << "Cannot open file! Aborting!" << endl; delete in; return KoFilter::FileNotFound; } int line, col; TQString errormessage; const bool parsed=inpdoc.setContent( in, &errormessage, &line, &col ); in->close(); delete in; if ( ! parsed ) { kdError(30514) << "Error while parsing file: " << "at line " << line << " column: " << col << " message: " << errormessage << endl; // ### TODO: feedback to the user return KoFilter::ParsingError; } // Do the conversion! convert(); KoStoreDevice* out = m_chain->storageFile( "root", KoStore::Write ); if( !out ) { kdError(30514) << "Unable to open output file!" << endl; return KoFilter::StorageCreationError; } TQCString cstring = outdoc.toCString(); // utf-8 already out->writeBlock( cstring.data(), cstring.length() ); return KoFilter::OK; // was successful } void XAMLImport::convert() { XAMLGraphicsContext *gc = new XAMLGraphicsContext; TQDomElement docElem = inpdoc.documentElement(); KoRect bbox( 0, 0, 550.0, 841.0 ); double width = !docElem.attribute( "width" ).isEmpty() ? parseUnit( docElem.attribute( "width" ), true, false, bbox ) : 550.0; double height = !docElem.attribute( "height" ).isEmpty() ? parseUnit( docElem.attribute( "height" ), false, true, bbox ) : 841.0; m_document.setWidth( width ); m_document.setHeight( height ); m_outerRect = m_document.boundingBox(); // undo y-mirroring if( !docElem.attribute( "viewBox" ).isEmpty() ) { // allow for viewbox def with ',' or whitespace TQString viewbox( docElem.attribute( "viewBox" ) ); TQStringList points = TQStringList::split( ' ', viewbox.replace( ',', ' ').simplifyWhiteSpace() ); gc->matrix.scale( width / points[2].toFloat() , height / points[3].toFloat() ); m_outerRect.setWidth( m_outerRect.width() * ( points[2].toFloat() / width ) ); m_outerRect.setHeight( m_outerRect.height() * ( points[3].toFloat() / height ) ); } m_gc.push( gc ); parseGroup( 0L, docElem ); TQWMatrix mat; mat.scale( 1, -1 ); mat.translate( 0, -m_document.height() ); VTransformCmd trafo( 0L, mat ); trafo.visit( m_document ); outdoc = m_document.saveXML(); } #define DPI 90 double XAMLImport::toPercentage( TQString s ) { if( s.endsWith( "%" ) ) return s.remove( '%' ).toDouble(); else return s.toDouble() * 100.0; } double XAMLImport::fromPercentage( TQString s ) { if( s.endsWith( "%" ) ) return s.remove( '%' ).toDouble() / 100.0; else return s.toDouble(); } // parses the number into parameter number const char * getNumber( const char *ptr, double &number ) { int integer, exponent; double decimal, frac; int sign, expsign; exponent = 0; integer = 0; frac = 1.0; decimal = 0; sign = 1; expsign = 1; // read the sign if(*ptr == '+') ptr++; else if(*ptr == '-') { ptr++; sign = -1; } // read the integer part while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') integer = (integer * 10) + *(ptr++) - '0'; if(*ptr == '.') // read the decimals { ptr++; while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') decimal += (*(ptr++) - '0') * (frac *= 0.1); } if(*ptr == 'e' || *ptr == 'E') // read the exponent part { ptr++; // read the sign of the exponent if(*ptr == '+') ptr++; else if(*ptr == '-') { ptr++; expsign = -1; } exponent = 0; while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') { exponent *= 10; exponent += *ptr - '0'; ptr++; } } number = integer + decimal; number *= sign * pow( (double)10, double( expsign * exponent ) ); return ptr; } double XAMLImport::parseUnit( const TQString &unit, bool horiz, bool vert, KoRect bbox ) { // TODO : percentage? double value = 0; const char *start = unit.latin1(); if(!start) { return 0; } const char *end = getNumber( start, value ); if( uint( end - start ) < unit.length() ) { if( unit.right( 2 ) == "pt" ) value = ( value / 72.0 ) * DPI; else if( unit.right( 2 ) == "cm" ) value = ( value / 2.54 ) * DPI; else if( unit.right( 2 ) == "pc" ) value = ( value / 6.0 ) * DPI; else if( unit.right( 2 ) == "mm" ) value = ( value / 25.4 ) * DPI; else if( unit.right( 2 ) == "in" ) value = value * DPI; else if( unit.right( 2 ) == "pt" ) value = ( value / 72.0 ) * DPI; else if( unit.right( 2 ) == "em" ) 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 ) ); else if( unit.right( 1 ) == "%" ) { if( horiz && vert ) value = ( value / 100.0 ) * (sqrt( pow( bbox.width(), 2 ) + pow( bbox.height(), 2 ) ) / sqrt( 2.0 ) ); else if( horiz ) value = ( value / 100.0 ) * bbox.width(); else if( vert ) value = ( value / 100.0 ) * bbox.height(); } } /*else { if( m_gc.current() ) { if( horiz && vert ) value *= sqrt( pow( m_gc.current()->matrix.m11(), 2 ) + pow( m_gc.current()->matrix.m22(), 2 ) ) / sqrt( 2.0 ); else if( horiz ) value /= m_gc.current()->matrix.m11(); else if( vert ) value /= m_gc.current()->matrix.m22(); } }*/ return value; } TQColor XAMLImport::parseColor( const TQString &rgbColor ) { int r, g, b; keywordToRGB( rgbColor, r, g, b ); return TQColor( r, g, b ); } void XAMLImport::parseColor( VColor &color, const TQString &s ) { if( s.startsWith( "rgb(" ) ) { TQString parse = s.stripWhiteSpace(); TQStringList colors = TQStringList::split( ',', parse ); TQString r = colors[0].right( ( colors[0].length() - 4 ) ); TQString g = colors[1]; TQString b = colors[2].left( ( colors[2].length() - 1 ) ); if( r.contains( "%" ) ) { r = r.left( r.length() - 1 ); r = TQString::number( int( ( double( 255 * r.toDouble() ) / 100.0 ) ) ); } if( g.contains( "%" ) ) { g = g.left( g.length() - 1 ); g = TQString::number( int( ( double( 255 * g.toDouble() ) / 100.0 ) ) ); } if( b.contains( "%" ) ) { b = b.left( b.length() - 1 ); b = TQString::number( int( ( double( 255 * b.toDouble() ) / 100.0 ) ) ); } TQColor c( r.toInt(), g.toInt(), b.toInt() ); color.set( c.red() / 255.0, c.green() / 255.0, c.blue() / 255.0 ); } else { TQString rgbColor = s.stripWhiteSpace(); TQColor c; if( rgbColor.startsWith( "#" ) ) c.setNamedColor( rgbColor ); else c = parseColor( rgbColor ); color.set( c.red() / 255.0, c.green() / 255.0, c.blue() / 255.0 ); } } void XAMLImport::parseColorStops( VGradient *gradient, const TQDomElement &e ) { VColor c; for( TQDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) { TQDomElement stop = n.toElement(); if( stop.tagName() == "stop" ) { float offset; TQString temp = stop.attribute( "offset" ); if( temp.contains( '%' ) ) { temp = temp.left( temp.length() - 1 ); offset = temp.toFloat() / 100.0; } else offset = temp.toFloat(); if( !stop.attribute( "stop-color" ).isEmpty() ) parseColor( c, stop.attribute( "stop-color" ) ); else { // try style attr TQString style = stop.attribute( "style" ).simplifyWhiteSpace(); TQStringList substyles = TQStringList::split( ';', style ); for( TQStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it ) { TQStringList substyle = TQStringList::split( ':', (*it) ); TQString command = substyle[0].stripWhiteSpace(); TQString params = substyle[1].stripWhiteSpace(); if( command == "stop-color" ) parseColor( c, params ); if( command == "stop-opacity" ) c.setOpacity( params.toDouble() ); } } if( !stop.attribute( "stop-opacity" ).isEmpty() ) c.setOpacity( stop.attribute( "stop-opacity" ).toDouble() ); gradient->addStop( c, offset, 0.5 ); } } } void XAMLImport::parseGradient( const TQDomElement &e ) { GradientHelper gradhelper; gradhelper.gradient.clearStops(); gradhelper.gradient.setRepeatMethod( VGradient::none ); TQString href = e.attribute( "xlink:href" ).mid( 1 ); if( !href.isEmpty() ) { //kdDebug() << "Indexing with href : " << href.latin1() << endl; gradhelper.gradient = m_gradients[ href ].gradient; } gradhelper.bbox = e.attribute( "gradientUnits" ) != "userSpaceOnUse"; if( e.tagName() == "linearGradient" ) { if( gradhelper.bbox ) { gradhelper.gradient.setOrigin( KoPoint( toPercentage( e.attribute( "x1", "0%" ) ), toPercentage( e.attribute( "y1", "0%" ) ) ) ); gradhelper.gradient.setVector( KoPoint( toPercentage( e.attribute( "x2", "100%" ) ), toPercentage( e.attribute( "y2", "0%" ) ) ) ); } else { gradhelper.gradient.setOrigin( KoPoint( e.attribute( "x1" ).toDouble(), e.attribute( "y1" ).toDouble() ) ); gradhelper.gradient.setVector( KoPoint( e.attribute( "x2" ).toDouble(), e.attribute( "y2" ).toDouble() ) ); } } else { if( gradhelper.bbox ) { gradhelper.gradient.setOrigin( KoPoint( toPercentage( e.attribute( "cx", "50%" ) ), toPercentage( e.attribute( "cy", "50%" ) ) ) ); gradhelper.gradient.setVector( KoPoint( toPercentage( e.attribute( "cx", "50%" ) ) + toPercentage( e.attribute( "r", "50%" ) ), toPercentage( e.attribute( "cy", "50%" ) ) ) ); gradhelper.gradient.setFocalPoint( KoPoint( toPercentage( e.attribute( "fx", "50%" ) ), toPercentage( e.attribute( "fy", "50%" ) ) ) ); } else { gradhelper.gradient.setOrigin( KoPoint( e.attribute( "cx" ).toDouble(), e.attribute( "cy" ).toDouble() ) ); gradhelper.gradient.setFocalPoint( KoPoint( e.attribute( "fx" ).toDouble(), e.attribute( "fy" ).toDouble() ) ); gradhelper.gradient.setVector( KoPoint( e.attribute( "cx" ).toDouble() + e.attribute( "r" ).toDouble(), e.attribute( "cy" ).toDouble() ) ); } gradhelper.gradient.setType( VGradient::radial ); } // handle spread method TQString spreadMethod = e.attribute( "spreadMethod" ); if( !spreadMethod.isEmpty() ) { if( spreadMethod == "reflect" ) gradhelper.gradient.setRepeatMethod( VGradient::reflect ); else if( spreadMethod == "repeat" ) gradhelper.gradient.setRepeatMethod( VGradient::repeat ); } parseColorStops( &gradhelper.gradient, e ); //gradient.setGradientTransform( parseTransform( e.attribute( "gradientTransform" ) ) ); gradhelper.gradientTransform = VPath::parseTransform( e.attribute( "gradientTransform" ) ); m_gradients.insert( e.attribute( "id" ), gradhelper ); } void XAMLImport::parsePA( VObject *obj, XAMLGraphicsContext *gc, const TQString &command, const TQString ¶ms ) { VColor fillcolor = gc->fill.color(); VColor strokecolor = gc->stroke.color(); if( command == "fill" ) { if( params == "none" ) gc->fill.setType( VFill::none ); else if( params.startsWith( "url(" ) ) { unsigned int start = params.find("#") + 1; unsigned int end = params.findRev(")"); TQString key = params.mid( start, end - start ); gc->fill.gradient() = m_gradients[ key ].gradient; if( m_gradients[ key ].bbox ) { // adjust to bbox KoRect bbox = obj->boundingBox(); //kdDebug() << "bbox x : " << bbox.x() << endl; //kdDebug() << "!!!!!!bbox y : " << bbox.y() << endl; //kdDebug() << gc->fill.gradient().origin().x() << endl; //kdDebug() << gc->fill.gradient().vector().x() << endl; double offsetx = parseUnit( TQString( "%1%" ).arg( gc->fill.gradient().origin().x() ), true, false, bbox ); double offsety = parseUnit( TQString( "%1%" ).arg( gc->fill.gradient().origin().y() ), false, true, bbox ); gc->fill.gradient().setOrigin( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) ); offsetx = parseUnit( TQString( "%1%" ).arg( gc->fill.gradient().focalPoint().x() ), true, false, bbox ); offsety = parseUnit( TQString( "%1%" ).arg( gc->fill.gradient().focalPoint().y() ), false, true, bbox ); gc->fill.gradient().setFocalPoint( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) ); offsetx = parseUnit( TQString( "%1%" ).arg( gc->fill.gradient().vector().x() ), true, false, bbox ); offsety = parseUnit( TQString( "%1%" ).arg( gc->fill.gradient().vector().y() ), false, true, bbox ); gc->fill.gradient().setVector( KoPoint( bbox.x() + offsetx, bbox.y() + offsety ) ); //kdDebug() << offsety << endl; //kdDebug() << gc->fill.gradient().origin().x() << endl; //kdDebug() << gc->fill.gradient().origin().y() << endl; //kdDebug() << gc->fill.gradient().vector().x() << endl; //kdDebug() << gc->fill.gradient().vector().y() << endl; } gc->fill.gradient().transform( m_gradients[ key ].gradientTransform ); if( !m_gradients[ key ].bbox ) gc->fill.gradient().transform( gc->matrix ); gc->fill.setType( VFill::grad ); } else { parseColor( fillcolor, params ); gc->fill.setType( VFill::solid ); } } else if( command == "fill-rule" ) { if( params == "nonzero" ) gc->fillRule = winding; else if( params == "evenodd" ) gc->fillRule = evenOdd; } else if( command == "stroke" ) { if( params == "none" ) gc->stroke.setType( VStroke::none ); else if( params.startsWith( "url(" ) ) { unsigned int start = params.find("#") + 1; unsigned int end = params.findRev(")"); TQString key = params.mid( start, end - start ); gc->stroke.gradient() = m_gradients[ key ].gradient; gc->stroke.gradient().transform( m_gradients[ key ].gradientTransform ); gc->stroke.gradient().transform( gc->matrix ); gc->stroke.setType( VStroke::grad ); } else { parseColor( strokecolor, params ); gc->stroke.setType( VStroke::solid ); } } else if( command == "stroke-width" ) gc->stroke.setLineWidth( parseUnit( params, true, true, m_outerRect ) ); else if( command == "stroke-linejoin" ) { if( params == "miter" ) gc->stroke.setLineJoin( VStroke::joinMiter ); else if( params == "round" ) gc->stroke.setLineJoin( VStroke::joinRound ); else if( params == "bevel" ) gc->stroke.setLineJoin( VStroke::joinBevel ); } else if( command == "stroke-linecap" ) { if( params == "butt" ) gc->stroke.setLineCap( VStroke::capButt ); else if( params == "round" ) gc->stroke.setLineCap( VStroke::capRound ); else if( params == "square" ) gc->stroke.setLineCap( VStroke::capSquare ); } else if( command == "stroke-miterlimit" ) gc->stroke.setMiterLimit( params.toFloat() ); else if( command == "stroke-dasharray" ) { TQValueList array; if(params != "none") { TQStringList dashes = TQStringList::split( ' ', params ); for( TQStringList::Iterator it = dashes.begin(); it != dashes.end(); ++it ) array.append( (*it).toFloat() ); } gc->stroke.dashPattern().setArray( array ); } else if( command == "stroke-dashoffset" ) gc->stroke.dashPattern().setOffset( params.toFloat() ); // handle opacity else if( command == "stroke-opacity" ) strokecolor.setOpacity( fromPercentage( params ) ); else if( command == "fill-opacity" ) fillcolor.setOpacity( fromPercentage( params ) ); else if( command == "opacity" ) { fillcolor.setOpacity( fromPercentage( params ) ); strokecolor.setOpacity( fromPercentage( params ) ); } else if( command == "font-family" ) { TQString family = params; family.replace( '\'' , ' ' ); gc->font.setFamily( family ); } else if( command == "font-size" ) { float pointSize = parseUnit( params ); pointSize *= gc->matrix.m22() > 0 ? gc->matrix.m22() : -1.0 * gc->matrix.m22(); gc->font.setPointSizeFloat( pointSize ); } else if( command == "text-decoration" ) { if( params == "line-through" ) gc->font.setStrikeOut( true ); else if( params == "underline" ) gc->font.setUnderline( true ); } if( gc->fill.type() != VFill::none ) gc->fill.setColor( fillcolor, false ); //if( gc->stroke.type() == VStroke::solid ) gc->stroke.setColor( strokecolor ); } void XAMLImport::addGraphicContext() { XAMLGraphicsContext *gc = new XAMLGraphicsContext; // set as default if( m_gc.current() ) *gc = *( m_gc.current() ); m_gc.push( gc ); } void XAMLImport::setupTransform( const TQDomElement &e ) { XAMLGraphicsContext *gc = m_gc.current(); TQWMatrix mat = VPath::parseTransform( e.attribute( "transform" ) ); gc->matrix = mat * gc->matrix; } void XAMLImport::parseStyle( VObject *obj, const TQDomElement &e ) { XAMLGraphicsContext *gc = m_gc.current(); if( !gc ) return; // try normal PA if( !e.attribute( "fill" ).isEmpty() ) parsePA( obj, gc, "fill", e.attribute( "fill" ) ); if( !e.attribute( "fill-rule" ).isEmpty() ) parsePA( obj, gc, "fill-rule", e.attribute( "fill-rule" ) ); if( !e.attribute( "stroke" ).isEmpty() ) parsePA( obj, gc, "stroke", e.attribute( "stroke" ) ); if( !e.attribute( "stroke-width" ).isEmpty() ) parsePA( obj, gc, "stroke-width", e.attribute( "stroke-width" ) ); if( !e.attribute( "stroke-linejoin" ).isEmpty() ) parsePA( obj, gc, "stroke-linejoin", e.attribute( "stroke-linejoin" ) ); if( !e.attribute( "stroke-linecap" ).isEmpty() ) parsePA( obj, gc, "stroke-linecap", e.attribute( "stroke-linecap" ) ); if( !e.attribute( "stroke-dasharray" ).isEmpty() ) parsePA( obj, gc, "stroke-dasharray", e.attribute( "stroke-dasharray" ) ); if( !e.attribute( "stroke-dashoffset" ).isEmpty() ) parsePA( obj, gc, "stroke-dashoffset", e.attribute( "stroke-dashoffset" ) ); if( !e.attribute( "stroke-opacity" ).isEmpty() ) parsePA( obj, gc, "stroke-opacity", e.attribute( "stroke-opacity" ) ); if( !e.attribute( "stroke-miterlimit" ).isEmpty() ) parsePA( obj, gc, "stroke-miterlimit", e.attribute( "stroke-miterlimit" ) ); if( !e.attribute( "fill-opacity" ).isEmpty() ) parsePA( obj, gc, "fill-opacity", e.attribute( "fill-opacity" ) ); if( !e.attribute( "opacity" ).isEmpty() ) parsePA( obj, gc, "opacity", e.attribute( "opacity" ) ); // try style attr TQString style = e.attribute( "style" ).simplifyWhiteSpace(); TQStringList substyles = TQStringList::split( ';', style ); for( TQStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it ) { TQStringList substyle = TQStringList::split( ':', (*it) ); TQString command = substyle[0].stripWhiteSpace(); TQString params = substyle[1].stripWhiteSpace(); parsePA( obj, gc, command, params ); } obj->setFill( gc->fill ); if( dynamic_cast( obj ) ) dynamic_cast( obj )->setFillRule( gc->fillRule ); // stroke scaling double lineWidth = gc->stroke.lineWidth(); gc->stroke.setLineWidth( lineWidth * sqrt( pow( m_gc.current()->matrix.m11(), 2 ) + pow( m_gc.current()->matrix.m22(), 2 ) ) / sqrt( 2.0 ) ); obj->setStroke( gc->stroke ); gc->stroke.setLineWidth( lineWidth ); } void XAMLImport::parseFont( const TQDomElement &e ) { XAMLGraphicsContext *gc = m_gc.current(); if( !gc ) return; if( ! e.attribute( "font-family" ).isEmpty() ) parsePA( 0L, m_gc.current(), "font-family", e.attribute( "font-family" ) ); if( ! e.attribute( "font-size" ).isEmpty() ) parsePA( 0L, m_gc.current(), "font-size", e.attribute( "font-size" ) ); if( ! e.attribute( "text-decoration" ).isEmpty() ) parsePA( 0L, m_gc.current(), "text-decoration", e.attribute( "text-decoration" ) ); } void XAMLImport::parseGroup( VGroup *grp, const TQDomElement &e ) { bool isDef = false; if( e.tagName() == "defs" ) isDef = true; for( TQDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() ) { TQDomElement b = n.toElement(); if( b.isNull() ) continue; VObject *obj = 0L; if( b.tagName() == "g" ) { VGroup *group; if ( grp ) group = new VGroup( grp ); else group = new VGroup( &m_document ); addGraphicContext(); setupTransform( b ); parseStyle( group, b ); parseFont( b ); parseGroup( group, b ); // handle id if( !b.attribute("id").isEmpty() ) group->setName( b.attribute("id") ); if( grp ) grp->append( group ); else m_document.append( group ); delete( m_gc.pop() ); continue; } if( b.tagName() == "defs" ) { parseGroup( 0L, b ); // try for gradients at least continue; } else if( b.tagName() == "linearGradient" || b.tagName() == "radialGradient" ) { parseGradient( b ); continue; } else if( b.tagName() == "rect" || b.tagName() == "ellipse" || b.tagName() == "circle" || b.tagName() == "line" || b.tagName() == "polyline" || b.tagName() == "polygon" || b.tagName() == "path" || b.tagName() == "image" ) { if (!isDef) obj = createObject( b ); else m_paths.insert( b.attribute( "id" ), b ); } else if( b.tagName() == "text" ) { if( isDef ) m_paths.insert( b.attribute( "id" ), b ); else createText( grp, b ); } else if( b.tagName() == "use" ) { double tx = b.attribute( "x" ).toDouble(); double ty = b.attribute( "y" ).toDouble(); if( !b.attribute( "xlink:href" ).isEmpty() ) { TQString params = b.attribute( "xlink:href" ); unsigned int start = params.find("#") + 1; unsigned int end = params.findRev(")"); TQString key = params.mid( start, end - start ); if(m_paths.contains(key)) { TQDomElement a = m_paths[key]; obj = createObject( a ); m_gc.current()->matrix.translate(tx,ty); parsePA( grp, m_gc.current(), "fill", b.attribute( "fill" ) ); } } } if( !obj ) continue; VTransformCmd trafo( 0L, m_gc.current()->matrix ); trafo.visit( *obj ); parseStyle( obj, b ); // handle id if( !b.attribute("id").isEmpty() ) obj->setName( b.attribute("id") ); if( grp ) grp->append( obj ); else m_document.append( obj ); delete( m_gc.pop() ); } } VObject* XAMLImport::findObject( const TQString &name, VGroup* group ) { if( ! group ) return 0L; VObjectListIterator itr = group->objects(); for( uint objcount = 1; itr.current(); ++itr, objcount++ ) if( itr.current()->state() != VObject::deleted ) { if( itr.current()->name() == name ) return itr.current(); if( dynamic_cast( itr.current() ) ) { VObject *obj = findObject( name, dynamic_cast( itr.current() ) ); if( obj ) return obj; } } return 0L; } VObject* XAMLImport::findObject( const TQString &name ) { TQPtrVector vector; m_document.layers().toVector( &vector ); for( int i = vector.count() - 1; i >= 0; i-- ) { if ( vector[i]->state() != VObject::deleted ) { VObject* obj = findObject( name, dynamic_cast( vector[i] ) ); if( obj ) return obj; } } return 0L; } void XAMLImport::createText( VGroup *grp, const TQDomElement &b ) { VText *text = 0L; TQString content; VSubpath base( 0L ); VPath *path = 0L; addGraphicContext(); setupTransform( b ); VTransformCmd trafo( 0L, m_gc.current()->matrix ); parseFont( b ); if( b.hasChildNodes() ) { if( base.isEmpty() && ! b.attribute( "x" ).isEmpty() && ! b.attribute( "y" ).isEmpty() ) { double x = parseUnit( b.attribute( "x" ) ); double y = parseUnit( b.attribute( "y" ) ); base.moveTo( KoPoint( x, y ) ); base.lineTo( KoPoint( x + 10, y ) ); } for( TQDomNode n = b.firstChild(); !n.isNull(); n = n.nextSibling() ) { TQDomElement e = n.toElement(); if( e.isNull() ) { content += n.toCharacterData().data(); } else if( e.tagName() == "textPath" ) { if( e.attribute( "xlink:href" ).isEmpty() ) continue; TQString uri = e.attribute( "xlink:href" ); unsigned int start = uri.find("#") + 1; unsigned int end = uri.findRev(")"); TQString key = uri.mid( start, end - start ); if( ! m_paths.contains(key) ) { VObject* obj = findObject( key ); if( obj ) path = dynamic_cast( obj ); } else { TQDomElement p = m_paths[key]; path = dynamic_cast( createObject( p ) ); if( path ) path->setState( VObject::deleted ); } if( ! path ) continue; base = *path->paths().getFirst(); content += e.text(); } else if( e.tagName() == "tspan" ) { // only use text of tspan element, as we are not supporting text // with different styles content += e.text(); if( base.isEmpty() && ! e.attribute( "x" ).isEmpty() && ! e.attribute( "y" ).isEmpty() ) { TQStringList posX = TQStringList::split( ", ", e.attribute( "x" ) ); TQStringList posY = TQStringList::split( ", ", e.attribute( "y" ) ); if( posX.count() && posY.count() ) { double x = parseUnit( posX.first() ); double y = parseUnit( posY.first() ); base.moveTo( KoPoint( x, y ) ); base.lineTo( KoPoint( x + 10, y ) ); } } } else if( e.tagName() == "tref" ) { if( e.attribute( "xlink:href" ).isEmpty() ) continue; TQString uri = e.attribute( "xlink:href" ); unsigned int start = uri.find("#") + 1; unsigned int end = uri.findRev(")"); TQString key = uri.mid( start, end - start ); if( ! m_paths.contains(key) ) { VObject* obj = findObject( key ); if( obj ) content += dynamic_cast( obj )->text(); } else { TQDomElement p = m_paths[key]; content += p.text(); } } else continue; } text = new VText( m_gc.current()->font, base, VText::Above, VText::Left, content.simplifyWhiteSpace() ); } else { VSubpath base( 0L ); double x = parseUnit( b.attribute( "x" ) ); double y = parseUnit( b.attribute( "y" ) ); base.moveTo( KoPoint( x, y ) ); base.lineTo( KoPoint( x + 10, y ) ); text = new VText( m_gc.current()->font, base, VText::Above, VText::Left, b.text().simplifyWhiteSpace() ); } if( text ) { text->setParent( &m_document ); parseStyle( text, b ); trafo.visit( *text ); if( !b.attribute("id").isEmpty() ) text->setName( b.attribute("id") ); if( grp ) grp->append( text ); else m_document.append( text ); } delete( m_gc.pop() ); } VObject* XAMLImport::createObject( const TQDomElement &b ) { if( b.tagName() == "rect" ) { addGraphicContext(); double x = parseUnit( b.attribute( "x" ), true, false, m_outerRect ); double y = parseUnit( b.attribute( "y" ), false, true, m_outerRect ); double width = parseUnit( b.attribute( "width" ), true, false, m_outerRect ); double height = parseUnit( b.attribute( "height" ), false, true, m_outerRect ); setupTransform( b ); return new VRectangle( 0L, KoPoint( x, height + y ) , width, height ); } else if( b.tagName() == "ellipse" ) { addGraphicContext(); setupTransform( b ); double rx = parseUnit( b.attribute( "rx" ) ); double ry = parseUnit( b.attribute( "ry" ) ); double left = parseUnit( b.attribute( "cx" ) ) - rx; double top = parseUnit( b.attribute( "cy" ) ) - ry; return new VEllipse( 0L, KoPoint( left, top ), rx * 2.0, ry * 2.0 ); } else if( b.tagName() == "circle" ) { addGraphicContext(); setupTransform( b ); double r = parseUnit( b.attribute( "r" ) ); double left = parseUnit( b.attribute( "cx" ) ) - r; double top = parseUnit( b.attribute( "cy" ) ) - r; return new VEllipse( 0L, KoPoint( left, top ), r * 2.0, r * 2.0 ); } else if( b.tagName() == "line" ) { addGraphicContext(); setupTransform( b ); VPath *path = new VPath( &m_document ); double x1 = b.attribute( "x1" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x1" ) ); double y1 = b.attribute( "y1" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y1" ) ); double x2 = b.attribute( "x2" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x2" ) ); double y2 = b.attribute( "y2" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y2" ) ); path->moveTo( KoPoint( x1, y1 ) ); path->lineTo( KoPoint( x2, y2 ) ); return path; } else if( b.tagName() == "polyline" || b.tagName() == "polygon" ) { addGraphicContext(); setupTransform( b ); VPath *path = new VPath( &m_document ); bool bFirst = true; TQString points = b.attribute( "points" ).simplifyWhiteSpace(); points.replace( ',', ' ' ); points.remove( '\r' ); points.remove( '\n' ); TQStringList pointList = TQStringList::split( ' ', points ); for( TQStringList::Iterator it = pointList.begin(); it != pointList.end(); ++it) { KoPoint point; point.setX( (*it).toDouble() ); point.setY( (*it).toDouble() ); if( bFirst ) { path->moveTo( point ); bFirst = false; } else path->lineTo( point ); } if( b.tagName() == "polygon" ) path->close(); return path; } else if( b.tagName() == "path" ) { addGraphicContext(); setupTransform( b ); VPath *path = new VPath( &m_document ); path->loadSvgPath( b.attribute( "d" ) ); return path; } else if( b.tagName() == "image" ) { addGraphicContext(); setupTransform( b ); TQString fname = b.attribute("xlink:href"); return new VImage( 0L, fname ); } return 0L; } #include