Back to index

scribus-ng  1.3.4.dfsg+svn20071115
svgplugin.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 #include "svgplugin.h"
00008 #include "svgplugin.moc"
00009 
00010 #include "scconfig.h"
00011 
00012 #include "customfdialog.h"
00013 #include "color.h"
00014 #include "scribus.h"
00015 #include "scribusXml.h"
00016 #include "mpalette.h"
00017 #include "prefsfile.h"
00018 #include <qfile.h>
00019 #include <qtextstream.h>
00020 #include <qdragobject.h>
00021 #include <qregexp.h>
00022 #include <qcursor.h>
00023 #include <cmath>
00024 #include <zlib.h>
00025 #include "commonstrings.h"
00026 #include "fpointarray.h"
00027 #include "menumanager.h"
00028 #include "prefsmanager.h"
00029 #include "pageitem.h"
00030 #include "scraction.h"
00031 #include "scribuscore.h"
00032 #include "scribusdoc.h"
00033 #include "selection.h"
00034 #include "undomanager.h"
00035 #include "loadsaveplugin.h"
00036 #include "util.h"
00037 #include "fonts/scfontmetrics.h"
00038 #include "sccolorengine.h"
00039 
00040 using namespace std;
00041 
00042 int svgimplugin_getPluginAPIVersion()
00043 {
00044        return PLUGIN_API_VERSION;
00045 }
00046 
00047 ScPlugin* svgimplugin_getPlugin()
00048 {
00049        SVGImportPlugin* plug = new SVGImportPlugin();
00050        Q_CHECK_PTR(plug);
00051        return plug;
00052 }
00053 
00054 void svgimplugin_freePlugin(ScPlugin* plugin)
00055 {
00056        SVGImportPlugin* plug = dynamic_cast<SVGImportPlugin*>(plugin);
00057        Q_ASSERT(plug);
00058        delete plug;
00059 }
00060 
00061 SVGImportPlugin::SVGImportPlugin() : LoadSavePlugin(),
00062        importAction(new ScrAction(ScrAction::DLL, QIconSet(), "", QKeySequence(), this, "ImportSVG"))
00063 {
00064        // Set action info in languageChange, so we only have to do
00065        // it in one place. This includes registering file format
00066        // support.
00067        languageChange();
00068 }
00069 
00070 void SVGImportPlugin::addToMainWindowMenu(ScribusMainWindow *mw)
00071 {
00072        importAction->setEnabled(true);
00073        connect( importAction, SIGNAL(activated()), SLOT(import()) );
00074        mw->scrMenuMgr->addMenuItem(importAction, "FileImport");
00075 }
00076 
00077 SVGImportPlugin::~SVGImportPlugin()
00078 {
00079        unregisterAll();
00080 };
00081 
00082 void SVGImportPlugin::languageChange()
00083 {
00084        importAction->setMenuText( tr("Import &SVG..."));
00085        // (Re)register file format support.
00086        unregisterAll();
00087        registerFormats();
00088 }
00089 
00090 const QString SVGImportPlugin::fullTrName() const
00091 {
00092        return QObject::tr("SVG Import");
00093 }
00094 
00095 const ScActionPlugin::AboutData* SVGImportPlugin::getAboutData() const
00096 {
00097        AboutData* about = new AboutData;
00098        about->authors = "Franz Schmid <franz@scribus.info>";
00099        about->shortDescription = tr("Imports SVG Files");
00100        about->description = tr("Imports most SVG files into the current document,\nconverting their vector data into Scribus objects.");
00101        about->license = "GPL";
00102        Q_CHECK_PTR(about);
00103        return about;
00104 }
00105 
00106 void SVGImportPlugin::deleteAboutData(const AboutData* about) const
00107 {
00108        Q_ASSERT(about);
00109        delete about;
00110 }
00111 
00112 void SVGImportPlugin::registerFormats()
00113 {
00114        QString svgName = tr("Scalable Vector Graphics");
00115        FileFormat fmt(this);
00116        fmt.trName = svgName;
00117        fmt.formatId = FORMATID_SVGIMPORT;
00118        fmt.filter = svgName + " (*.svg *.SVG *.svgz *.SVGZ)";
00119        fmt.nameMatch = QRegExp("\\.(svg|svgz)$", false);
00120        fmt.load = true;
00121        fmt.save = false;
00122        fmt.mimeTypes = QStringList("image/svg+xml");
00123        fmt.priority = 64;
00124        registerFormat(fmt);
00125 }
00126 
00127 bool SVGImportPlugin::fileSupported(QIODevice* /* file */, const QString & fileName) const
00128 {
00129        // TODO: identify valid SVG
00130        return true;
00131 }
00132 
00133 bool SVGImportPlugin::loadFile(const QString & fileName, const FileFormat & /* fmt */, int flags, int /*index*/)
00134 {
00135        // For now, "load file" and import are the same thing for this plugin
00136        return import(fileName, flags);
00137 }
00138 
00139 bool SVGImportPlugin::import(QString filename, int flags)
00140 {
00141        if (!checkFlags(flags))
00142               return false;
00143        m_Doc=ScCore->primaryMainWindow()->doc;
00144        ScribusMainWindow* mw=(m_Doc==0) ? ScCore->primaryMainWindow() : m_Doc->scMW();
00145        if (filename.isEmpty())
00146        {
00147               flags |= lfInteractive;
00148               PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("SVGPlugin");
00149               QString wdir = prefs->get("wdir", ".");
00150               CustomFDialog diaf(mw, wdir, QObject::tr("Open"), QObject::tr("SVG-Images (*.svg *.svgz);;All Files (*)"));
00151               if (diaf.exec())
00152               {
00153                      filename = diaf.selectedFile();
00154                      prefs->set("wdir", filename.left(filename.findRev("/")));
00155               }
00156               else
00157                      return true;
00158        }
00159        
00160        if (UndoManager::undoEnabled() && m_Doc)
00161        {
00162               UndoManager::instance()->beginTransaction(m_Doc->currentPage()->getUName(),Um::IImageFrame,Um::ImportSVG, filename, Um::ISVG);
00163        }
00164        else if (UndoManager::undoEnabled() && !m_Doc)
00165               UndoManager::instance()->setUndoEnabled(false);
00166        SVGPlug *dia = new SVGPlug(mw, flags);
00167        dia->import(filename, flags);
00168        Q_CHECK_PTR(dia);
00169        if (UndoManager::undoEnabled())
00170               UndoManager::instance()->commit();
00171        else
00172               UndoManager::instance()->setUndoEnabled(true);
00173        if (dia->importCanceled)
00174        {
00175               if (dia->importFailed)
00176                      QMessageBox::warning(mw, CommonStrings::trWarning, tr("The file could not be imported"), 1, 0, 0);
00177               else if (dia->unsupported)
00178                      QMessageBox::warning(mw, CommonStrings::trWarning, tr("SVG file contains some unsupported features"), 1, 0, 0);
00179        }
00180 
00181        delete dia;
00182        return true;
00183 }
00184 
00185 SVGPlug::SVGPlug( ScribusMainWindow* mw, int flags ) :
00186        QObject(mw)
00187 {      
00188        tmpSel=new Selection(this, false);
00189        m_Doc=mw->doc;
00190        unsupported = false;
00191        importFailed = false;
00192        importCanceled = true;
00193        importedColors.clear();
00194        docDesc = "";
00195        docTitle = "";
00196        groupLevel = 0;
00197        interactive = (flags & LoadSavePlugin::lfInteractive);
00198        m_gc.setAutoDelete( true );
00199 }
00200 
00201 bool SVGPlug::import(QString fname, int flags)
00202 {
00203        if (!loadData(fname))
00204               return false;
00205        QString CurDirP = QDir::currentDirPath();
00206        QFileInfo efp(fname);
00207        QDir::setCurrent(efp.dirPath());
00208        convert(flags);
00209        QDir::setCurrent(CurDirP);
00210        return true;
00211 }
00212 
00213 bool SVGPlug::loadData(QString fName)
00214 {
00215        QString f("");
00216        bool isCompressed = false;
00217        QByteArray bb(3);
00218        QFile fi(fName);
00219        if (fi.open(IO_ReadOnly))
00220        {
00221               fi.readBlock(bb.data(), 2);
00222               fi.close();
00223               if ((bb[0] == QChar(0x1F)) && (bb[1] == QChar(0x8B)))
00224                      isCompressed = true;
00225        }
00226        if ((fName.right(2) == "gz") || (isCompressed))
00227        {
00228               gzFile gzDoc;
00229               char buff[4097];
00230               int i;
00231               gzDoc = gzopen(fName.latin1(),"rb");
00232               if(gzDoc == NULL)
00233                      return false;
00234               while((i = gzread(gzDoc,&buff,4096)) > 0)
00235               {
00236                      buff[i] = '\0';
00237                      f.append(buff);
00238               }
00239               gzclose(gzDoc);
00240        }
00241        else
00242               loadText(fName, &f);
00243        return inpdoc.setContent(f);
00244 }
00245 
00246 void SVGPlug::convert(int flags)
00247 {
00248        bool ret = false;
00249        SvgStyle *gc = new SvgStyle;
00250        QDomElement docElem = inpdoc.documentElement();
00251        QSize wh = parseWidthHeight(docElem);
00252        double width = wh.width();
00253        double height = wh.height();
00254        if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
00255        {
00256               m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
00257               m_Doc->addPage(0);
00258               m_Doc->view()->addPage(0);
00259        }
00260        else
00261        {
00262               if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
00263               {
00264                      m_Doc=ScCore->primaryMainWindow()->doFileNew(width, height, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
00265                      ScCore->primaryMainWindow()->HaveNewDoc();
00266                      ret = true;
00267               }
00268        }
00269        if ((ret) || (!interactive))
00270        {
00271               if (width > height)
00272                      m_Doc->PageOri = 1;
00273               else
00274                      m_Doc->PageOri = 0;
00275               m_Doc->m_pageSize = "Custom";
00276        }
00277        FPoint minSize = m_Doc->minCanvasCoordinate;
00278        FPoint maxSize = m_Doc->maxCanvasCoordinate;
00279        m_Doc->view()->Deselect();
00280        m_Doc->setLoading(true);
00281        m_Doc->DoDrawing = false;
00282        m_Doc->view()->updatesOn(false);
00283        m_Doc->scMW()->ScriptRunning = true;
00284        qApp->setOverrideCursor(QCursor(waitCursor), true);
00285        gc->Family = m_Doc->toolSettings.defFont;
00286        m_Doc->PageColors.ensureBlackAndWhite();
00287        m_gc.push( gc );
00288        viewTransformX = 0;
00289        viewTransformY = 0;
00290        viewScaleX = 1;
00291        viewScaleY = 1;
00292        if( !docElem.attribute( "viewBox" ).isEmpty() )
00293        {
00294               QWMatrix matrix;
00295               QSize wh2 = parseWidthHeight(docElem);
00296               double w2 = wh2.width();
00297               double h2 = wh2.height();
00298               addGraphicContext();
00299               QString viewbox( docElem.attribute( "viewBox" ) );
00300               QStringList points = QStringList::split( ' ', viewbox.replace( QRegExp(","), " ").simplifyWhiteSpace() );
00301               viewTransformX = points[0].toDouble();
00302               viewTransformY = points[1].toDouble();
00303               viewScaleX = w2 / points[2].toDouble();
00304               viewScaleY = h2 / points[3].toDouble();
00305               matrix.translate(viewTransformX, viewTransformY);
00306               matrix.scale(viewScaleX, viewScaleY);
00307               m_gc.current()->matrix = matrix;
00308        }
00309        QPtrList<PageItem> Elements = parseGroup( docElem );
00310        if (flags & LoadSavePlugin::lfCreateDoc)
00311        {
00312               m_Doc->documentInfo.setTitle(docTitle);
00313               m_Doc->documentInfo.setComments(docDesc);
00314        }
00315        tmpSel->clear();
00316        if (Elements.count() == 0)
00317        {
00318               importFailed = true;
00319               if (importedColors.count() != 0)
00320               {
00321                      for (uint cd = 0; cd < importedColors.count(); cd++)
00322                      {
00323                             m_Doc->PageColors.remove(importedColors[cd]);
00324                      }
00325               }
00326        }
00327        if (Elements.count() > 1)
00328        {
00329               bool isGroup = true;
00330               int firstElem = -1;
00331               if (Elements.at(0)->Groups.count() != 0)
00332                      firstElem = Elements.at(0)->Groups.top();
00333               for (uint bx = 0; bx < Elements.count(); ++bx)
00334               {
00335                      PageItem* bxi = Elements.at(bx);
00336                      if (bxi->Groups.count() != 0)
00337                      {
00338                             if (bxi->Groups.top() != firstElem)
00339                                    isGroup = false;
00340                      }
00341                      else
00342                             isGroup = false;
00343               }
00344               if (!isGroup)
00345               {
00346                      double minx = 99999.9;
00347                      double miny = 99999.9;
00348                      double maxx = -99999.9;
00349                      double maxy = -99999.9;
00350                      uint lowestItem = 999999;
00351                      uint highestItem = 0;
00352                      for (uint a = 0; a < Elements.count(); ++a)
00353                      {
00354                             Elements.at(a)->Groups.push(m_Doc->GroupCounter);
00355                             PageItem* currItem = Elements.at(a);
00356                             lowestItem = QMIN(lowestItem, currItem->ItemNr);
00357                             highestItem = QMAX(highestItem, currItem->ItemNr);
00358                             double lw = currItem->lineWidth() / 2.0;
00359                             if (currItem->rotation() != 0)
00360                             {
00361                                    FPointArray pb;
00362                                    pb.resize(0);
00363                                    pb.addPoint(FPoint(currItem->xPos()-lw, currItem->yPos()-lw));
00364                                    pb.addPoint(FPoint(currItem->width()+lw*2.0, -lw, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00365                                    pb.addPoint(FPoint(currItem->width()+lw*2.0, currItem->height()+lw*2.0, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00366                                    pb.addPoint(FPoint(-lw, currItem->height()+lw*2.0, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00367                                    for (uint pc = 0; pc < 4; ++pc)
00368                                    {
00369                                           minx = QMIN(minx, pb.point(pc).x());
00370                                           miny = QMIN(miny, pb.point(pc).y());
00371                                           maxx = QMAX(maxx, pb.point(pc).x());
00372                                           maxy = QMAX(maxy, pb.point(pc).y());
00373                                    }
00374                             }
00375                             else
00376                             {
00377                                    minx = QMIN(minx, currItem->xPos()-lw);
00378                                    miny = QMIN(miny, currItem->yPos()-lw);
00379                                    maxx = QMAX(maxx, currItem->xPos()-lw + currItem->width()+lw*2.0);
00380                                    maxy = QMAX(maxy, currItem->yPos()-lw + currItem->height()+lw*2.0);
00381                             }
00382                      }
00383                      double gx = minx;
00384                      double gy = miny;
00385                      double gw = maxx - minx;
00386                      double gh = maxy - miny;
00387                      PageItem *high = m_Doc->Items->at(highestItem);
00388                      int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, gx, gy, gw, gh, 0, m_Doc->toolSettings.dBrush, m_Doc->toolSettings.dPen, true);
00389                      PageItem *neu = m_Doc->Items->take(z);
00390                      m_Doc->Items->insert(lowestItem, neu);
00391                      neu->Groups.push(m_Doc->GroupCounter);
00392                      neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
00393                      neu->isGroupControl = true;
00394                      neu->groupsLastItem = high;
00395                      for (uint a = 0; a < m_Doc->Items->count(); ++a)
00396                      {
00397                             m_Doc->Items->at(a)->ItemNr = a;
00398                      }
00399                      neu->setRedrawBounding();
00400                      neu->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
00401                      Elements.prepend(neu);
00402                      m_Doc->GroupCounter++;
00403               }
00404        }
00405        m_Doc->DoDrawing = true;
00406        m_Doc->scMW()->ScriptRunning = false;
00407        if (interactive)
00408               m_Doc->setLoading(false);
00409        qApp->setOverrideCursor(QCursor(arrowCursor), true);
00410        if ((Elements.count() > 0) && (!ret) && (interactive))
00411        {
00412               if (flags & LoadSavePlugin::lfScripted)
00413               {
00414                      bool loadF = m_Doc->isLoading();
00415                      m_Doc->setLoading(false);
00416                      m_Doc->changed();
00417                      m_Doc->setLoading(loadF);
00418                      for (uint dre=0; dre<Elements.count(); ++dre)
00419                      {
00420                             m_Doc->m_Selection->addItem(Elements.at(dre), true);
00421                      }
00422                      m_Doc->m_Selection->setGroupRect();
00423                      m_Doc->view()->updatesOn(true);
00424                      importCanceled = false;
00425               }
00426               else
00427               {
00428                      m_Doc->DragP = true;
00429                      m_Doc->DraggedElem = 0;
00430                      m_Doc->DragElements.clear();
00431                      for (uint dre=0; dre<Elements.count(); ++dre)
00432                      {
00433                             m_Doc->DragElements.append(Elements.at(dre)->ItemNr);
00434                             tmpSel->addItem(Elements.at(dre), true);
00435                      }
00436                      ScriXmlDoc *ss = new ScriXmlDoc();
00437                      tmpSel->setGroupRect();
00438                      QDragObject * dr = new QTextDrag(ss->WriteElem(m_Doc, m_Doc->view(), tmpSel), m_Doc->view());
00439 #ifndef QT_MAC
00440 // see #2526
00441                      m_Doc->itemSelection_DeleteItem(tmpSel);
00442 #endif
00443                      m_Doc->view()->resizeContents(qRound((maxSize.x() - minSize.x()) * m_Doc->view()->scale()), qRound((maxSize.y() - minSize.y()) * m_Doc->view()->scale()));
00444                      m_Doc->view()->scrollBy(qRound((m_Doc->minCanvasCoordinate.x() - minSize.x()) * m_Doc->view()->scale()), qRound((m_Doc->minCanvasCoordinate.y() - minSize.y()) * m_Doc->view()->scale()));
00445                      m_Doc->minCanvasCoordinate = minSize;
00446                      m_Doc->maxCanvasCoordinate = maxSize;
00447                      m_Doc->view()->updatesOn(true);
00448                      dr->setPixmap(loadIcon("DragPix.xpm"));
00449                      dr->drag();
00450                      /*importCanceled = dr->drag();
00451                      if (!importCanceled)
00452                      {
00453                             if (importedColors.count() != 0)
00454                             {
00455                                    for (uint cd = 0; cd < importedColors.count(); cd++)
00456                                    {
00457                                           m_Doc->PageColors.remove(importedColors[cd]);
00458                                    }
00459                             }
00460                      }*/
00461                      delete ss;
00462                      m_Doc->DragP = false;
00463                      m_Doc->DraggedElem = 0;
00464                      m_Doc->DragElements.clear();
00465               }
00466        }
00467        else
00468        {
00469               bool loadF = m_Doc->isLoading();
00470               m_Doc->setLoading(false);
00471               m_Doc->changed();
00472               m_Doc->reformPages();
00473               m_Doc->view()->updatesOn(true);
00474               m_Doc->setLoading(loadF);
00475        }
00476 }
00477 
00478 void SVGPlug::addGraphicContext()
00479 {
00480        SvgStyle *gc = new SvgStyle;
00481        if ( m_gc.current() )
00482               *gc = *( m_gc.current() );
00483        m_gc.push( gc );
00484 }
00485 
00486 void SVGPlug::setupNode( const QDomElement &e )
00487 {
00488        addGraphicContext();
00489        setupTransform( e );
00490        parseStyle(m_gc.current(), e);
00491 }
00492 
00493 void SVGPlug::setupTransform( const QDomElement &e )
00494 {
00495        SvgStyle *gc = m_gc.current();
00496        QWMatrix mat = parseTransform( e.attribute( "transform" ) );
00497        if (!e.attribute("transform").isEmpty())
00498               gc->matrix = mat * gc->matrix;
00499 }
00500 
00501 void SVGPlug::finishNode( const QDomElement &e, PageItem* item)
00502 {
00503        SvgStyle *gc = m_gc.current();
00504        QWMatrix gcm = gc->matrix;
00505        double BaseX = m_Doc->currentPage()->xOffset();
00506        double BaseY = m_Doc->currentPage()->yOffset();
00507        double coeff1 = sqrt(gcm.m11() * gcm.m11() + gcm.m12() * gcm.m12());
00508        double coeff2 = sqrt(gcm.m21() * gcm.m21() + gcm.m22() * gcm.m22());
00509        switch (item->itemType())
00510        {
00511        case PageItem::ImageFrame:
00512               {
00513                      QWMatrix mm = gc->matrix;
00514                      item->moveBy(mm.dx(), mm.dy());
00515                      item->setWidthHeight(item->width() * mm.m11(), item->height() * mm.m22());
00516                      item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
00517                      if (item->PicAvail)
00518                             item->setImageXYScale(item->width() / item->pixm.width(), item->height() / item->pixm.height());
00519                      break;
00520               }
00521        case PageItem::TextFrame:
00522               {
00523                      QWMatrix mm = gc->matrix;
00524                      item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
00525               }
00526               break;
00527        default:
00528               {
00529                      item->ClipEdited = true;
00530                      item->FrameType = 3;
00531                      QWMatrix mm = gc->matrix;
00532                      item->PoLine.map(mm);
00533                      /*if (haveViewBox)
00534                      {
00535                             QWMatrix mv;
00536                             mv.translate(viewTransformX, viewTransformY);
00537                             mv.scale(viewScaleX, viewScaleY);
00538                             ite->PoLine.map(mv);
00539                      }*/
00540                      item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
00541                      FPoint wh = getMaxClipF(&item->PoLine);
00542                      item->setWidthHeight(wh.x(), wh.y());
00543 //                   if (item->asPolyLine())
00544 //                          item->setPolyClip(qRound(QMAX(item->lineWidth() / 2.0, 1)));
00545 //                   else
00546 //                          item->Clip = FlattenPath(item->PoLine, item->Segments);
00547                      m_Doc->AdjustItemSize(item);
00548                      break;
00549               }
00550        }
00551        item->setRedrawBounding();
00552        item->OwnPage = m_Doc->OnPage(item);
00553        if( !e.attribute("id").isEmpty() )
00554               item->setItemName(" "+e.attribute("id"));
00555        item->setFillTransparency( 1 - gc->FillOpacity * gc->Opacity );
00556        item->setLineTransparency( 1 - gc->StrokeOpacity * gc->Opacity );
00557        item->PLineEnd = gc->PLineEnd;
00558        item->PLineJoin = gc->PLineJoin;
00559        if (item->fillColor() == CommonStrings::None)
00560               item->setTextFlowMode(PageItem::TextFlowDisabled);
00561        else
00562               item->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
00563        item->DashOffset = gc->dashOffset;
00564        item->DashValues = gc->dashArray;
00565        if (gc->Gradient != 0)
00566        {
00567               if (gc->GradCo.Stops() > 1)
00568               {
00569                      item->fill_gradient = gc->GradCo;
00570                      if (!gc->CSpace)
00571                      {
00572                             item->GrStartX = gc->GX1 * item->width();
00573                             item->GrStartY = gc->GY1 * item->height();
00574                             item->GrEndX = gc->GX2 * item->width();
00575                             item->GrEndY = gc->GY2 * item->height();
00576                             double angle1 = atan2(gc->GY2-gc->GY1,gc->GX2-gc->GX1)*(180.0/M_PI);
00577                             double angle2 = atan2(item->GrEndY - item->GrStartX, item->GrEndX - item->GrStartX)*(180.0/M_PI);
00578                             double dx = item->GrStartX + (item->GrEndX - item->GrStartX) / 2.0;
00579                             double dy = item->GrStartY + (item->GrEndY - item->GrStartY) / 2.0;
00580                             QWMatrix mm, mm2;
00581                             if ((gc->GY1 < gc->GY2) && (gc->GX1 < gc->GX2))
00582                             {
00583                                    mm.rotate(-angle2);
00584                                    mm2.rotate(angle1);
00585                             }
00586                             FPointArray gra;
00587                             gra.setPoints(2, item->GrStartX-dx, item->GrStartY-dy, item->GrEndX-dx, item->GrEndY-dy);
00588                             gra.map(mm*mm2);
00589                             gra.translate(dx, dy);
00590                             item->GrStartX = gra.point(0).x();
00591                             item->GrStartY = gra.point(0).y();
00592                             item->GrEndX = gra.point(1).x();
00593                             item->GrEndY = gra.point(1).y();
00594                      }
00595                      else
00596                      {
00597                             QWMatrix mm = gc->matrix;
00598                             mm = gc->matrixg * mm;
00599                             FPointArray gra;
00600                             gra.setPoints(2, gc->GX1, gc->GY1, gc->GX2, gc->GY2);
00601                             gra.map(mm);
00602                             gc->GX1 = gra.point(0).x();
00603                             gc->GY1 = gra.point(0).y();
00604                             gc->GX2 = gra.point(1).x();
00605                             gc->GY2 = gra.point(1).y();
00606                             item->GrStartX = gc->GX1 - item->xPos() + BaseX;
00607                             item->GrStartY = gc->GY1 - item->yPos() + BaseY;
00608                             item->GrEndX = gc->GX2 - item->xPos() + BaseX;
00609                             item->GrEndY = gc->GY2 - item->yPos() + BaseY;
00610                      }
00611                      item->GrType = gc->Gradient;
00612               }
00613               else
00614               {
00615                      item->GrType = 0;
00616                      QPtrVector<VColorStop> cstops = gc->GradCo.colorStops();
00617                      item->setFillColor(cstops.at(0)->name);
00618                      item->setFillShade(cstops.at(0)->shade);
00619               }
00620        }
00621 }
00622 
00623 bool SVGPlug::isIgnorableNode( const QDomElement &e )
00624 {
00625        QString nodeName(e.tagName());
00626        if (nodeName == "metadata" || nodeName.contains("sodipodi") || nodeName.contains("inkscape"))
00627               return true;
00628        return false;
00629 }
00630 
00631 FPoint SVGPlug::parseTextPosition(const QDomElement &e)
00632 {
00633        // FIXME According to spec, we should in fact return a point list 
00634        QString xatt =  e.attribute( "x", "0" );
00635        QString yatt =  e.attribute( "y", "0" );
00636        if ( xatt.contains(',') || xatt.contains(' ') )
00637        {
00638               xatt.replace(QChar(','), QChar(' '));
00639               QStringList xl(QStringList::split(QChar(' '), xatt));
00640               xatt = xl.first();
00641        }
00642        if ( yatt.contains(',') || yatt.contains(' ') )
00643        {
00644               yatt.replace(QChar(','), QChar(' '));
00645               QStringList yl(QStringList::split(QChar(' '), yatt));
00646               yatt = yl.first();
00647        }
00648        double x = parseUnit( xatt );
00649        double y = parseUnit( yatt );
00650        return FPoint(x, y);
00651 }
00652 
00653 QSize SVGPlug::parseWidthHeight(const QDomElement &e)
00654 {
00655        QSize size(550, 841);
00656        QString sw = e.attribute("width", "100%");
00657        QString sh = e.attribute("height", "100%");
00658        double w =  550, h = 841;
00659        if (!sw.isEmpty())
00660               w = sw.endsWith("%") ? fromPercentage(sw) : parseUnit(sw);
00661        if (!sh.isEmpty())
00662               h = sh.endsWith("%") ? fromPercentage(sh) : parseUnit(sh);
00663        if (!e.attribute("viewBox").isEmpty())
00664        {
00665               QRect viewBox = parseViewBox(e);
00666               double scw = (viewBox.width() > 0 && viewBox.height() > 0) ? viewBox.width()  : size.width();
00667               double sch = (viewBox.width() > 0 && viewBox.height() > 0) ? viewBox.height() : size.height();
00668               w *= (sw.endsWith("%") ? scw : 1.0);
00669               h *= (sh.endsWith("%") ? sch : 1.0);
00670        }
00671        else
00672        {
00673               w *= (sw.endsWith("%") ? size.width() : 1.0);
00674               h *= (sh.endsWith("%") ? size.height() : 1.0);
00675        }
00676        // OpenOffice files may not have width and height attributes, so avoid unnecessary large dimensions
00677        if (w > 10000 || h > 10000)
00678        {
00679               double m = max(w, h);
00680               w = w / m * 842;
00681               h = h / m * 842;
00682        }
00683        size.setWidth(qRound(w));
00684        size.setHeight(qRound(h));
00685        return size;
00686 }
00687 
00688 QRect SVGPlug::parseViewBox(const QDomElement &e)
00689 {
00690        QRect box(0, 0, 0, 0);
00691        if ( !e.attribute( "viewBox" ).isEmpty() )
00692        {
00693               QString viewbox( e.attribute( "viewBox" ) );
00694               QStringList points = QStringList::split( ' ', viewbox.replace( QRegExp(","), " ").simplifyWhiteSpace() );
00695               double left = points[0].toDouble();
00696               double bottom  = points[1].toDouble();
00697               double width = points[2].toDouble();
00698               double height = points[3].toDouble();
00699               box.setCoords((int) left, (int) bottom, (int) (left + width), (int) (bottom + height));
00700        }
00701        return box;
00702 }
00703 
00704 void SVGPlug::parseDefs(const QDomElement &e)
00705 {
00706        for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
00707        {
00708               QDomElement b = n.toElement();
00709               if ( b.isNull() )
00710                      continue;
00711               SvgStyle svgStyle;
00712               parseStyle( &svgStyle, b );
00713               if ( !svgStyle.Display) 
00714                      continue;
00715               QString STag2 = b.tagName();
00716               if ( STag2 == "g" )
00717                      parseDefs(b);
00718               else if ( STag2 == "linearGradient" || STag2 == "radialGradient" )
00719                      parseGradient( b );
00720               else if (STag2 == "clipPath")
00721                      parseClipPath(b);
00722               else if ( b.hasAttribute("id") )
00723               {
00724                      QString id = b.attribute("id");
00725                      if (!id.isEmpty())
00726                             m_nodeMap.insert(id, b);
00727               }
00728        }
00729 }
00730 
00731 void SVGPlug::parseClipPath(const QDomElement &e)
00732 {
00733        QString id(e.attribute("id"));
00734        if (!id.isEmpty())
00735        {
00736               FPointArray clip;
00737               QDomNode n2 = e.firstChild();
00738               QDomElement b2 = n2.toElement();
00739               while (b2.nodeName() == "use")
00740                      b2 = getReferencedNode(b2);
00741               if (b2.nodeName() == "path")
00742                      parseSVG( b2.attribute( "d" ), &clip );
00743               else if (b2.nodeName() == "rect")
00744               {
00745                      double width = parseUnit( b2.attribute( "width" ));
00746                      double height = parseUnit( b2.attribute( "height" ) );
00747                      clip.addQuadPoint(0.0, 0.0, 0.0, 0.0, width, 0.0, width, 0.0);
00748                      clip.addQuadPoint(width, 0.0, width, 0.0, width, height, width, height);
00749                      clip.addQuadPoint(width, height, width, height, 0.0, height, 0.0, height);
00750                      clip.addQuadPoint(0.0, height, 0.0, height, 0.0, 0.0, 0.0, 0.0);
00751               }
00752               if (clip.size() >= 2)
00753                      m_clipPaths.insert(id, clip);
00754        }
00755 }
00756 
00757 void SVGPlug::parseClipPathAttr(const QDomElement &e, FPointArray& clipPath)
00758 {
00759        clipPath.resize(0);
00760        if (e.hasAttribute("clip-path"))
00761        {
00762               QString attr = e.attribute("clip-path");
00763               if (attr.startsWith( "url("))
00764               {
00765                      unsigned int start = attr.find("#") + 1;
00766                      unsigned int end = attr.findRev(")");
00767                      QString key = attr.mid(start, end - start);
00768                      QMap<QString, FPointArray>::iterator it = m_clipPaths.find(key);
00769                      if (it != m_clipPaths.end())
00770                             clipPath = it.data().copy();
00771               }
00772        }
00773 }
00774 
00775 QPtrList<PageItem> SVGPlug::parseGroup(const QDomElement &e)
00776 {
00777        FPointArray clipPath;
00778        QPtrList<PageItem> GElements, gElements;
00779        double BaseX = m_Doc->currentPage()->xOffset();
00780        double BaseY = m_Doc->currentPage()->yOffset();
00781        groupLevel++;
00782        setupNode(e);
00783        parseClipPathAttr(e, clipPath);
00784        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, 1, 1, 0, CommonStrings::None, CommonStrings::None, true);
00785        PageItem *neu = m_Doc->Items->at(z);
00786        for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
00787        {
00788               QDomElement b = n.toElement();
00789               if( b.isNull() || isIgnorableNode(b) )
00790                      continue;
00791               SvgStyle svgStyle;
00792               parseStyle( &svgStyle, b );
00793               if (!svgStyle.Display) 
00794                      continue;
00795               QPtrList<PageItem> el = parseElement(b);
00796               for (uint ec = 0; ec < el.count(); ++ec)
00797                      gElements.append(el.at(ec));
00798        }
00799        groupLevel--;
00800        SvgStyle *gc = m_gc.current();
00801        if (gElements.count() < 2 && (clipPath.size() == 0) && (gc->Opacity == 1.0))
00802        {
00803               m_Doc->Items->take(z);
00804               delete neu;
00805               for (uint a = 0; a < m_Doc->Items->count(); ++a)
00806               {
00807                      m_Doc->Items->at(a)->ItemNr = a;
00808               }
00809               for (uint gr = 0; gr < gElements.count(); ++gr)
00810               {
00811                      GElements.append(gElements.at(gr));
00812               }
00813        }
00814        else
00815        {
00816               double minx = 99999.9;
00817               double miny = 99999.9;
00818               double maxx = -99999.9;
00819               double maxy = -99999.9;
00820               GElements.append(neu);
00821               for (uint gr = 0; gr < gElements.count(); ++gr)
00822               {
00823                      PageItem* currItem = gElements.at(gr);
00824                      double lw = currItem->lineWidth() / 2.0;
00825                      if (currItem->rotation() != 0)
00826                      {
00827                             FPointArray pb;
00828                             pb.resize(0);
00829                             pb.addPoint(FPoint(currItem->xPos()-lw, currItem->yPos()-lw));
00830                             pb.addPoint(FPoint(currItem->width()+lw*2.0, -lw, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00831                             pb.addPoint(FPoint(currItem->width()+lw*2.0, currItem->height()+lw*2.0, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00832                             pb.addPoint(FPoint(-lw, currItem->height()+lw*2.0, currItem->xPos()-lw, currItem->yPos()-lw, currItem->rotation(), 1.0, 1.0));
00833                             for (uint pc = 0; pc < 4; ++pc)
00834                             {
00835                                    minx = QMIN(minx, pb.point(pc).x());
00836                                    miny = QMIN(miny, pb.point(pc).y());
00837                                    maxx = QMAX(maxx, pb.point(pc).x());
00838                                    maxy = QMAX(maxy, pb.point(pc).y());
00839                             }
00840                      }
00841                      else
00842                      {
00843                             minx = QMIN(minx, currItem->xPos()-lw);
00844                             miny = QMIN(miny, currItem->yPos()-lw);
00845                             maxx = QMAX(maxx, currItem->xPos()-lw + currItem->width()+lw*2.0);
00846                             maxy = QMAX(maxy, currItem->yPos()-lw + currItem->height()+lw*2.0);
00847                      }
00848               }
00849               double gx = minx;
00850               double gy = miny;
00851               double gw = maxx - minx;
00852               double gh = maxy - miny;
00853               neu->setXYPos(gx, gy);
00854               neu->setWidthHeight(gw, gh);
00855               if (clipPath.size() != 0)
00856               {
00857                      QWMatrix mm;
00858                      mm.translate(-gx + BaseX, -gy + BaseY);
00859                      neu->PoLine = clipPath.copy();
00860                      neu->PoLine.map(mm);
00861                      clipPath.resize(0);
00862                      /* fix for needless large groups created by the cairo svg-export, won't work tho with complex clip paths
00863                      FPoint tp2(getMinClipF(&neu->PoLine));
00864                      FPoint tp(getMaxClipF(&neu->PoLine));
00865                      if ((tp2.x() < 0) && (tp2.y() < 0) && (tp.x() > neu->width()) && (tp.y() > neu->height()))
00866                             neu->SetRectFrame(); */
00867               }
00868               else
00869                      neu->SetRectFrame();
00870               neu->Clip = FlattenPath(neu->PoLine, neu->Segments);
00871               neu->Groups.push(m_Doc->GroupCounter);
00872               neu->isGroupControl = true;
00873               neu->groupsLastItem = gElements.at(gElements.count()-1);
00874               if( !e.attribute("id").isEmpty() )
00875                      neu->setItemName(e.attribute("id"));
00876               else
00877                      neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
00878               neu->setFillTransparency(1 - gc->Opacity);
00879               for (uint gr = 0; gr < gElements.count(); ++gr)
00880               {
00881                      gElements.at(gr)->Groups.push(m_Doc->GroupCounter);
00882                      GElements.append(gElements.at(gr));
00883               }
00884               neu->setRedrawBounding();
00885               neu->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
00886               m_Doc->GroupCounter++;
00887        }
00888        delete( m_gc.pop() );
00889        return GElements;
00890 }
00891 
00892 QPtrList<PageItem> SVGPlug::parseElement(const QDomElement &e)
00893 {
00894        QPtrList<PageItem> GElements;
00895        if (e.hasAttribute("id"))
00896               m_nodeMap.insert(e.attribute("id"), e);
00897        QString STag = e.tagName();
00898        if( STag == "g" )
00899        {
00900               GElements = parseGroup( e );
00901               return GElements;
00902        }
00903        if( STag == "defs" )
00904               parseDefs(e);
00905        else if( STag == "switch" )
00906               GElements = parseSwitch(e);
00907        else if( STag == "symbol" )
00908               GElements = parseSymbol(e);
00909        else if( STag == "use" )
00910               GElements = parseUse(e);
00911        else if( STag == "linearGradient" || STag == "radialGradient" )
00912               parseGradient( e );
00913        else if( STag == "rect" )
00914               GElements = parseRect(e);
00915        else if( STag == "ellipse" )
00916               GElements = parseEllipse(e);
00917        else if( STag == "circle" )
00918               GElements = parseCircle(e);
00919        else if( STag == "line" )
00920               GElements = parseLine(e);
00921        else if( STag == "path" )
00922               GElements = parsePath(e);
00923        else if( STag == "polyline" || e.tagName() == "polygon" )
00924               GElements = parsePolyline(e);
00925        else if( STag == "text" )
00926               GElements = parseText(e);
00927        else if( STag == "clipPath" )
00928               parseClipPath(e);
00929        else if( STag == "desc" )
00930        {
00931               if (groupLevel == 1)
00932                      docDesc = e.text();
00933        }
00934        else if( STag == "title" )
00935        {
00936               if (groupLevel == 1)
00937                      docTitle = e.text();
00938        }
00939 /*     else if( STag == "image" )
00940               GElements = parseImage(e);
00941        } */
00942        else
00943        {
00944               // warn if unsupported SVG feature are encountered
00945               qDebug(QString("unsupported SVG feature: %1").arg(STag));
00946               unsupported = true;
00947        }
00948        return GElements;
00949 }
00950 
00951 QPtrList<PageItem> SVGPlug::parseCircle(const QDomElement &e)
00952 {
00953        QPtrList<PageItem> CElements;
00954        double BaseX = m_Doc->currentPage()->xOffset();
00955        double BaseY = m_Doc->currentPage()->yOffset();
00956        double r = parseUnit( e.attribute( "r" ) );
00957        double x = parseUnit( e.attribute( "cx" ) ) - r;
00958        double y = parseUnit( e.attribute( "cy" ) ) - r;
00959        setupNode(e);
00960        SvgStyle *gc = m_gc.current();
00961        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, r * 2.0, r * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
00962        PageItem* ite = m_Doc->Items->at(z);
00963        QWMatrix mm = QWMatrix();
00964        mm.translate(x, y);
00965        ite->PoLine.map(mm);
00966        FPoint wh = getMaxClipF(&ite->PoLine);
00967        ite->setWidthHeight(wh.x(), wh.y());
00968        finishNode(e, ite);
00969        CElements.append(ite);
00970        delete( m_gc.pop() );
00971        return CElements;
00972 }
00973 
00974 QPtrList<PageItem> SVGPlug::parseEllipse(const QDomElement &e)
00975 {
00976        QPtrList<PageItem> EElements;
00977        double BaseX = m_Doc->currentPage()->xOffset();
00978        double BaseY = m_Doc->currentPage()->yOffset();
00979        double rx = parseUnit( e.attribute( "rx" ) );
00980        double ry = parseUnit( e.attribute( "ry" ) );
00981        double x = parseUnit( e.attribute( "cx" ) ) - rx;
00982        double y = parseUnit( e.attribute( "cy" ) ) - ry;
00983        setupNode(e);
00984        SvgStyle *gc = m_gc.current();
00985        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, rx * 2.0, ry * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
00986        PageItem* ite = m_Doc->Items->at(z);
00987        QWMatrix mm = QWMatrix();
00988        mm.translate(x, y);
00989        ite->PoLine.map(mm);
00990        FPoint wh = getMaxClipF(&ite->PoLine);
00991        ite->setWidthHeight(wh.x(), wh.y());
00992        finishNode(e, ite);
00993        EElements.append(ite);
00994        delete( m_gc.pop() );
00995        return EElements;
00996 }
00997 
00998 QPtrList<PageItem> SVGPlug::parseImage(const QDomElement &e)
00999 {
01000        FPointArray clipPath;
01001        QPtrList<PageItem> IElements;
01002        QString fname = e.attribute("xlink:href");
01003        double BaseX = m_Doc->currentPage()->xOffset();
01004        double BaseY = m_Doc->currentPage()->yOffset();
01005        double x = e.attribute( "x" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x" ) );
01006        double y = e.attribute( "y" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y" ) );
01007        double w = e.attribute( "width" ).isEmpty() ? 1.0 : parseUnit( e.attribute( "width" ) );
01008        double h = e.attribute( "height" ).isEmpty() ? 1.0 : parseUnit( e.attribute( "height" ) );
01009        setupNode(e);
01010        parseClipPathAttr(e, clipPath);
01011        int z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Unspecified, x+BaseX, y+BaseY, w, h, 1, m_Doc->toolSettings.dBrushPict, CommonStrings::None, true);
01012        if (!fname.isEmpty())
01013               m_Doc->LoadPict(fname, z);
01014        PageItem* ite = m_Doc->Items->at(z);
01015        if (clipPath.size() != 0)
01016               ite->PoLine = clipPath.copy();
01017        clipPath.resize(0);
01018        ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
01019        finishNode(e, ite);
01020        IElements.append(ite);
01021        delete( m_gc.pop() );
01022        return IElements;
01023 }
01024 
01025 QPtrList<PageItem> SVGPlug::parseLine(const QDomElement &e)
01026 {
01027        QPtrList<PageItem> LElements;
01028        double BaseX = m_Doc->currentPage()->xOffset();
01029        double BaseY = m_Doc->currentPage()->yOffset();
01030        double x1 = e.attribute( "x1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x1" ) );
01031        double y1 = e.attribute( "y1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y1" ) );
01032        double x2 = e.attribute( "x2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x2" ) );
01033        double y2 = e.attribute( "y2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y2" ) );
01034        setupNode(e);
01035        SvgStyle *gc = m_gc.current();
01036        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
01037        PageItem* ite = m_Doc->Items->at(z);
01038        ite->PoLine.resize(4);
01039        ite->PoLine.setPoint(0, FPoint(x1, y1));
01040        ite->PoLine.setPoint(1, FPoint(x1, y1));
01041        ite->PoLine.setPoint(2, FPoint(x2, y2));
01042        ite->PoLine.setPoint(3, FPoint(x2, y2));
01043        finishNode(e, ite);
01044        LElements.append(ite);
01045        delete( m_gc.pop() );
01046        return LElements;
01047 }
01048 
01049 QPtrList<PageItem> SVGPlug::parsePath(const QDomElement &e)
01050 {
01051        FPointArray pArray;
01052        QPtrList<PageItem> PElements;
01053        double BaseX = m_Doc->currentPage()->xOffset();
01054        double BaseY = m_Doc->currentPage()->yOffset();
01055        setupNode(e);
01056        SvgStyle *gc = m_gc.current();
01057        PageItem::ItemType itype = parseSVG(e.attribute("d"), &pArray) ? PageItem::PolyLine : PageItem::Polygon; 
01058        int z = m_Doc->itemAdd(itype, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
01059        PageItem* ite = m_Doc->Items->at(z);
01060        ite->fillRule = (gc->fillRule != "nonzero");
01061        ite->PoLine = pArray;
01062        if (ite->PoLine.size() < 4)
01063        {
01064 //                   m_Doc->m_Selection->addItem(ite);
01065               tmpSel->addItem(ite);
01066 //                   m_Doc->itemSelection_DeleteItem();
01067               m_Doc->itemSelection_DeleteItem(tmpSel);
01068 //                   m_Doc->m_Selection->clear();
01069        }
01070        else
01071        {
01072               finishNode(e, ite);
01073               PElements.append(ite);
01074        }
01075        delete( m_gc.pop() );
01076        return PElements;
01077 }
01078 
01079 QPtrList<PageItem> SVGPlug::parsePolyline(const QDomElement &e)
01080 {
01081        int z;
01082        QPtrList<PageItem> PElements;
01083        double BaseX = m_Doc->currentPage()->xOffset();
01084        double BaseY = m_Doc->currentPage()->yOffset();
01085        setupNode(e);
01086        SvgStyle *gc = m_gc.current();
01087        QString points = e.attribute( "points" );
01088        if (!points.isEmpty())
01089        {
01090               QString STag = e.tagName();
01091               points = points.simplifyWhiteSpace().replace(',', " ");
01092               QStringList pointList = QStringList::split( ' ', points );
01093               if (( e.tagName() == "polygon" ) && (pointList.count() > 4))
01094                      z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
01095               else
01096                      z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
01097               PageItem* ite = m_Doc->Items->at(z);
01098               ite->fillRule = (gc->fillRule != "nonzero"); 
01099               ite->PoLine.resize(0);
01100               ite->PoLine.svgInit();
01101               bool bFirst = true;
01102               double x = 0.0;
01103               double y = 0.0;
01104               for( QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++ )
01105               {
01106                      if( bFirst )
01107                      {
01108                             x = (*(it++)).toDouble();
01109                             y = (*it).toDouble();
01110                             ite->PoLine.svgMoveTo(x, y);
01111                             bFirst = false;
01112                      }
01113                      else
01114                      {
01115                             x = (*(it++)).toDouble();
01116                             y = (*it).toDouble();
01117                             ite->PoLine.svgLineTo(x, y);
01118                      }
01119               }
01120               if (( STag == "polygon" ) && (pointList.count() > 4))
01121                      ite->PoLine.svgClosePath();
01122               else
01123                      ite->convertTo(PageItem::PolyLine);
01124               finishNode(e, ite);
01125               PElements.append(ite);
01126        }
01127        delete( m_gc.pop() );
01128        return PElements;
01129 }
01130 
01131 QPtrList<PageItem> SVGPlug::parseRect(const QDomElement &e)
01132 {
01133        QPtrList<PageItem> RElements;
01134        double BaseX = m_Doc->currentPage()->xOffset();
01135        double BaseY = m_Doc->currentPage()->yOffset();
01136        double x = parseUnit( e.attribute( "x" ) );
01137        double y = parseUnit( e.attribute( "y" ) );
01138        double width = parseUnit( e.attribute( "width" ));
01139        double height = parseUnit( e.attribute( "height" ) );
01140        double rx = e.attribute( "rx" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "rx" ) );
01141        double ry = e.attribute( "ry" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "ry" ) );
01142        setupNode(e);
01143        SvgStyle *gc = m_gc.current();
01144        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, width, height, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
01145        PageItem* ite = m_Doc->Items->at(z);
01146        if ((rx != 0) || (ry != 0))
01147        {
01148               ite->setCornerRadius(QMAX(rx, ry));
01149               ite->SetFrameRound();
01150               m_Doc->setRedrawBounding(ite);
01151        }
01152        QWMatrix mm = QWMatrix();
01153        mm.translate(x, y);
01154        ite->PoLine.map(mm);
01155        FPoint wh = getMaxClipF(&ite->PoLine);
01156        ite->setWidthHeight(wh.x(), wh.y());
01157        finishNode(e, ite);
01158        RElements.append(ite);
01159        delete( m_gc.pop() );
01160        return RElements;
01161 }
01162 
01163 QPtrList<PageItem> SVGPlug::parseText(const QDomElement &e)
01164 {
01165        QPtrList<PageItem> GElements;
01166        setupNode(e);
01167        QDomNode c = e.firstChild();
01168        //double x = e.attribute( "x" ).isEmpty() ? 0.0 : parseUnit(e.attribute("x"));
01169        //double y = e.attribute( "y" ).isEmpty() ? 0.0 : parseUnit(e.attribute("y"));
01170        FPoint p = parseTextPosition(e);
01171        double x = p.x(), y = p.y();
01172        if ((!c.isNull()) && (c.toElement().tagName() == "tspan"))
01173        {
01174               for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
01175               {
01176                      QDomElement tspan = n.toElement();
01177                      addGraphicContext();
01178                      SvgStyle *gc = m_gc.current();
01179                      parseStyle(gc, tspan);
01180                      if (!gc->Display)
01181                             continue;
01182                      QPtrList<PageItem> el = parseTextElement(x, y, tspan);
01183                      for (uint ec = 0; ec < el.count(); ++ec)
01184                             GElements.append(el.at(ec));
01185                      delete( m_gc.pop() );
01186               }
01187        }
01188        else
01189        {
01190 //            SvgStyle *gc = m_gc.current();
01191               QPtrList<PageItem> el = parseTextElement(x, y, e);
01192               for (uint ec = 0; ec < el.count(); ++ec)
01193                      GElements.append(el.at(ec));
01194        }
01195        delete( m_gc.pop() );
01196        return GElements;
01197 }
01198 
01199 QPtrList<PageItem> SVGPlug::parseTextElement(double x, double y, const QDomElement &e)
01200 {
01201        QPtrList<PageItem> GElements;
01202 //     QFont ff(m_Doc->UsedFonts[m_gc.current()->Family]);
01203        QFont ff(m_gc.current()->Family);
01204        ff.setPointSize(QMAX(qRound(m_gc.current()->FontSize / 10.0), 1));
01205        QFontMetrics fontMetrics(ff);
01206        int desc = fontMetrics.descent();
01207        double BaseX = m_Doc->currentPage()->xOffset();
01208        double BaseY = m_Doc->currentPage()->yOffset();
01209        QString Text = QString::fromUtf8(e.text()).stripWhiteSpace();
01210        QDomNode c = e.firstChild();
01211        if ( e.tagName() == "tspan" && e.text().isNull() )
01212                      Text = " ";
01213 
01214        double maxWidth = 0, maxHeight = 0;
01215        double tempW = 0, tempH = 0;
01216        SvgStyle *gc = m_gc.current();
01217        double ity = (e.tagName() == "tspan") ? y : (y - qRound(gc->FontSize / 10.0));
01218        int z = m_Doc->itemAdd(PageItem::TextFrame, PageItem::Unspecified, x, ity, 10, 10, gc->LWidth, CommonStrings::None, gc->FillCol, true);
01219        PageItem* ite = m_Doc->Items->at(z);
01220        ite->setTextToFrameDist(0.0, 0.0, 0.0, 0.0);
01221 //FIXME:av                  ite->setLineSpacing(gc->FontSize / 10.0 + 2);
01222        const double lineSpacing = gc->FontSize / 10.0 + 2;
01223        ite->setHeight(lineSpacing +desc+2);
01224        m_Doc->scMW()->SetNewFont(gc->Family);
01225        QWMatrix mm = gc->matrix;
01226        double scalex = sqrt(mm.m11() * mm.m11() + mm.m12() * mm.m12());
01227        double scaley = sqrt(mm.m21() * mm.m21() + mm.m22() * mm.m22());
01228        if( (!e.attribute("x").isEmpty()) && (!e.attribute("y").isEmpty()) )
01229        {
01230               FPoint p = parseTextPosition(e);
01231               double x1 = p.x(), y1 = p.y();
01232               double mx = mm.m11() * x1 + mm.m21() * y1 + mm.dx();
01233               double my = mm.m12() * x1 + mm.m22() * y1 + mm.dy();
01234               ite->setXPos(mx + BaseX);
01235               ite->setYPos(my + BaseY);
01236        }
01237        else
01238        {
01239               double mx = mm.m11() * x + mm.m21() * y + mm.dx();
01240               double my = mm.m12() * x + mm.m22() * y + mm.dy();
01241               ite->setXPos(mx + BaseX);
01242               ite->setYPos(my + BaseY);
01243        }
01244        ite->setFillColor(CommonStrings::None);
01245        ite->setLineColor(CommonStrings::None);
01246        /*
01247        ite->setFont(gc->Family);
01248        ite->TxtFill = gc->FillCol;
01249        ite->ShTxtFill = 100;
01250        ite->TxtStroke = gc->StrokeCol;
01251        ite->ShTxtStroke = 100;
01252        ite->setFontSize(gc->FontSize);
01253        ite->TxTStyle = 0;
01254        ite->TxtScale = 1000;
01255        ite->TxtScaleV = 1000;
01256        ite->TxtBase = 0;
01257        ite->TxtShadowX = 50;
01258        ite->TxtShadowY = -50;
01259        ite->TxtOutline = 10;
01260        ite->TxtUnderPos = -1;
01261        ite->TxtUnderWidth = -1;
01262        ite->TxtStrikePos = -1;
01263        ite->TxtStrikeWidth = -1;
01264               */
01265        for (uint tt = 0; tt < Text.length(); ++tt)
01266        {
01267               CharStyle nstyle;
01268               QString ch = Text.mid(tt,1);
01269               nstyle.setFont((*m_Doc->AllFonts)[gc->Family]);
01270               nstyle.setFontSize(gc->FontSize);
01271               nstyle.setFillColor(gc->FillCol);
01272               nstyle.setTracking(0);
01273               nstyle.setFillShade(100);
01274               nstyle.setStrokeColor(gc->StrokeCol);
01275               nstyle.setStrokeShade(100);
01276               nstyle.setScaleH(1000);
01277               nstyle.setScaleV(1000);
01278               nstyle.setBaselineOffset(0);
01279               nstyle.setShadowXOffset(50);
01280               nstyle.setShadowYOffset(-50);
01281               nstyle.setOutlineWidth(10);
01282               nstyle.setUnderlineOffset(-1);
01283               nstyle.setUnderlineWidth(-1);
01284               nstyle.setStrikethruOffset(-1);
01285               nstyle.setStrikethruWidth(-1);
01286               if( !e.attribute( "stroke" ).isEmpty() )
01287                      nstyle.setFeatures(StyleFlag(ScStyle_Outline).featureList());
01288               else
01289                      nstyle.setFeatures(StyleFlag(ScStyle_Default).featureList());
01290               int pos = ite->itemText.length();
01291               ite->itemText.insertChars(pos, ch);
01292               ite->itemText.applyCharStyle(pos, 1, nstyle);
01293               tempW += nstyle.font().realCharWidth(ch[0], nstyle.fontSize() / 10.0)+1;
01294               tempH  = nstyle.font().realCharHeight(ch[0], nstyle.fontSize() / 10.0);
01295               maxWidth  = (tempW > maxWidth) ? tempW : maxWidth;
01296               maxHeight = (tempH > maxHeight) ? tempH : maxHeight;
01297               if (ch == SpecialChars::PARSEP)
01298               {
01299                      ite->setWidthHeight(QMAX(ite->width(), tempW), ite->height() + lineSpacing+desc);
01300                      tempW = 0;
01301               }
01302        }
01303        double xpos = ite->xPos();
01304        double ypos = ite->yPos();
01305        ite->setWidthHeight(QMAX(ite->width(), maxWidth), QMAX(ite->height(), maxHeight));
01306        double xoffset = 0.0, yoffset = 0.0;
01307        if( gc->textAnchor == "middle" )
01308        {
01309 //            m_Doc->m_Selection->clear();
01310               tmpSel->clear();
01311 //            m_Doc->m_Selection->addItem(ite, true);
01312               tmpSel->addItem(ite, true);
01313 //            m_Doc->itemSelection_SetAlignment(1);
01314               m_Doc->itemSelection_SetAlignment(1, tmpSel);
01315               xoffset = -ite->width() / 2;
01316        }
01317        else if( gc->textAnchor == "end")
01318        {
01319 //            m_Doc->m_Selection->clear();
01320               tmpSel->clear();
01321 //            m_Doc->m_Selection->addItem(ite, true);
01322               tmpSel->addItem(ite, true);
01323 //            m_Doc->itemSelection_SetAlignment(2);
01324               m_Doc->itemSelection_SetAlignment(2, tmpSel);
01325               xoffset = -ite->width();
01326        }
01327        double rotation = getRotationFromMatrix(gc->matrix, 0.0);
01328        if (rotation != 0.0)
01329        {
01330               double temp = xoffset;
01331               xoffset = cos(-rotation) * temp;
01332               yoffset = sin(-rotation) * temp;
01333        }
01334        ite->setXPos(xpos + xoffset);
01335        ite->setYPos(ypos + yoffset);
01336        ite->setRotation(-rotation * 180 / M_PI);
01337        ite->SetRectFrame();
01338        m_Doc->setRedrawBounding(ite);
01339        ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
01340 //     m_Doc->m_Selection->addItem(ite);
01341        tmpSel->addItem(ite);
01342        m_Doc->view()->frameResizeHandle = 1;
01343 //     m_Doc->m_Selection->setGroupRect();
01344        tmpSel->setGroupRect();
01345 //     m_Doc->view()->scaleGroup(scalex, scaley);
01346        m_Doc->view()->scaleGroup(scalex, scaley, true, tmpSel);
01347        // scaleGroup scale may modify position... weird...
01348        ite->setXYPos(xpos + xoffset, ypos + yoffset);
01349        tmpSel->clear();
01350 //     m_Doc->view()->Deselect();
01351        // Probably some scalex and scaley to add somewhere
01352        ite->moveBy(maxHeight * sin(-rotation) * scaley, -maxHeight * cos(-rotation) * scaley);
01353        if( !e.attribute("id").isEmpty() )
01354               ite->setItemName(" "+e.attribute("id"));
01355        ite->setFillTransparency( 1 - gc->FillOpacity * gc->Opacity);
01356        ite->setLineTransparency( 1 - gc->StrokeOpacity * gc->Opacity);
01357        ite->PLineEnd = gc->PLineEnd;
01358        ite->PLineJoin = gc->PLineJoin;
01359        //ite->setTextFlowsAroundFrame(false);
01360        ite->setTextFlowMode(PageItem::TextFlowDisabled);
01361        ite->DashOffset = gc->dashOffset;
01362        ite->DashValues = gc->dashArray;
01363        /*                   if (gc->Gradient != 0)
01364                             {
01365                                    ite->fill_gradient = gc->GradCo;
01366                                    m_Doc->view()->SelItem.append(ite);
01367                                    m_Doc->view()->ItemGradFill(gc->Gradient, gc->GCol2, 100, gc->GCol1, 100);
01368                                    m_Doc->view()->SelItem.clear();
01369                             } */
01370        GElements.append(ite);
01371        return GElements;
01372 }
01373 
01374 QPtrList<PageItem> SVGPlug::parseSwitch(const QDomElement &e)
01375 {
01376        QString href;
01377        QStringList hrefs;
01378        QPtrList<PageItem> SElements;
01379        for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
01380        {
01381               QDomElement de = n.toElement();
01382               QString STag = de.tagName();
01383               if (STag == "foreignObject")
01384               {
01385                      if (de.hasAttribute("xlink:href"))
01386                      {
01387                             href = de.attribute("xlink:href").mid(1);
01388                             if (!href.isEmpty())
01389                                    hrefs.append(href);
01390                      }
01391                      for (QDomNode n1 = de.firstChild(); !n1.isNull(); n1 = n1.nextSibling())
01392                      {
01393                             QDomElement de1 = n1.toElement();
01394                             if (de1.hasAttribute("xlink:href"))
01395                             {
01396                                    href = de1.attribute("xlink:href").mid(1);
01397                                    if (!href.isEmpty())
01398                                           hrefs.append(href);
01399                             }
01400                      }
01401               }
01402               else 
01403               {
01404                      if (de.hasAttribute("requiredExtensions") || de.hasAttribute("requiredFeatures"))
01405                             continue;
01406                      else if (de.hasAttribute("id") && hrefs.contains(de.attribute("id")))
01407                             continue;
01408                      else
01409                      {
01410                             SElements = parseElement(de);
01411                             if (SElements.count() > 0)
01412                                    break;
01413                      }
01414               }
01415        }
01416        return SElements;
01417 }
01418 
01419 QPtrList<PageItem> SVGPlug::parseSymbol(const QDomElement &e)
01420 {
01421        QPtrList<PageItem> SElements;
01422        QString id = e.attribute(id);
01423        if( !id.isEmpty() )
01424               m_nodeMap.insert(id, e);
01425        return SElements;
01426 }
01427 
01428 QPtrList<PageItem> SVGPlug::parseUse(const QDomElement &e)
01429 {
01430        QPtrList<PageItem> UElements;
01431        QDomElement ue = getNodeFromUseElement(e);
01432        if (!ue.isNull())
01433               UElements = parseElement(ue);
01434        return UElements;
01435 }
01436 
01437 QDomElement SVGPlug::getNodeFromUseElement(const QDomElement &e)
01438 {
01439        QDomElement ret;
01440        QMap<QString, QDomElement>::Iterator it;
01441        QString href = e.attribute("xlink:href").mid(1);
01442        it = m_nodeMap.find(href);
01443        if (it != m_nodeMap.end())
01444        {
01445               // Transform use element to group
01446               ret = e.cloneNode().toElement();
01447               ret.setTagName("g");
01448               if( ret.hasAttribute("x") || ret.hasAttribute("y") )
01449               {
01450                      QString xAtt  = ret.attribute("x", "0.0");
01451                      QString yAtt  = ret.attribute("y", "0.0");
01452                      QString trans = ret.attribute("transform", "");
01453                      trans += QString(" translate(%1, %2)").arg(xAtt).arg(yAtt);
01454                      ret.setAttribute("transform", trans);
01455               }
01456               ret.removeAttribute("x");
01457               ret.removeAttribute("y");
01458               ret.removeAttribute("width");
01459               ret.removeAttribute("height");
01460               ret.removeAttribute("xlink:href");
01461               QDomNode clone = it.data().cloneNode();
01462               QDomElement cloneElm = clone.toElement();
01463               if( cloneElm.tagName() == "symbol" )
01464                      cloneElm.setTagName("g"); // later fix to be svg
01465               ret.appendChild(cloneElm);
01466        }
01467        return ret;
01468 }
01469 
01470 QDomElement SVGPlug::getReferencedNode(const QDomElement &e)
01471 {
01472        QDomElement ret;
01473        QMap<QString, QDomElement>::Iterator it;
01474        QString href = e.attribute("xlink:href").mid(1);
01475        it = m_nodeMap.find(href);
01476        if (it != m_nodeMap.end())
01477               ret = it.data().cloneNode().toElement();
01478        return ret;
01479 }
01480 
01481 double SVGPlug::fromPercentage( const QString &s )
01482 {
01483        if (s.endsWith( "%" ))
01484        {
01485               QString s1 = s.left(s.length() - 1);
01486               return s1.toDouble() / 100.0;
01487        }
01488        else
01489               return s.toDouble();
01490 }
01491 
01492 double SVGPlug::parseUnit(const QString &unit)
01493 {
01494        bool noUnit = false;
01495        QString unitval=unit;
01496        if( unit.right( 2 ) == "pt" )
01497               unitval.replace( "pt", "" );
01498        else if( unit.right( 2 ) == "cm" )
01499               unitval.replace( "cm", "" );
01500        else if( unit.right( 2 ) == "mm" )
01501               unitval.replace( "mm" , "" );
01502        else if( unit.right( 2 ) == "in" )
01503               unitval.replace( "in", "" );
01504        else if( unit.right( 2 ) == "px" )
01505               unitval.replace( "px", "" );
01506        if (unitval == unit)
01507               noUnit = true;
01508        double value = unitval.toDouble();
01509        if( unit.right( 2 ) == "pt" )
01510               value = value;
01511        else if( unit.right( 2 ) == "cm" )
01512               value = ( value / 2.54 ) * 72;
01513        else if( unit.right( 2 ) == "mm" )
01514               value = ( value / 25.4 ) * 72;
01515        else if( unit.right( 2 ) == "in" )
01516               value = value * 72;
01517        else if( unit.right( 2 ) == "px" )
01518               value = value * 0.8;
01519        else if(noUnit)
01520               value = value;
01521        return value;
01522 }
01523 
01524 QWMatrix SVGPlug::parseTransform( const QString &transform )
01525 {
01526        QWMatrix ret;
01527        // Split string for handling 1 transform statement at a time
01528        QStringList subtransforms = QStringList::split(')', transform);
01529        QStringList::ConstIterator it = subtransforms.begin();
01530        QStringList::ConstIterator end = subtransforms.end();
01531        for(; it != end; ++it)
01532        {
01533               QWMatrix result;
01534               QStringList subtransform = QStringList::split('(', (*it));
01535               subtransform[0] = subtransform[0].stripWhiteSpace().lower();
01536               subtransform[1] = subtransform[1].simplifyWhiteSpace();
01537               QRegExp reg("[,( ]");
01538               QStringList params = QStringList::split(reg, subtransform[1]);
01539               if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
01540                      subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
01541               if(subtransform[0] == "rotate")
01542               {
01543                      if(params.count() == 3)
01544                      {
01545                             double x = params[1].toDouble();
01546                             double y = params[2].toDouble();
01547                             result.translate(x, y);
01548                             result.rotate(params[0].toDouble());
01549                             result.translate(-x, -y);
01550                      }
01551                      else
01552                             result.rotate(params[0].toDouble());
01553               }
01554               else if(subtransform[0] == "translate")
01555               {
01556                      if(params.count() == 2)
01557                             result.translate(params[0].toDouble(), params[1].toDouble());
01558                      else    // Spec : if only one param given, assume 2nd param to be 0
01559                             result.translate(params[0].toDouble(), 0);
01560               }
01561               else if(subtransform[0] == "scale")
01562               {
01563                      if(params.count() == 2)
01564                             result.scale(params[0].toDouble(), params[1].toDouble());
01565                      else    // Spec : if only one param given, assume uniform scaling
01566                             result.scale(params[0].toDouble(), params[0].toDouble());
01567               }
01568               else if(subtransform[0] == "skewx")
01569                      result.shear(tan(params[0].toDouble() * 0.01745329251994329576), 0.0F);
01570               else if(subtransform[0] == "skewy")
01571                      result.shear(0.0F, tan(params[0].toDouble() * 0.01745329251994329576));
01572               else if(subtransform[0] == "matrix")
01573               {
01574                      if(params.count() >= 6)
01575                      {
01576                             double sx = params[0].toDouble();
01577                             double sy = params[3].toDouble();
01578                             result.setMatrix(sx, params[1].toDouble(), params[2].toDouble(), sy, params[4].toDouble(), params[5].toDouble());
01579                      }
01580               }
01581               ret = result * ret;
01582        }
01583        return ret;
01584 }
01585 
01586 const char * SVGPlug::getCoord( const char *ptr, double &number )
01587 {
01588        int integer, exponent;
01589        double decimal, frac;
01590        int sign, expsign;
01591 
01592        exponent = 0;
01593        integer = 0;
01594        frac = 1.0;
01595        decimal = 0;
01596        sign = 1;
01597        expsign = 1;
01598 
01599        // read the sign
01600        if(*ptr == '+')
01601               ptr++;
01602        else if(*ptr == '-')
01603        {
01604               ptr++;
01605               sign = -1;
01606        }
01607 
01608        // read the integer part
01609        while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
01610               integer = (integer * 10) + *(ptr++) - '0';
01611        if(*ptr == '.') // read the decimals
01612        {
01613               ptr++;
01614               while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
01615                      decimal += (*(ptr++) - '0') * (frac *= 0.1);
01616        }
01617 
01618        if(*ptr == 'e' || *ptr == 'E') // read the exponent part
01619        {
01620               ptr++;
01621 
01622               // read the sign of the exponent
01623               if(*ptr == '+')
01624                      ptr++;
01625               else if(*ptr == '-')
01626               {
01627                      ptr++;
01628                      expsign = -1;
01629               }
01630 
01631               exponent = 0;
01632               while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
01633               {
01634                      exponent *= 10;
01635                      exponent += *ptr - '0';
01636                      ptr++;
01637               }
01638        }
01639        number = integer + decimal;
01640        number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
01641        // skip the following space
01642        if(*ptr == ' ')
01643               ptr++;
01644 
01645        return ptr;
01646 }
01647 
01648 bool SVGPlug::parseSVG( const QString &s, FPointArray *ite )
01649 {
01650        return ite->parseSVG(s);
01651 }
01652 
01653 
01654 QColor SVGPlug::parseColorN( const QString &rgbColor )
01655 {
01656        int r, g, b;
01657        keywordToRGB( rgbColor.lower(), r, g, b );
01658        return QColor( r, g, b );
01659 }
01660 
01661 
01662 QString SVGPlug::parseColor( const QString &s )
01663 {
01664        QColor c;
01665        QString ret = CommonStrings::None;
01666        if( s.startsWith( "rgb(" ) )
01667        {
01668               QString parse = s.stripWhiteSpace();
01669               QStringList colors = QStringList::split( ',', parse );
01670               QString r = colors[0].right( ( colors[0].length() - 4 ) );
01671               QString g = colors[1];
01672               QString b = colors[2].left( ( colors[2].length() - 1 ) );
01673               if( r.contains( "%" ) )
01674               {
01675                      r = r.left( r.length() - 1 );
01676                      r = QString::number( static_cast<int>( ( static_cast<double>( 255 * r.toDouble() ) / 100.0 ) ) );
01677               }
01678               if( g.contains( "%" ) )
01679               {
01680                      g = g.left( g.length() - 1 );
01681                      g = QString::number( static_cast<int>( ( static_cast<double>( 255 * g.toDouble() ) / 100.0 ) ) );
01682               }
01683               if( b.contains( "%" ) )
01684               {
01685                      b = b.left( b.length() - 1 );
01686                      b = QString::number( static_cast<int>( ( static_cast<double>( 255 * b.toDouble() ) / 100.0 ) ) );
01687               }
01688               c = QColor(r.toInt(), g.toInt(), b.toInt());
01689        }
01690        else
01691        {
01692               QString rgbColor = s.stripWhiteSpace();
01693               if( rgbColor.startsWith( "#" ) )
01694                      c.setNamedColor( rgbColor );
01695               else
01696                      c = parseColorN( rgbColor );
01697        }
01698        ColorList::Iterator it;
01699        bool found = false;
01700        int r, g, b;
01701        QColor tmpR;
01702        for (it = m_Doc->PageColors.begin(); it != m_Doc->PageColors.end(); ++it)
01703        {
01704               if (it.data().getColorModel() == colorModelRGB)
01705               {
01706                      it.data().getRGB(&r, &g, &b);
01707                      tmpR.setRgb(r, g, b);
01708                      if (c == tmpR)
01709                      {
01710                             ret = it.key();
01711                             found = true;
01712                      }
01713               }
01714        }
01715        if (!found)
01716        {
01717               ScColor tmp;
01718               tmp.fromQColor(c);
01719               tmp.setSpotColor(false);
01720               tmp.setRegistrationColor(false);
01721               m_Doc->PageColors.insert("FromSVG"+c.name(), tmp);
01722               importedColors.append("FromSVG"+c.name());
01723               ret = "FromSVG"+c.name();
01724        }
01725        return ret;
01726 }
01727 
01728 void SVGPlug::parsePA( SvgStyle *obj, const QString &command, const QString &params )
01729 {
01730        if( command == "display" )
01731               obj->Display = (params == "none") ? false : true;
01732        else if( command == "stroke-opacity" )
01733               obj->StrokeOpacity  = fromPercentage(params);
01734        else if( command == "fill-opacity" )
01735               obj->FillOpacity = fromPercentage(params);
01736        else if( command == "opacity" )
01737               obj->Opacity = fromPercentage(params);
01738        else if( command == "fill" )
01739        {
01740 //            if ((obj->InherCol) && (params == "currentColor"))
01741               if (params == "currentColor")
01742                      obj->FillCol = obj->CurCol;
01743               else if (params == "none")
01744               {
01745                      obj->FillCol = CommonStrings::None;
01746               }
01747               else if( params.startsWith( "url(" ) )
01748               {
01749                      unsigned int start = params.find("#") + 1;
01750                      unsigned int end = params.findRev(")");
01751                      QString key = params.mid(start, end - start);
01752                      while (!m_gradients[key].reference.isEmpty())
01753                      {
01754                             QString key2 = m_gradients[key].reference;
01755                             if (m_gradients[key2].typeValid)
01756                                    obj->Gradient = m_gradients[key2].Type;
01757                             if (m_gradients[key2].gradientValid)
01758                                    obj->GradCo = m_gradients[key2].gradient;
01759                             if (m_gradients[key2].cspaceValid)
01760                                    obj->CSpace = m_gradients[key2].CSpace;
01761                             if (m_gradients[key2].x1Valid)
01762                                    obj->GX1 = m_gradients[key2].X1;
01763                             if (m_gradients[key2].y1Valid)
01764                                    obj->GY1 = m_gradients[key2].Y1;
01765                             if (m_gradients[key2].x2Valid)
01766                                    obj->GX2 = m_gradients[key2].X2;
01767                             if (m_gradients[key2].y2Valid)
01768                                    obj->GY2 = m_gradients[key2].Y2;
01769                             if (m_gradients[key2].matrixValid)
01770                                    obj->matrixg = m_gradients[key2].matrix;
01771                             key = m_gradients[key].reference;
01772                      }
01773                      key = params.mid(start, end - start);
01774                      if (m_gradients[key].typeValid)
01775                             obj->Gradient = m_gradients[key].Type;
01776                      if (m_gradients[key].gradientValid)
01777                             obj->GradCo = m_gradients[key].gradient;
01778                      if (m_gradients[key].cspaceValid)
01779                             obj->CSpace = m_gradients[key].CSpace;
01780                      if (m_gradients[key].x1Valid)
01781                             obj->GX1 = m_gradients[key].X1;
01782                      if (m_gradients[key].y1Valid)
01783                             obj->GY1 = m_gradients[key].Y1;
01784                      if (m_gradients[key].x2Valid)
01785                             obj->GX2 = m_gradients[key].X2;
01786                      if (m_gradients[key].y2Valid)
01787                             obj->GY2 = m_gradients[key].Y2;
01788                      if (m_gradients[key].matrixValid)
01789                             obj->matrixg = m_gradients[key].matrix;
01790                      obj->FillCol = CommonStrings::None;
01791               }
01792               else
01793                      obj->FillCol = parseColor(params);
01794        }
01795        else if( command == "fill-rule" )
01796        {
01797               obj->fillRule = params;
01798        }
01799        else if( command == "color" )
01800        {
01801               if (params == "none")
01802                      obj->CurCol = CommonStrings::None;
01803               else if( params.startsWith( "url(" ) )
01804                      obj->CurCol = CommonStrings::None;
01805               else if (params == "currentColor")
01806                      obj->CurCol = obj->CurCol;
01807               else
01808                      obj->CurCol = parseColor(params);
01809        }
01810        else if( command == "stroke" )
01811        {
01812 //            if ((obj->InherCol) && (params == "currentColor"))
01813               if (params == "currentColor")
01814                      obj->StrokeCol = obj->CurCol;
01815               else if (params == "none")
01816               {
01817                      obj->StrokeCol = CommonStrings::None;
01818               }
01819               else if( params.startsWith( "url(" ) )
01820               {
01821                      obj->StrokeCol = CommonStrings::None;
01822               }
01823               else
01824                      obj->StrokeCol = parseColor(params);
01825               /*            if( params == "none" )
01826                                    gc->stroke.setType( VStroke::none );
01827                             else if( params.startsWith( "url(" ) )
01828                             {
01829                                    unsigned int start = params.find("#") + 1;
01830                                    unsigned int end = params.findRev(")");
01831                                    QString key = params.mid( start, end - start );
01832                                    gc->stroke.gradient() = m_gradients[ key ].gradient;
01833                                    gc->stroke.gradient().transform( m_gradients[ key ].gradientTransform );
01834                                    gc->stroke.gradient().transform( gc->matrix );
01835                                    gc->stroke.setType( VStroke::grad );
01836                             }
01837                             else
01838                             {
01839                                    parseColor( strokecolor, params );
01840                                    gc->stroke.setType( VStroke::solid );
01841                             } */
01842        }
01843        else if( command == "stroke-width" )
01844               obj->LWidth = parseUnit( params );
01845        else if( command == "stroke-linejoin" )
01846        {
01847               if( params == "miter" )
01848                      obj->PLineJoin = Qt::MiterJoin;
01849               else if( params == "round" )
01850                      obj->PLineJoin = Qt::RoundJoin;
01851               else if( params == "bevel" )
01852                      obj->PLineJoin = Qt::BevelJoin;
01853        }
01854        else if( command == "stroke-linecap" )
01855        {
01856               if( params == "butt" )
01857                      obj->PLineEnd = Qt::FlatCap;
01858               else if( params == "round" )
01859                      obj->PLineEnd = Qt::RoundCap;
01860               else if( params == "square" )
01861                      obj->PLineEnd = Qt::SquareCap;
01862        }
01863        //     else if( command == "stroke-miterlimit" )
01864        //            gc->stroke.setMiterLimit( params.todouble() );
01865        else if( command == "stroke-dasharray" )
01866        {
01867               QValueList<double> array;
01868               if(params != "none")
01869               {
01870                      QString params2 = params.simplifyWhiteSpace().replace(',', " ");
01871                      QStringList dashes = QStringList::split( ' ', params2 );
01872                      for( QStringList::Iterator it = dashes.begin(); it != dashes.end(); ++it )
01873                             array.append( (*it).toDouble() );
01874               }
01875               obj->dashArray = array;
01876        }
01877        else if( command == "stroke-dashoffset" )
01878               obj->dashOffset = params.toDouble();
01879        else if( command == "font-family" )
01880        {
01881               QString family = params;
01882               QString ret = "";
01883               family.replace( QRegExp( "'" ) , QChar( ' ' ) );
01884               obj->Family = m_Doc->toolSettings.defFont; // family;
01885               bool found = false;
01886               SCFontsIterator it(PrefsManager::instance()->appPrefs.AvailFonts);
01887               for ( ; it.hasNext(); it.next())
01888               {
01889                      QString fam;
01890                      QString fn = it.current().scName();
01891                      int    pos=fn.find(" ");
01892                      fam = fn.left(pos);
01893                      if (fam == family)
01894                      {
01895                             found = true;
01896                             ret = fn;
01897                      }
01898               }
01899               if (found)
01900                      obj->Family = ret;
01901               else
01902                      obj->Family = m_Doc->toolSettings.defFont;
01903        }
01904        else if( command == "font-size" )
01905               obj->FontSize = static_cast<int>(parseUnit(params) * 10.0);
01906        else if( command == "text-anchor" )
01907               obj->textAnchor = params;
01908        else
01909               unsupported = true;
01910 }
01911 
01912 void SVGPlug::parseStyle( SvgStyle *obj, const QDomElement &e )
01913 {
01914        SvgStyle *gc = m_gc.current();
01915        if (!gc)
01916               return;
01917        if( !e.attribute( "display" ).isEmpty() )
01918               parsePA( obj, "display", e.attribute( "display" ) );
01919        if( !e.attribute( "color" ).isEmpty() )
01920        {
01921               if (e.attribute( "color" ) == "inherit")
01922                      gc->InherCol = true;
01923               else
01924                      parsePA( obj, "color", e.attribute( "color" ) );
01925        }
01926        if( !e.attribute( "fill" ).isEmpty() )
01927               parsePA( obj, "fill", e.attribute( "fill" ) );
01928        if( !e.attribute( "stroke" ).isEmpty() )
01929               parsePA( obj, "stroke", e.attribute( "stroke" ) );
01930        if( !e.attribute( "stroke-width" ).isEmpty() )
01931               parsePA( obj, "stroke-width", e.attribute( "stroke-width" ) );
01932        if( !e.attribute( "stroke-linejoin" ).isEmpty() )
01933               parsePA( obj, "stroke-linejoin", e.attribute( "stroke-linejoin" ) );
01934        if( !e.attribute( "stroke-linecap" ).isEmpty() )
01935               parsePA( obj, "stroke-linecap", e.attribute( "stroke-linecap" ) );
01936        if( !e.attribute( "stroke-dasharray" ).isEmpty() )
01937               parsePA( obj, "stroke-dasharray", e.attribute( "stroke-dasharray" ) );
01938        if( !e.attribute( "stroke-dashoffset" ).isEmpty() )
01939               parsePA( obj, "stroke-dashoffset", e.attribute( "stroke-dashoffset" ) );
01940        if( !e.attribute( "stroke-opacity" ).isEmpty() )
01941               parsePA( obj, "stroke-opacity", e.attribute( "stroke-opacity" ) );
01942        /*     if( !e.attribute( "stroke-miterlimit" ).isEmpty() )
01943                      parsePA( obj, "stroke-miterlimit", e.attribute( "stroke-miterlimit" ) );   */
01944        if( !e.attribute( "fill-rule" ).isEmpty() )
01945               parsePA( obj, "fill-rule", e.attribute( "fill-rule" ) );
01946        if( !e.attribute( "fill-opacity" ).isEmpty() )
01947               parsePA( obj, "fill-opacity", e.attribute( "fill-opacity" ) );
01948        if( !e.attribute( "opacity" ).isEmpty() )
01949               parsePA( obj, "opacity", e.attribute( "opacity" ) );
01950        if( !e.attribute( "font-family" ).isEmpty() )
01951               parsePA( obj, "font-family", e.attribute( "font-family" ) );
01952        if( !e.attribute( "font-size" ).isEmpty() )
01953               parsePA( obj, "font-size", e.attribute( "font-size" ) );
01954        if( !e.attribute( "text-anchor" ).isEmpty() )
01955               parsePA( obj, "text-anchor", e.attribute( "text-anchor" ) );
01956        QString style = e.attribute( "style" ).simplifyWhiteSpace();
01957        QStringList substyles = QStringList::split( ';', style );
01958        for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
01959        {
01960               QStringList substyle = QStringList::split( ':', (*it) );
01961               QString command      = substyle[0].stripWhiteSpace();
01962               QString params       = substyle[1].stripWhiteSpace();
01963               parsePA( obj, command, params );
01964        }
01965        return;
01966 }
01967 
01968 void SVGPlug::parseColorStops(GradientHelper *gradient, const QDomElement &e)
01969 {
01970        QString Col = "Black";
01971        double offset = 0;
01972        double opa;
01973        SvgStyle svgStyle;
01974        parseStyle( &svgStyle, e );
01975        for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
01976        {
01977               opa = 1.0;
01978               QDomElement stop = n.toElement();
01979               if(stop.tagName() == "stop")
01980               {
01981                      QString temp = stop.attribute( "offset" );
01982                      if( temp.contains( '%' ) )
01983                      {
01984                             temp = temp.left( temp.length() - 1 );
01985                             offset = temp.toDouble() / 100.0;
01986                      }
01987                      else
01988                             offset = temp.toDouble();
01989                      if( !stop.attribute( "stop-opacity" ).isEmpty() )
01990                             opa = fromPercentage(stop.attribute("stop-opacity"));
01991                      if( !stop.attribute( "stop-color" ).isEmpty() )
01992                      {
01993                             if (stop.attribute("stop-color") == "currentColor")
01994                                    Col = svgStyle.CurCol;
01995                             else
01996                                    Col = parseColor(stop.attribute("stop-color"));
01997                      }
01998                      else
01999                      {
02000                             QString style = stop.attribute( "style" ).simplifyWhiteSpace();
02001                             QStringList substyles = QStringList::split( ';', style );
02002                             for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
02003                             {
02004                                    QStringList substyle = QStringList::split( ':', (*it) );
02005                                    QString command      = substyle[0].stripWhiteSpace();
02006                                    QString params       = substyle[1].stripWhiteSpace();
02007                                    if( command == "stop-color" )
02008                                           Col = parseColor(params);
02009                                    if( command == "stop-opacity" )
02010                                           opa = fromPercentage(params);
02011                             }
02012                      }
02013               }
02014               const ScColor& gradC = m_Doc->PageColors[Col];
02015               gradient->gradient.addStop( ScColorEngine::getRGBColor(gradC, m_Doc), offset, 0.5, opa, Col, 100 );
02016               gradient->gradientValid = true;
02017        }
02018        if (gradient->gradientValid)
02019               gradient->gradient.filterStops();
02020 }
02021 
02022 void SVGPlug::parseGradient( const QDomElement &e )
02023 {
02024        GradientHelper gradhelper;
02025        gradhelper.gradientValid = false;
02026        gradhelper.gradient.clearStops();
02027        gradhelper.gradient.setRepeatMethod( VGradient::none );
02028 
02029        QString href = e.attribute("xlink:href").mid(1);
02030        double x1=0, y1=0, x2=0, y2=0;
02031        if (!href.isEmpty())
02032        {
02033               if (m_gradients.contains(href))
02034               {
02035                      gradhelper.Type = m_gradients[href].Type;
02036                      gradhelper.gradient = m_gradients[href].gradient;
02037                      gradhelper.X1 = m_gradients[href].X1;
02038                      gradhelper.Y1 = m_gradients[href].Y1;
02039                      gradhelper.X2 = m_gradients[href].X2;
02040                      gradhelper.Y2 = m_gradients[href].Y2;
02041                      gradhelper.CSpace = m_gradients[href].CSpace;
02042                      gradhelper.matrix = m_gradients[href].matrix;
02043                      gradhelper.x1Valid = m_gradients[href].x1Valid;
02044                      gradhelper.x2Valid = m_gradients[href].x2Valid;
02045                      gradhelper.y1Valid = m_gradients[href].y1Valid;
02046                      gradhelper.y2Valid = m_gradients[href].y2Valid;
02047                      gradhelper.cspaceValid = m_gradients[href].cspaceValid;
02048                      gradhelper.matrixValid = m_gradients[href].matrixValid;
02049                      gradhelper.gradientValid = m_gradients[href].gradientValid;
02050                      gradhelper.typeValid = m_gradients[href].typeValid;
02051               }
02052               gradhelper.reference = href;
02053        }
02054        if (e.tagName() == "linearGradient")
02055        {
02056               if (e.hasAttribute("x1"))
02057               {
02058                      gradhelper.X1 = parseUnit(e.attribute("x1", "0"));
02059                      gradhelper.x1Valid = true;
02060               }
02061               if (e.hasAttribute("y1"))
02062               {
02063                      gradhelper.Y1 = parseUnit(e.attribute("y1", "0"));
02064                      gradhelper.y1Valid = true;
02065               }
02066               if (e.hasAttribute("x2"))
02067               {
02068                      gradhelper.X2 = parseUnit(e.attribute("x2", "1"));
02069                      gradhelper.x2Valid = true;
02070               }
02071               if (e.hasAttribute("y2"))
02072               {
02073                      gradhelper.Y2 = parseUnit(e.attribute("y2", "0"));
02074                      gradhelper.y2Valid = true;
02075               }
02076               gradhelper.Type = 6;
02077               gradhelper.typeValid = true;
02078        }
02079        else
02080        {
02081               if (e.hasAttribute("cx"))
02082               {
02083                      x1 = parseUnit(e.attribute("cx","0.5"));
02084                      gradhelper.x1Valid = true;
02085               }
02086               if (e.hasAttribute("cy"))
02087               {
02088                      y1 = parseUnit(e.attribute("cy", "0.5"));
02089                      gradhelper.y1Valid = true;
02090               }
02091               if (e.hasAttribute("r"))
02092               {
02093                      x2 = parseUnit(e.attribute("r", "0.5"));
02094                      gradhelper.x2Valid = true;
02095               }
02096               y2 = y1;
02097               gradhelper.y2Valid = true;
02098               gradhelper.X1 = x1;
02099               gradhelper.Y1 = y1;
02100               gradhelper.X2 = x1 + x2;
02101               gradhelper.Y2 = y1;
02102               gradhelper.Type = 7;
02103               gradhelper.typeValid = true;
02104        }
02105        if ( !e.attribute( "gradientUnits" ).isEmpty() )
02106        {
02107               QString uni = e.attribute( "gradientUnits");
02108               if (uni == "userSpaceOnUse")
02109                      gradhelper.CSpace = true;
02110               else
02111                      gradhelper.CSpace = false;
02112               gradhelper.cspaceValid = true;
02113        }
02114        else
02115        {
02116               gradhelper.CSpace = false;
02117               gradhelper.cspaceValid = false;
02118        }
02119        QString transf = e.attribute("gradientTransform");
02120        if( !transf.isEmpty() )
02121        {
02122               gradhelper.matrix = parseTransform( e.attribute("gradientTransform") );
02123               gradhelper.matrixValid = true;
02124        }
02125        else
02126               gradhelper.matrixValid = false;
02127        QString spreadMethod = e.attribute( "spreadMethod" );
02128        if( !spreadMethod.isEmpty() )
02129        {
02130               if( spreadMethod == "reflect" )
02131                      gradhelper.gradient.setRepeatMethod( VGradient::reflect );
02132               else if( spreadMethod == "repeat" )
02133                      gradhelper.gradient.setRepeatMethod( VGradient::repeat );
02134        }
02135        parseColorStops(&gradhelper, e);
02136        m_gradients.insert(e.attribute("id"), gradhelper);
02137 }
02138 
02139 SVGPlug::~SVGPlug()
02140 {
02141        delete tmpSel;
02142 }