summaryrefslogtreecommitdiffstats
path: root/ksvg/core
diff options
context:
space:
mode:
Diffstat (limited to 'ksvg/core')
-rw-r--r--ksvg/core/CanvasFactory.cpp176
-rw-r--r--ksvg/core/CanvasFactory.h69
-rw-r--r--ksvg/core/CanvasItem.h154
-rw-r--r--ksvg/core/CanvasItems.cpp509
-rw-r--r--ksvg/core/CanvasItems.h133
-rw-r--r--ksvg/core/DocumentFactory.cpp110
-rw-r--r--ksvg/core/DocumentFactory.h63
-rw-r--r--ksvg/core/KSVGCanvas.cpp786
-rw-r--r--ksvg/core/KSVGCanvas.h190
-rw-r--r--ksvg/core/KSVGHelper.cpp92
-rw-r--r--ksvg/core/KSVGHelper.h144
-rw-r--r--ksvg/core/KSVGLoader.cpp449
-rw-r--r--ksvg/core/KSVGLoader.h92
-rw-r--r--ksvg/core/KSVGReader.cc500
-rw-r--r--ksvg/core/KSVGReader.h67
-rw-r--r--ksvg/core/KSVGTextChunk.cpp69
-rw-r--r--ksvg/core/KSVGTextChunk.h54
-rw-r--r--ksvg/core/Makefile.am16
-rw-r--r--ksvg/core/ksvgrenderer.desktop56
19 files changed, 3729 insertions, 0 deletions
diff --git a/ksvg/core/CanvasFactory.cpp b/ksvg/core/CanvasFactory.cpp
new file mode 100644
index 00000000..ca2822b2
--- /dev/null
+++ b/ksvg/core/CanvasFactory.cpp
@@ -0,0 +1,176 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <ksimpleconfig.h>
+#include <kparts/componentfactory.h>
+
+#include "KSVGCanvas.h"
+#include "CanvasFactory.h"
+
+using namespace KSVG;
+
+CanvasFactory *CanvasFactory::s_factory = 0;
+
+CanvasFactory::CanvasFactory()
+{
+ m_canvasList.setAutoDelete(true);
+}
+
+CanvasFactory::~CanvasFactory()
+{
+}
+
+CanvasFactory *CanvasFactory::self()
+{
+ if(!s_factory)
+ s_factory = new CanvasFactory();
+
+ return s_factory;
+}
+
+void CanvasFactory::cleanup()
+{
+ m_canvasList.clear();
+}
+
+void CanvasFactory::queryCanvas()
+{
+ m_canvasList.clear();
+
+ QValueList<KService::Ptr> traderList = KTrader::self()->query("KSVG/Renderer", "(Type == 'Service')");
+ KTrader::OfferList::Iterator it(traderList.begin());
+ for( ; it != traderList.end(); ++it)
+ {
+ KService::Ptr ptr = (*it);
+
+ QString name = ptr->property("Name").toString();
+ QString internal = ptr->property("X-KSVG-InternalName").toString();
+ if(name.isEmpty() || internal.isEmpty())
+ continue;
+
+ CanvasInfo *cinfo = new CanvasInfo();
+ cinfo->service = ptr;
+ cinfo->canvas = 0;
+ cinfo->name = name;
+ cinfo->internal = internal;
+
+ m_canvasList.append(cinfo);
+ }
+
+ if(m_canvasList.isEmpty())
+ {
+ kdError(26001) << "Couldn't load any canvas!!! FATAL ERROR." << endl;
+ return;
+ }
+}
+
+KSVGCanvas *CanvasFactory::loadCanvas(int width, int height)
+{
+ queryCanvas();
+
+ KSimpleConfig *config = new KSimpleConfig("ksvgpluginrc", false);
+ config->setGroup("Canvas");
+ QString load = config->readEntry("ActiveCanvas", "libart");
+ delete config;
+
+ QPtrListIterator<CanvasInfo> it(m_canvasList);
+ CanvasInfo *info = it.current();
+ while((info = it.current()) != 0)
+ {
+ if(info->internal == load)
+ {
+ QStringList args;
+ args.prepend(QString::number(width));
+ args.prepend(QString::number(height));
+
+ info->canvas = KParts::ComponentFactory::createInstanceFromLibrary<KSVGCanvas>(QFile::encodeName(info->service->library()), 0, 0, args);
+
+ if(info->canvas)
+ return info->canvas;
+ else
+ {
+ kdError(26001) << "Failed to load canvas: " << load << " FATAL ERROR." << endl;
+ break;
+ }
+ }
+
+ ++it;
+ }
+
+ return 0;
+}
+
+int CanvasFactory::itemInList(KSVGCanvas *canvas)
+{
+ QPtrListIterator<CanvasInfo> it(m_canvasList);
+ CanvasInfo *info = it.current();
+ unsigned int i = 0;
+ while((info = it.current()) != 0)
+ {
+ if(info->canvas == canvas)
+ return i;
+
+ i++;
+ ++it;
+ }
+
+ return 0;
+}
+
+QString CanvasFactory::internalNameFor(const QString &name)
+{
+ QPtrListIterator<CanvasInfo> it(m_canvasList);
+ CanvasInfo *info = it.current();
+ while((info = it.current()) != 0)
+ {
+ if(info->name == name)
+ return info->internal;
+
+ ++it;
+ }
+
+ return QString::null;
+}
+
+void CanvasFactory::deleteCanvas(KSVGCanvas *canvas)
+{
+ QPtrListIterator<CanvasInfo> it(m_canvasList);
+ CanvasInfo *info = it.current();
+ while((info = it.current()) != 0)
+ {
+ if(info->canvas == canvas)
+ {
+ delete info->canvas;
+ info->canvas = 0;
+ }
+
+ ++it;
+ }
+}
+
+QPtrList<CanvasInfo> CanvasFactory::canvasList()
+{
+ return m_canvasList;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/CanvasFactory.h b/ksvg/core/CanvasFactory.h
new file mode 100644
index 00000000..dc272700
--- /dev/null
+++ b/ksvg/core/CanvasFactory.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CANVASFACTORY_H
+#define CANVASFACTORY_H
+
+#include <ktrader.h>
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+namespace KSVG
+{
+
+class KSVGCanvas;
+class CanvasInfo
+{
+public:
+ KService::Ptr service;
+ KSVGCanvas *canvas;
+ QString name, internal;
+};
+
+class CanvasFactory
+{
+public:
+ CanvasFactory();
+ ~CanvasFactory();
+
+ static CanvasFactory *self();
+
+ void cleanup();
+ KSVGCanvas *loadCanvas(int width, int height);
+
+ int itemInList(KSVGCanvas *canvas);
+ QString internalNameFor(const QString &name);
+ void deleteCanvas(KSVGCanvas *canvas);
+
+ QPtrList<CanvasInfo> canvasList();
+
+private:
+ void queryCanvas();
+
+ static CanvasFactory *s_factory;
+ QPtrList<CanvasInfo> m_canvasList;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/CanvasItem.h b/ksvg/core/CanvasItem.h
new file mode 100644
index 00000000..7ffc7ad9
--- /dev/null
+++ b/ksvg/core/CanvasItem.h
@@ -0,0 +1,154 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CANVASITEM_H
+#define CANVASITEM_H
+
+#include <qrect.h>
+#include <qpoint.h>
+#include <qvaluelist.h>
+
+#define CHUNK_SIZE_HORIZONTAL 32
+#define CHUNK_SIZE_VERTICAL 32
+
+namespace KSVG
+{
+
+class SVGElementImpl;
+
+enum RenderContext
+{
+ /* NONE = for initializing */
+ NONE = 0,
+ /* NORMAL = use baseVal()'s for calculation, and fillRule */
+ NORMAL = 1,
+ /* CLIPPING = use baseVal()'s for calculation, and clipRule */
+ CLIPPING = 2,
+ /* ANIMATION = use animVal()'s for calculation, and fillRule */
+ ANIMATION = 4
+};
+
+enum CanvasItemUpdate
+{
+ UPDATE_STYLE,
+ UPDATE_LINEWIDTH,
+ UPDATE_TRANSFORM,
+ UPDATE_ZOOM,
+ UPDATE_PAN
+};
+
+class CanvasItem
+{
+public:
+ CanvasItem() { m_zIndex = 0; m_referenced = false; }
+ virtual ~CanvasItem() { }
+
+ virtual QRect bbox() const = 0;
+ virtual bool fillContains(const QPoint &) = 0;
+ virtual bool strokeContains(const QPoint &) = 0;
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0) = 0;
+ virtual void draw() = 0;
+ virtual bool isVisible() = 0;
+
+ void setZIndex(unsigned int zIndex) { m_zIndex = zIndex; }
+ unsigned int zIndex() const { return m_zIndex; }
+
+ void setReferenced(bool referenced) { m_referenced = referenced; }
+ bool referenced() const { return m_referenced; }
+
+ virtual SVGElementImpl *element() const { return 0; }
+
+protected:
+ unsigned int m_zIndex;
+ bool m_referenced;
+};
+
+class CanvasItemPtr
+{
+public:
+ CanvasItemPtr() : ptr(0) { }
+ CanvasItemPtr(CanvasItem *p) : ptr(p) { }
+
+ bool operator<=(const CanvasItemPtr& that) const
+ {
+ // Order same-z objects by identity.
+ if(that.ptr->zIndex() == ptr->zIndex())
+ return that.ptr >= ptr;
+ return that.ptr->zIndex() >= ptr->zIndex();
+ }
+ bool operator<(const CanvasItemPtr& that) const
+ {
+ // Order same-z objects by identity.
+ if(that.ptr->zIndex() == ptr->zIndex())
+ return that.ptr > ptr;
+ return that.ptr->zIndex() > ptr->zIndex();
+ }
+ bool operator>(const CanvasItemPtr& that) const
+ {
+ // Order same-z objects by identity.
+ if(that.ptr->zIndex() == ptr->zIndex())
+ return that.ptr < ptr;
+ return that.ptr->zIndex() < ptr->zIndex();
+ }
+ bool operator==(const CanvasItemPtr& that) const { return that.ptr == ptr; }
+ operator CanvasItem *() const { return ptr; }
+
+private:
+ CanvasItem *ptr;
+};
+
+class CanvasItemList : public QValueList<CanvasItem *>
+{
+public:
+ void sort() { qHeapSort(*((QValueList<CanvasItemPtr> *) this)); }
+};
+
+class CanvasChunk
+{
+public:
+ CanvasChunk(short x, short y) : m_x(x), m_y(y), m_dirty(false) { }
+
+ void sort() { m_list.sort(); }
+ const CanvasItemList &list() const { return m_list; }
+
+ void add(CanvasItem *item) { m_list.prepend(item); m_dirty = true; }
+ void remove(CanvasItem *item) { m_list.remove(item); m_dirty = true; }
+
+ void setDirty() { m_dirty = true; }
+ bool unsetDirty() { bool y = m_dirty; m_dirty = false; return y; }
+ bool isDirty() const { return m_dirty; }
+
+ short x() const { return m_x; }
+ short y() const { return m_y; }
+
+ QRect bbox() const { return QRect(m_x * CHUNK_SIZE_HORIZONTAL, m_y * CHUNK_SIZE_VERTICAL, CHUNK_SIZE_HORIZONTAL, CHUNK_SIZE_VERTICAL); }
+
+private:
+ CanvasItemList m_list;
+ short m_x;
+ short m_y;
+ bool m_dirty : 1;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/CanvasItems.cpp b/ksvg/core/CanvasItems.cpp
new file mode 100644
index 00000000..0ffd017c
--- /dev/null
+++ b/ksvg/core/CanvasItems.cpp
@@ -0,0 +1,509 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KSVGCanvas.h"
+#include "KSVGHelper.h"
+#include "KSVGTextChunk.h"
+
+#include "CanvasItems.h"
+
+#include "SVGMatrixImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPathElementImpl.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGTSpanElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+
+#include <Glyph.h>
+#include <Converter.h>
+#include <Font.h>
+
+#include <kdebug.h>
+
+using namespace KSVG;
+
+CanvasText::CanvasText(SVGTextElementImpl *text) : CanvasItem(), m_text(text)
+{
+}
+
+CanvasText::~CanvasText()
+{
+}
+
+void CanvasText::handleTSpan(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy, SVGElementImpl *element, KSVGTextChunk *textChunk, T2P::BezierPath *bpath)
+{
+ SVGTSpanElementImpl *tspan = dynamic_cast<SVGTSpanElementImpl *>(element);
+ if(!tspan)
+ return;
+
+ if(!tspan->text().isEmpty() || element->nodeName() == "tref")
+ {
+ if((KSVG_TOKEN_NOT_PARSED_ELEMENT(SVGTextPositioningElementImpl::X, tspan) && KSVG_TOKEN_NOT_PARSED_ELEMENT(SVGTextPositioningElementImpl::Y, tspan)))// && !bpath)
+ textChunk->addText(tspan->text(), tspan);
+ else
+ {
+ // new absolute value for next textChunk, render old one
+ if(textChunk->count() > 0)
+ {
+ createGlyphs(textChunk, canvas, screenCTM, curx, cury, curx, cury, bpath);
+ textChunk->clear();
+ }
+
+ int usex, usey;
+ bool bMultipleX = false;
+ bool bMultipleY = false;
+
+ if(tspan->x()->baseVal()->numberOfItems() == 0)
+ {
+ usex = curx;
+
+ if(tspan->dx()->baseVal()->numberOfItems() > 0)
+ usex += int(tspan->dx()->baseVal()->getItem(0)->value());
+ }
+ else
+ {
+ if(tspan->x()->baseVal()->numberOfItems() > 1)
+ bMultipleX = true;
+
+ usex = int(tspan->x()->baseVal()->getItem(0)->value());
+ }
+
+ if(tspan->y()->baseVal()->numberOfItems() == 0)
+ {
+ usey = cury;
+
+ if(tspan->dy()->baseVal()->numberOfItems() > 0)
+ usey += int(tspan->dy()->baseVal()->getItem(0)->value());
+ }
+ else
+ {
+ if(tspan->y()->baseVal()->numberOfItems() > 1)
+ bMultipleY = true;
+
+ usey = int(tspan->y()->baseVal()->getItem(0)->value());
+ }
+
+ QString text = tspan->text();
+ if(!text.isEmpty())
+ {
+ T2P::GlyphLayoutParams *params = tspan->layoutParams();
+
+ if(bMultipleX || bMultipleY)
+ {
+ for(unsigned int i = 0; i < text.length(); i++)
+ {
+ if(bMultipleX && i < tspan->x()->baseVal()->numberOfItems())
+ usex = int(tspan->x()->baseVal()->getItem(i)->value());
+ if(bMultipleY && i < tspan->y()->baseVal()->numberOfItems())
+ usey = int(tspan->y()->baseVal()->getItem(i)->value());
+
+ textChunk->addText(QString(text.at(i)), tspan);
+ createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath);
+ textChunk->clear();
+
+ if(!params->tb())
+ usex += endx;
+ else
+ usey += endy;
+ }
+ }
+ else
+ {
+ textChunk->addText(text, tspan);
+ //createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath);
+ //textChunk->clear();
+ }
+
+ curx = usex;
+ cury = usey;
+
+ if(!params->tb())
+ curx += endx;
+ else
+ cury += endy;
+
+ delete params;
+ }
+ }
+ }
+
+ DOM::Node node = (tspan->getTextDirection() == LTR) ? tspan->firstChild() : tspan->lastChild();
+
+ bool tspanFound = false;
+ for(; !node.isNull(); node = ((tspan->getTextDirection() == LTR) ? node.nextSibling() : node.previousSibling()))
+ {
+ SVGElementImpl *element = m_text->ownerDoc()->getElementFromHandle(node.handle());
+ if(node.nodeType() == DOM::Node::TEXT_NODE)
+ {
+ if(tspanFound)
+ {
+ DOM::Text text = node;
+ QString temp = text.data().string();
+ textChunk->addText(temp, tspan);
+ }
+ }
+ else if(element->nodeName() == "tspan" || element->nodeName() == "tref")
+ {
+ tspanFound = true;
+ handleTSpan(canvas, screenCTM, curx, cury, endx, endy, element, textChunk, 0);
+ }
+ }
+
+}
+
+KSVGTextChunk *CanvasText::createTextChunk(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy)
+{
+ KSVGTextChunk *textChunk = new KSVGTextChunk();
+
+ SVGLengthImpl *length = m_text->x()->baseVal()->getItem(0);
+ if(length)
+ curx = int(length->value());
+
+ length = m_text->y()->baseVal()->getItem(0);
+ if(length)
+ cury = int(length->value());
+
+ // Otherwhise some js scripts which require a child, don't work (Niko)
+ if(!m_text->hasChildNodes())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(m_text->ownerDoc())->createTextNode(DOM::DOMString(""));
+ m_text->appendChild(impl);
+ }
+ else
+ {
+ DOM::Node node = (m_text->getTextDirection() == LTR) ? m_text->firstChild() : m_text->lastChild();
+
+ for(; !node.isNull(); node = ((m_text->getTextDirection() == LTR) ? node.nextSibling() : node.previousSibling()))
+ {
+ if(node.nodeType() == DOM::Node::TEXT_NODE)
+ {
+ DOM::Text text = node;
+ QString temp = text.data().string();
+
+ if(!temp.isEmpty())
+ {
+ if(m_text->getTextDirection() != LTR)
+ {
+ QString convert = temp;
+
+ for(int i = temp.length(); i > 0; i--)
+ convert[temp.length() - i] = temp[i - 1];
+
+ temp = convert;
+ }
+
+ textChunk->addText(temp, m_text);
+ }
+ }
+ else
+ {
+ SVGElementImpl *element = m_text->ownerDoc()->getElementFromHandle(node.handle());
+ if(element->nodeName() == "textPath")
+ {
+ // new absolute value for next textChunk, render old one
+ if(textChunk->count() > 0)
+ {
+ createGlyphs(textChunk, canvas, screenCTM, curx, cury, curx, cury);
+ textChunk->clear();
+ }
+
+ SVGTextPathElementImpl *tpath = dynamic_cast<SVGTextPathElementImpl *>(element);
+ QString target = SVGURIReferenceImpl::getTarget(tpath->href()->baseVal().string());
+ SVGPathElementImpl *path = dynamic_cast<SVGPathElementImpl *>(tpath->ownerSVGElement()->getElementById(target));
+
+ T2P::BezierPath *bpath = 0;
+ if(path && path->item())
+ bpath = tpath->ownerDoc()->canvas()->toBezierPath(path->item());
+
+ DOM::Node iterate = tpath->firstChild();
+ for(; !iterate.isNull(); iterate = iterate.nextSibling())
+ {
+ if(iterate.nodeType() == DOM::Node::TEXT_NODE)
+ {
+ DOM::Text text = iterate;
+ QString temp = text.data().string();
+
+ if(!temp.isEmpty())
+ textChunk->addText(temp, tpath);
+ }
+ else
+ {
+ kdDebug() << "FOUND TSPAN IN TEXTPATH! BPATH:" << bpath <<endl;
+
+ SVGElementImpl *itelement = m_text->ownerDoc()->getElementFromHandle(iterate.handle());
+ handleTSpan(canvas, screenCTM, curx, cury, endx, endy, itelement, textChunk, bpath);
+ }
+ }
+
+ if(textChunk->count() > 0)
+ {
+ int usex = 0, usey = 0;
+ createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath);
+ textChunk->clear();
+
+ curx = usex;
+ cury = usey;
+
+ T2P::GlyphLayoutParams *params = tpath->layoutParams();
+
+ if(!params->tb())
+ curx += endx;
+ else
+ cury += endy;
+
+ delete params;
+ }
+ }
+ else if(element->nodeName() == "tspan" || element->nodeName() == "tref")
+ handleTSpan(canvas, screenCTM, curx, cury, endx, endy, element, textChunk, 0);
+ }
+ }
+ }
+
+ return textChunk;
+}
+
+void CanvasText::createGlyphs(KSVGTextChunk *textChunk, KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int curx, int cury, int &endx, int &endy, T2P::BezierPath *bpath) const
+{
+ double _curx = double(curx);
+ QMemArray<double> _cury(1);
+ _cury[0] = double(cury);
+
+ T2P::GlyphLayoutParams *params = m_text->layoutParams();
+ SVGTextPositioningElementImpl *tp = textChunk->getTextElement(0);
+ SVGTextContentElementImpl *tc = textChunk->getTextContentElement(0);
+ SVGTextContentElementImpl *tc0 = tc;
+
+ T2P::SharedFont font;
+ QString text;
+ QPtrList<T2P::GlyphSet> glyphs;
+ glyphs.setAutoDelete(true);
+
+ double pathAdvance = 0;
+ SVGTextPathElementImpl *tpath = dynamic_cast<SVGTextPathElementImpl *>(tc0);
+ if(tpath)
+ pathAdvance = tpath->startOffset()->baseVal()->value();
+ double pathLength = bpath ? bpath->length() : 0;
+ double pathDy = 0;
+ for(unsigned int i = 0; i < textChunk->count(); i++)
+ {
+ tp = textChunk->getTextElement(i);
+ tc = textChunk->getTextContentElement(i);
+
+ if(tp && tp->dx()->baseVal()->numberOfItems() > 0)
+ if(bpath)
+ pathAdvance += tp->dx()->baseVal()->getItem(0)->value() / pathLength;
+ else
+ _curx += tp->dx()->baseVal()->getItem(0)->value();
+ _cury[i] += (tp && tp->dy()->baseVal()->numberOfItems() > 0) ? tp->dy()->baseVal()->getItem(0)->value() : 0;
+
+ SVGMatrixImpl *tempMatrix = SVGSVGElementImpl::createSVGMatrix();
+ tempMatrix->translate(_curx, _cury[i]);
+
+ text = textChunk->getText(i);
+ if(i != textChunk->count() - 1)
+ text += QChar(' ');
+
+ if(!canvas->fontContext()->ready())
+ canvas->fontContext()->init();
+
+ font = canvas->fontContext()->requestFont(canvas->fontVisualParams(tc));
+
+ if(!font)
+ break;
+
+ double addLetterSpacing = 0;
+
+ // Apply affine corrections, through lengthAdjust + textLength
+ if(tp && tp->textLength()->baseVal()->value() != -1)
+ {
+ // #1 Measure text
+ SVGTextElementImpl *textElement = dynamic_cast<SVGTextElementImpl *>(tp);
+ const SVGMatrixImpl *ctm = textElement->screenCTM();
+
+ T2P::Affine affine;
+ {
+ SVGMatrixImpl *temp = SVGSVGElementImpl::createSVGMatrix();
+
+ temp->multiply(ctm);
+ temp->translate(_curx, _cury[0]);
+
+ KSVGHelper::matrixToAffine(temp, affine);
+
+ temp->deref();
+ }
+
+ T2P::GlyphSet *measure = canvas->fontContext()->calcString(font.get(), text.ucs2(), text.length(), affine, params, bpath);
+
+ // Free bpath's
+ measure->set().clear();
+
+ // #2 Calculate textLength
+ double textLength = tp->textLength()->baseVal()->value();
+
+ // #3 Apply the spacing
+ if(tp->lengthAdjust()->baseVal() == LENGTHADJUST_SPACINGANDGLYPHS)
+ tempMatrix->scaleNonUniform((textLength * ctm->a()) / measure->width(), 1);
+ else if(tp->lengthAdjust()->baseVal() == LENGTHADJUST_SPACING)
+ addLetterSpacing = ((textLength - (measure->width() / ctm->a())) / text.length());
+
+ // #4 cleanup
+ delete measure;
+ }
+
+ {
+ T2P::GlyphLayoutParams *params = tc->layoutParams();
+ params->setLetterSpacing(params->letterSpacing() + addLetterSpacing);
+ if(bpath)
+ {
+ params->setTextPathStartOffset(pathAdvance);
+ if(tp && tp->dy()->baseVal()->numberOfItems() > 0)
+ pathDy += tp->dy()->baseVal()->getItem(0)->value();
+ QString shift = QString("%1%%").arg((pathDy / font->fontParams()->size()) * -100.0);
+ params->setBaselineShift(shift.latin1());
+ }
+
+ T2P::Affine affine;
+ KSVGHelper::matrixToAffine(tempMatrix, affine);
+ tempMatrix->deref();
+
+ T2P::GlyphSet *glyph = canvas->fontContext()->calcString(font.get(), text.ucs2(), text.length(), affine, params, bpath);
+ if(bpath)
+ pathAdvance += double(glyph->width()) / pathLength;
+ _curx += (params->tb() ? 0 : glyph->xpen());
+ _cury.resize(i + 2);
+ _cury[i + 1] = _cury[i] + (params->tb() ? glyph->ypen() : 0);
+ if(!glyph)
+ break;
+ else
+ glyphs.append(glyph);
+
+ delete params;
+ }
+ }
+
+ // Calculate text-anchor
+ double anchor = 0;
+
+ // anchor == "start" is the default here (Rob)
+ if(tc->getTextAnchor() == TAMIDDLE)
+ {
+ if(!params->tb())
+ anchor = ((_curx - curx) + 1) / 2;
+ else
+ anchor = ((_cury[textChunk->count()] - cury) + 1) / 2;
+ }
+ else if(tc->getTextAnchor() == TAEND)
+ {
+ if(!params->tb())
+ anchor = (_curx - curx);
+ else
+ anchor = (_cury[textChunk->count()] - cury);
+ }
+
+ // Render all glyphs of the text chunk
+ // Take first glyphset
+ T2P::GlyphSet *glyph = glyphs.at(0);
+ if(!glyph)
+ return;
+
+ // Draw 'text-decoration'
+ // TODO: Currently just ignore text-decoration on vertical layouts, is that correct?
+ // Underline and overline have to be drawn before the glyphs are rendered
+ if(tc0->getTextDecoration() & UNDERLINE && !params->tb())
+ addTextDecoration(tc0, (curx - anchor), (cury + (glyph->underlinePosition() - glyph->pixelBaseline())),
+ _curx - curx, glyph->underlineThickness());
+ if(tc0->getTextDecoration() & OVERLINE && !params->tb())
+ addTextDecoration(tc0, (curx - anchor), (cury + (glyph->overlinePosition() - glyph->pixelBaseline())),
+ _curx - curx, glyph->underlineThickness());
+
+ for(unsigned int j = 0; j < glyphs.count(); j++)
+ {
+ glyph = glyphs.at(j);
+ SVGTextContentElementImpl *style = textChunk->getTextContentElement(j);
+
+ // Draw 'text-decoration'
+ // TODO: Currently just ignore text-decoration on vertical layouts, is that correct?
+ // Underline and overline have to be drawn before the glyphs are rendered
+ if(style->getAttribute("text-decoration") == "underline" && !params->tb())
+ addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->underlinePosition() - glyph->pixelBaseline())),
+ glyph->width(), glyph->underlineThickness());
+ else if(style->getAttribute("text-decoration") == "overline" && !params->tb())
+ addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->overlinePosition() - glyph->pixelBaseline())),
+ glyph->width(), glyph->underlineThickness());
+
+ renderCallback(style, screenCTM, glyph, params, anchor);
+
+ // Clear GlyphAffinePair's
+ for(std::vector<T2P::GlyphAffinePair *>::iterator it = glyph->set().begin(); it != glyph->set().end(); ++it)
+ {
+ T2P::GlyphAffinePair *glyphAffine = *it;
+ delete glyphAffine;
+ }
+
+ glyph->set().clear();
+
+ // Draw 'line-through' text decoration
+ // Line-through has to be drawn after the glyphs are rendered
+ if(style->getAttribute("text-decoration") == "line-through" && !params->tb())
+ addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->strikeThroughPosition() - glyph->pixelBaseline())), glyph->width(), glyph->underlineThickness());
+
+ }
+
+ endx = glyph->bboxX() + glyph->width();
+ endy = int(_cury[glyphs.count() - 1]);
+
+ // Draw 'line-through' text decoration
+ // Line-through has to be drawn after the glyphs are rendered
+ if(tc0->getTextDecoration() & LINE_THROUGH && !params->tb())
+ addTextDecoration(tc0, (curx - anchor), (cury + (glyph->strikeThroughPosition() - glyph->pixelBaseline())), _curx - curx, glyph->underlineThickness());
+
+ delete params;
+}
+
+// #####
+
+void MarkerHelper::doMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle, const QString &markerId)
+{
+ SVGMarkerElementImpl *marker = dynamic_cast<SVGMarkerElementImpl *>(shape->ownerSVGElement()->getElementById(markerId));
+ if(marker)
+ marker->draw(shape, x, y, style->getStrokeWidth()->baseVal()->value(), angle);
+}
+
+void MarkerHelper::doStartMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle)
+{
+ doMarker(shape, style, x, y, angle, style->getStartMarker());
+}
+
+void MarkerHelper::doMidMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle)
+{
+ doMarker(shape, style, x, y, angle, style->getMidMarker());
+}
+
+void MarkerHelper::doEndMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle)
+{
+ doMarker(shape, style, x, y, angle, style->getEndMarker());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/CanvasItems.h b/ksvg/core/CanvasItems.h
new file mode 100644
index 00000000..8959d6ba
--- /dev/null
+++ b/ksvg/core/CanvasItems.h
@@ -0,0 +1,133 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CANVASITEMS_H
+#define CANVASITEMS_H
+
+#include <qptrlist.h>
+#include "CanvasItem.h"
+#include "SVGTextElementImpl.h"
+#include "SVGTextPathElementImpl.h"
+
+#include "svgpathparser.h"
+#include "SVGBBoxTarget.h"
+
+namespace T2P
+{
+ class GlyphSet;
+ class BezierPath;
+ class GlyphLayoutParams;
+}
+
+namespace KSVG
+{
+
+class KSVGCanvas;
+class KSVGTextChunk;
+class SVGPathParser;
+class SVGMatrixImpl;
+class SVGMarkerElementImpl;
+class SVGClipPathElementImpl;
+class SVGTextContentElementImpl;
+class SVGTextPathElementImpl;
+
+#define CANVAS_CLASS(Prefix, Class, Postfix, Member) \
+class Canvas##Class : public CanvasItem \
+{ \
+public: \
+ Canvas##Class(Prefix##Class##Postfix *Member) : CanvasItem(), m_##Member(Member) { } \
+ virtual ~Canvas##Class() { } \
+ virtual SVGElementImpl *element() { return reinterpret_cast<SVGElementImpl *>(m_##Member); } \
+protected: \
+ Prefix##Class##Postfix *m_##Member; \
+};
+
+CANVAS_CLASS(SVG, ClipPath, ElementImpl, clipPath)
+
+class CanvasMarker : public CanvasItem
+{
+public:
+ CanvasMarker(SVGMarkerElementImpl *marker) : CanvasItem(), m_marker(marker) {}
+ virtual ~CanvasMarker() {}
+ virtual SVGElementImpl *element() { return reinterpret_cast<SVGElementImpl *>(m_marker); }
+
+ virtual void draw(SVGShapeImpl *obj, double x, double y, double lwidth = 1.0, double angle = 0.0)
+ {
+ Q_UNUSED(obj); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(lwidth); Q_UNUSED(angle);
+ }
+
+protected:
+ SVGMarkerElementImpl *m_marker;
+};
+
+class MarkerHelper
+{
+protected:
+ void doStartMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0);
+ void doMidMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0);
+ void doEndMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0);
+
+private:
+ void doMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle, const QString &marker);
+};
+
+class CanvasText : public CanvasItem
+{
+public:
+ CanvasText(SVGTextElementImpl *text);
+ virtual ~CanvasText();
+
+ KSVGTextChunk *createTextChunk(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy);
+ virtual SVGElementImpl *element() const { return m_text; }
+
+ virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const = 0;
+ void createGlyphs(KSVGTextChunk *textChunk, KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int curx, int cury, int &endx, int &endy, T2P::BezierPath *bpath = 0) const;
+
+ virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const = 0;
+
+private:
+ void handleTSpan(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy, SVGElementImpl *element, KSVGTextChunk *textChunk, T2P::BezierPath *bpath);
+
+protected:
+ SVGTextElementImpl *m_text;
+};
+
+class CanvasPaintServer : public SVGBBoxTarget
+{
+public:
+ CanvasPaintServer() : SVGBBoxTarget() { m_finalized = false; }
+ virtual ~CanvasPaintServer() {}
+
+ void setFinalized() { m_finalized = true; }
+ void resetFinalized() { m_finalized = false; }
+ bool finalized() { return m_finalized; }
+
+ virtual void finalizePaintServer() = 0;
+ virtual void reference(const QString &href) = 0;
+
+private:
+ bool m_finalized;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/DocumentFactory.cpp b/ksvg/core/DocumentFactory.cpp
new file mode 100644
index 00000000..bcc0ddcb
--- /dev/null
+++ b/ksvg/core/DocumentFactory.cpp
@@ -0,0 +1,110 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qobject.h>
+
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+
+#include "SVGDocument.h"
+#include "SVGElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "DocumentFactory.h"
+
+using namespace KSVG;
+
+namespace KSVG
+{
+ class DocumentFactory::Private
+ {
+ public:
+ Private() { m_docs.setAutoDelete(true); }
+ ~Private() { m_docs.clear(); }
+
+ void setup(bool bFit) { m_docs.append(new SVGDocumentImpl(!bFit /* animations */, bFit)); }
+ SVGDocumentImpl *doc() const { return m_docs.current(); }
+
+ private:
+ QPtrList<SVGDocumentImpl> m_docs;
+ };
+}
+
+static KStaticDeleter<DocumentFactory> s_deleter;
+static DocumentFactory *s_factory = 0;
+
+DocumentFactory::DocumentFactory() : m_d(new Private())
+{
+}
+
+DocumentFactory::~DocumentFactory()
+{
+ delete m_d;
+}
+
+DocumentFactory *DocumentFactory::self()
+{
+ if(!s_factory)
+ s_deleter.setObject(s_factory, new DocumentFactory());
+ return s_factory;
+}
+
+SVGDocument *DocumentFactory::requestDocument(QObject *notifyObject, const char *notifySlot) const
+{
+ SVGDocumentImpl *impl = requestDocumentImpl(false);
+ QObject::connect(impl, SIGNAL(finishedParsing(bool, const QString &)), notifyObject, notifySlot);
+
+ return new SVGDocument(impl);
+}
+
+bool DocumentFactory::startParsing(SVGDocument *document, const KURL &url)
+{
+ if(!document || !document->handle())
+ return false;
+
+ return reinterpret_cast<SVGDocumentImpl *>(document->handle())->open(url);
+}
+
+bool DocumentFactory::attachCanvas(KSVGCanvas *canvas, SVGDocument *document)
+{
+ if(!canvas || !document || !document->handle())
+ return false;
+
+ SVGDocumentImpl *docImpl = reinterpret_cast<SVGDocumentImpl *>(document->handle());
+
+ if(docImpl)
+ {
+ docImpl->attach(canvas);
+ return true;
+ }
+
+ return false;
+}
+
+SVGDocumentImpl *DocumentFactory::requestDocumentImpl(bool bFit) const
+{
+ m_d->setup(bFit);
+
+ SVGDocumentImpl *impl = m_d->doc();
+ impl->ref();
+
+ return impl;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/DocumentFactory.h b/ksvg/core/DocumentFactory.h
new file mode 100644
index 00000000..290d54ac
--- /dev/null
+++ b/ksvg/core/DocumentFactory.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DocumentFactory_H
+#define DocumentFactory_H
+
+#include <kurl.h>
+#include <qobject.h>
+
+namespace KSVG
+{
+
+class KSVGCanvas;
+class SVGDocument;
+class SVGDocumentImpl;
+class DocumentFactory
+{
+public:
+ DocumentFactory();
+ ~DocumentFactory();
+
+ static DocumentFactory *self();
+
+ // Creates a document and connects the parsingFinished() signal to the notifySlot...
+ SVGDocument *requestDocument(QObject *notifyObject, const char *notifySlot) const;
+
+ // Loads 'url' and emits parsingFinisihed() signal, when done
+ bool startParsing(SVGDocument *document, const KURL &url);
+
+ // Attaches the a canvas to the document, that is ksvg specific code
+ bool attachCanvas(KSVGCanvas *canvas, SVGDocument *document);
+
+ // Internal use only - external coders don't have the
+ // possibility to use SVGDocumentImpl anyway
+ SVGDocumentImpl *requestDocumentImpl(bool bFit) const;
+
+private:
+ class Private;
+ Private *m_d;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGCanvas.cpp b/ksvg/core/KSVGCanvas.cpp
new file mode 100644
index 00000000..d4e75d79
--- /dev/null
+++ b/ksvg/core/KSVGCanvas.cpp
@@ -0,0 +1,786 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "CanvasItem.h"
+#include "CanvasItems.h"
+#include "KSVGCanvas.moc"
+
+#include "SVGRectImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGDocumentImpl.h"
+
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qpaintdevicemetrics.h>
+#include <qwmatrix.h>
+
+#include <X11/Xlib.h>
+
+#include <math.h>
+
+#include <libs/xrgbrender/gdk-pixbuf-xlibrgb.h>
+
+#include <Font.h>
+#include <fontconfig/fontconfig.h>
+
+#define USE_TIMER
+
+using namespace KSVG;
+
+KSVGCanvas::KSVGCanvas(unsigned int width, unsigned int height) : m_viewportWidth(width), m_viewportHeight(height), m_width(width), m_height(height)
+{
+ m_fontContext = 0;
+
+ m_items.setAutoDelete(true);
+
+ m_chunkSizeVer = CHUNK_SIZE_VERTICAL;
+ m_chunkSizeHor = CHUNK_SIZE_HORIZONTAL;
+
+ m_zoom = 1;
+
+ m_buffer = 0;
+
+ m_backgroundColor = QColor(250, 250, 250);
+
+ m_immediateUpdate = false;
+}
+
+void KSVGCanvas::setup(QPaintDevice *drawWindow, QPaintDevice *directWindow)
+{
+ m_drawWindow = drawWindow;
+ m_directWindow = directWindow;
+
+ m_buffer = 0;
+ m_nrChannels = 3;
+
+ setRenderBufferSize(m_width, m_height);
+
+ xlib_rgb_init_with_depth(m_drawWindow->x11Display(), XScreenOfDisplay(m_drawWindow->x11Display(), m_drawWindow->x11Screen()), m_drawWindow->x11Depth());
+ m_gc = XCreateGC(m_drawWindow->x11Display(), m_drawWindow->handle(), 0, 0);
+}
+
+void KSVGCanvas::setViewportDimension(unsigned int w, unsigned int h)
+{
+ m_viewportWidth = w;
+ m_viewportHeight = h;
+ setRenderBufferSize(w, h);
+}
+
+void KSVGCanvas::setup(unsigned char *buffer, unsigned int width, unsigned int height)
+{
+ setBuffer(buffer);
+ m_drawWindow = 0;
+ m_directWindow = 0;
+
+ m_nrChannels = 4;
+
+ if(height > 0)
+ {
+ m_width = width;
+ m_height = height;
+ }
+
+ setRenderBufferSize(m_width, m_height);
+
+ m_gc = 0;
+}
+
+void KSVGCanvas::setBuffer(unsigned char *buffer)
+{
+ m_buffer = buffer;
+}
+
+KSVGCanvas::~KSVGCanvas()
+{
+ if(m_fontContext)
+ delete m_fontContext;
+
+ if(m_buffer && m_gc)
+ delete []m_buffer;
+
+ if(m_gc)
+ XFreeGC(m_drawWindow->x11Display(), m_gc);
+
+ reset();
+}
+
+void KSVGCanvas::retune(unsigned int csh, unsigned int csv)
+{
+ m_chunkSizeHor = csh;
+ m_chunkSizeVer = csv;
+}
+
+void KSVGCanvas::resize(unsigned int w, unsigned int h)
+{
+ if(m_buffer && (m_width != int(w) || m_height != int(h)))
+ {
+ unsigned char *oldbuffer = m_buffer;
+
+ m_buffer = new unsigned char[w * h * m_nrChannels];
+
+ int minw = kMin(int(w), m_width);
+ int minh = kMin(int(h), m_height);
+
+ int origstride = m_width * m_nrChannels;
+ int newstride = w * m_nrChannels;
+
+ // Redraw new areas, if any
+ int diffw = w - m_width;
+ int diffh = h - m_height;
+
+ QRect r(m_width, 0, diffw, m_height + diffh);
+ QRect r3(0, m_height, m_width + diffw, diffh);
+
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ m_width = w;
+ m_height = h;
+
+ setBuffer(m_buffer);
+ fill();
+
+ if(diffw > 0 || diffh > 0)
+ {
+ CanvasItemList drawables;
+ if(diffw > 0)
+ {
+ QRect r2 = mtx.invert().map(r);
+
+ // Recalc items
+ for(int j = r2.top() / int(m_chunkSizeVer); j <= r2.bottom() / int(m_chunkSizeVer); j++)
+ {
+ for(int i = r2.left() / int(m_chunkSizeHor); i <= r2.right() / int(m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(chunk)
+ {
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+ if(!drawables.contains(*it))
+ drawables.append(*it);
+ }
+ }
+ }
+ }
+ }
+
+ if(diffh > 0)
+ {
+ QRect r4 = mtx.invert().map(r3);
+
+ // Recalc items
+ for(int j = r4.top() / int(m_chunkSizeVer); j <= r4.bottom() / int(m_chunkSizeVer); j++)
+ {
+ for(int i = r4.left() / int(m_chunkSizeHor); i <= r4.right() / int(m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(chunk)
+ {
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+ if(!drawables.contains(*it))
+ drawables.append(*it);
+ }
+ }
+ }
+ }
+ }
+
+ drawables.sort();
+
+ for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it)
+ (*it)->draw();
+ }
+
+ for(int y = 0; y < minh; y++)
+ memcpy(m_buffer + y * newstride, oldbuffer + y * origstride, minw * m_nrChannels);
+
+ delete []oldbuffer;
+ }
+}
+
+void KSVGCanvas::setRenderBufferSize(int w, int h)
+{
+ kdDebug(26005) << k_funcinfo << endl;
+
+ if(m_drawWindow)
+ {
+ bool needsRedraw = (!m_buffer) || (m_width != w || m_height != h);
+
+ if(needsRedraw)
+ {
+ QPaintDeviceMetrics metrics(m_drawWindow);
+ m_width = kMin(int(w), metrics.width());
+ m_height = kMin(int(h), metrics.height());
+
+ if(m_buffer)
+ delete []m_buffer;
+
+ m_buffer = new unsigned char[m_width * m_height * m_nrChannels];
+ }
+ }
+
+ fill();
+}
+
+void KSVGCanvas::clear(const QRect &r)
+{
+ QRect r2 = r & QRect(0, 0, m_width, m_height);
+ if(!r2.isEmpty() && m_buffer)
+ {
+ for(int i = 0; i < r2.height(); i++)
+ memset(m_buffer + int(r2.x() * m_nrChannels) + int((r2.y() + i) * (m_width * m_nrChannels)), qRgba(250, 250, 250, 250), r2.width() * m_nrChannels);
+ }
+}
+
+void KSVGCanvas::fill()
+{
+ if(m_buffer)
+ {
+ unsigned char r = m_backgroundColor.red();
+ unsigned char g = m_backgroundColor.green();
+ unsigned char b = m_backgroundColor.blue();
+
+ if(m_nrChannels == 3)
+ {
+ if(r == g && r == b)
+ memset(m_buffer, r, m_width * m_height * m_nrChannels);
+ else
+ {
+ unsigned char *p = m_buffer;
+
+ for(int i = 0; i < m_width * m_height; i++)
+ {
+ *p++ = r;
+ *p++ = g;
+ *p++ = b;
+ }
+ }
+ }
+ else
+ {
+ Q_UINT32 *p = reinterpret_cast<Q_UINT32 *>(m_buffer);
+ unsigned char a = qAlpha(m_backgroundColor.rgb());
+
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+ Q_UINT32 rgba = (a << 24) | (b << 16) | (g << 8) | r;
+#else
+ Q_UINT32 rgba = (r << 24) | (g << 16) | (b << 8) | a;
+#endif
+ for(int i = 0; i < m_width * m_height; i++)
+ *p++ = rgba;
+ }
+ }
+}
+
+// Clipping
+void KSVGCanvas::clipToBuffer(int &x0, int &y0, int &x1, int &y1) const
+{
+ // clamp to viewport
+ x0 = QMAX(x0, 0);
+ x0 = QMIN(x0, int(m_width - 1));
+
+ y0 = QMAX(y0, 0);
+ y0 = QMIN(y0, int(m_height - 1));
+
+ x1 = QMAX(x1, 0);
+ x1 = QMIN(x1, int(m_width - 1));
+
+ y1 = QMAX(y1, 0);
+ y1 = QMIN(y1, int(m_height - 1));
+}
+
+T2P::FontVisualParams *KSVGCanvas::fontVisualParams(SVGStylableImpl *style) const
+{
+ T2P::FontVisualParams *fontVisualParams = new T2P::FontVisualParams();
+
+ // Calc weight & slant
+ int weight = 0, slant = 0;
+ EFontStyle fontStyle = style->getFontStyle();
+ QString fontWeight = style->getFontWeight();
+
+ if(fontWeight.contains("bold"))
+ weight |= FC_WEIGHT_DEMIBOLD;
+ if(fontWeight.contains("bolder"))
+ weight |= FC_WEIGHT_BOLD;
+ if(fontWeight.contains("lighter"))
+ weight |= FC_WEIGHT_LIGHT;
+
+ bool ok = true;
+ int weightNumber = fontWeight.toInt(&ok);
+
+ if(ok)
+ weight = weightNumber;
+
+ if(fontStyle == FSNORMAL)
+ slant |= FC_SLANT_ROMAN;
+ else if(fontStyle == ITALIC)
+ slant |= FC_SLANT_ITALIC;
+ else if(fontStyle == OBLIQUE)
+ slant |= FC_SLANT_OBLIQUE;
+
+ // Calc font names
+ SVGStringListImpl *fontList = style->getFontFamily();
+
+ for(unsigned int i = 0; i <= fontList->numberOfItems(); i++)
+ {
+ DOM::DOMString *string = fontList->getItem(i);
+
+ if(string)
+ fontVisualParams->fontList().push_back(string->string().latin1());
+ }
+
+ fontVisualParams->setWeight(weight);
+ fontVisualParams->setSlant(slant);
+ fontVisualParams->setSize(style->getFontSize());
+
+ return fontVisualParams;
+}
+
+void KSVGCanvas::invalidate(CanvasItem *item, bool recalc)
+{
+ if(m_chunksByItem.find(item) != m_chunksByItem.end())
+ {
+ if(recalc)
+ {
+ removeFromChunks(item);
+ addToChunks(item);
+ }
+
+ QPtrListIterator<CanvasChunk> it = m_chunksByItem[item];
+ for(it.toFirst(); it.current(); ++it)
+ {
+ (*it)->setDirty();
+ if(!m_dirtyChunks.contains(*it))
+ m_dirtyChunks.append(*it);
+ }
+ }
+ else
+ addToChunks(item);
+}
+
+void KSVGCanvas::insert(CanvasItem *item, int z)
+{
+ if(z == -1)
+ {
+ item->setZIndex(m_chunksByItem.size());
+ m_chunksByItem[item] = QPtrList<CanvasChunk>();
+ addToChunks(item);
+ m_items.append(item);
+
+ bool visible = item->isVisible();
+ if(visible)
+ invalidate(item, false);
+
+ if(m_immediateUpdate)
+ {
+ if(visible)
+ {
+ item->draw();
+ QRect bbox = item->bbox();
+ blit(bbox, true);
+ }
+ }
+ }
+ else
+ {
+ // make some space
+ for(unsigned int i = z; i < m_items.count(); i++)
+ m_items.at(i)->setZIndex(m_items.at(i)->zIndex() + 1);
+
+ item->setZIndex(z);
+ }
+}
+
+void KSVGCanvas::removeItem(CanvasItem *item)
+{
+ removeFromChunks(item);
+ m_items.remove(item);
+}
+
+void KSVGCanvas::removeFromChunks(CanvasItem *item)
+{
+ QPtrListIterator<CanvasChunk> it = m_chunksByItem[item];
+ for(it.toFirst(); it.current(); ++it)
+ {
+ (*it)->remove(item);
+ if(!m_dirtyChunks.contains(*it))
+ m_dirtyChunks.append(*it);
+ }
+ m_chunksByItem.remove(item);
+}
+
+void KSVGCanvas::addToChunks(CanvasItem *item)
+{
+ QRect bbox = item->bbox();
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ bbox = mtx.invert().map(bbox);
+ for(int j = bbox.top() / m_chunkSizeVer; j <= (bbox.bottom() / m_chunkSizeVer); j++)
+ {
+ for(int i = bbox.left() / int(m_chunkSizeHor); i <= (bbox.right() / m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(!chunk)
+ {
+ chunk = new CanvasChunk(i, j);
+ m_chunkManager.addChunk(chunk);
+ }
+
+ chunk->add(item);
+ m_chunksByItem[item].append(chunk);
+ }
+ }
+}
+
+unsigned int KSVGCanvas::setElementItemZIndexRecursive(SVGElementImpl *element, unsigned int z)
+{
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+
+ if(shape)
+ {
+ CanvasItem *item = shape->item();
+
+ if(item)
+ {
+ SVGImageElementImpl *image = dynamic_cast<SVGImageElementImpl *>(shape);
+
+ if(image && image->svgImageRootElement())
+ {
+ // Set the z for all items in the svg image, since they live in the
+ // same canvas.
+ z = setElementItemZIndexRecursive(image->svgImageRootElement(), z);
+ }
+ else
+ {
+ item->setZIndex(z);
+ invalidate(item, false);
+ z++;
+ }
+ }
+ }
+
+ for(DOM::Node node = element->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *e = element->ownerDoc()->getElementFromHandle(node.handle());
+
+ if(e)
+ z = setElementItemZIndexRecursive(e, z);
+ }
+
+ return z;
+}
+
+void KSVGCanvas::update(const QPoint &panPoint, bool erase)
+{
+#ifdef USE_TIMER
+ QTime t;
+ t.start();
+#endif
+
+ int dx = panPoint.x() - m_pan.x();
+ int dy = panPoint.y() - m_pan.y();
+ m_pan = panPoint;
+
+ if(erase)
+ fill();
+
+ // reset clip paths
+ QDictIterator<CanvasClipPath> itr(m_clipPaths);
+ for(; itr.current(); ++itr)
+ (*itr)->update(UPDATE_TRANSFORM);
+
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ QRect r(0, 0, m_width, m_height);
+ QRect r2 = mtx.invert().map(r);
+
+ // pan all items
+ for(unsigned int i = 0; i < m_items.count(); i++)
+ m_items.at(i)->update(UPDATE_PAN, dx, dy);
+
+ // recalc items
+ CanvasItemList drawables;
+ QPtrListIterator<CanvasItem> it = m_items;
+ for(int j = r2.top() / m_chunkSizeVer; j <= (r2.bottom() / m_chunkSizeVer); j++)
+ {
+ for(int i = r2.left() / m_chunkSizeHor; i <= (r2.right() / m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(chunk)
+ {
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+ if(!drawables.contains(*it))
+ drawables.append(*it);
+ }
+ }
+ }
+ }
+
+ drawables.sort();
+ for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it)
+ (*it)->draw();
+
+ if(m_drawWindow)
+ blit(QRect(0, 0, m_width, m_height), false);
+
+ m_dirtyChunks.clear();
+
+#ifdef USE_TIMER
+ kdDebug(26000) << k_funcinfo << " Total time: " << t.elapsed() << endl;
+#endif
+}
+
+void KSVGCanvas::update(float zoomFactor)
+{
+#ifdef USE_TIMER
+ QTime t;
+ t.start();
+#endif
+
+ if(zoomFactor >= 1)
+ {
+ int newWidth = static_cast<int>(m_viewportWidth * zoomFactor);
+ int newHeight = static_cast<int>(m_viewportHeight * zoomFactor);
+ setRenderBufferSize(newWidth, newHeight);
+ }
+ else
+ fill();
+
+ // reset clip paths
+ QDictIterator<CanvasClipPath> itr(m_clipPaths);
+ for(; itr.current(); ++itr)
+ (*itr)->update(UPDATE_TRANSFORM);
+
+ m_zoom = zoomFactor;
+
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ QRect r(0, 0, m_width, m_height);
+ QRect r2 = mtx.invert().map(r);
+
+ // zoom all items
+ for(unsigned int i = 0; i < m_items.count(); i++)
+ m_items.at(i)->update(UPDATE_ZOOM);
+
+ // recalc items
+ CanvasItemList drawables;
+ QPtrListIterator<CanvasItem> it = m_items;
+ for(int j = r2.top() / m_chunkSizeVer; j <= (r2.bottom() / m_chunkSizeVer); j++)
+ {
+ for(int i = r2.left() / m_chunkSizeHor; i <= (r2.right() / m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(chunk)
+ {
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+ if(!drawables.contains(*it))
+ drawables.append(*it);
+ }
+ }
+ }
+ }
+
+ drawables.sort();
+ for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it)
+ (*it)->draw();
+
+ if(m_drawWindow)
+ blit(QRect(0, 0, m_width, m_height), false);
+
+ m_dirtyChunks.clear();
+
+#ifdef USE_TIMER
+ kdDebug(26000) << k_funcinfo << " Total time: " << t.elapsed() << endl;
+#endif
+}
+
+void KSVGCanvas::reset()
+{
+ m_items.clear();
+ m_chunkManager.clear();
+ m_chunksByItem.clear();
+ m_dirtyChunks.clear();
+ m_pan.setX(0);
+ m_pan.setY(0);
+ m_zoom = 1;
+}
+
+void KSVGCanvas::update()
+{
+#ifdef USE_TIMER
+ QTime t;
+ t.start();
+#endif
+
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ // Process dirty chunks
+ QPtrList<CanvasChunk> chunkList;
+ CanvasItemList drawables;
+ for(unsigned int i = 0; i < m_dirtyChunks.count(); i++)
+ {
+ CanvasChunk *chunk = m_dirtyChunks[i];
+ Q_ASSERT(chunk->isDirty());
+
+ QRect r = chunk->bbox();
+ QRect chunkbox(mtx.map(r.topLeft()), mtx.map(r.bottomRight()));
+ clear(chunkbox);
+ chunkList.append(chunk);
+
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+// kdDebug(26005) << k_funcinfo << " Checking: " << *it << endl;
+ if(!drawables.contains(*it))
+ {
+// kdDebug(26005) << k_funcinfo << " Yes, appending to update list!" << endl;
+ drawables.append(*it);
+ }
+ }
+
+ chunk->unsetDirty();
+ }
+
+ drawables.sort();
+
+ // Draw dirty chunks
+ for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it)
+ {
+// kdDebug(26005) << " Need to redraw dirty : " << (*it) << " with z : " << (*it)->zIndex() << endl;
+ (*it)->draw();
+ }
+
+ // Blit dirty chunks
+ QPtrListIterator<CanvasChunk> it = chunkList;
+ for(it.toFirst(); it.current(); ++it)
+ {
+ QRect r = (*it)->bbox();
+ QRect chunkbox(mtx.map(r.topLeft()), mtx.map(r.bottomRight()));
+ blit(chunkbox, false);
+ }
+
+ m_dirtyChunks.clear();
+
+#ifdef USE_TIMER
+ kdDebug(26005) << k_funcinfo << " Total time: " << t.elapsed() << endl;
+#endif
+}
+
+CanvasItemList KSVGCanvas::collisions(const QPoint &p, bool exact) const
+{
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ QPoint p2 = mtx.invert().map(p);
+ if(p2.x() < 0 || p2.y() < 0)
+ return CanvasItemList();
+
+ unsigned int x = p2.x() / int(m_chunkSizeHor);
+ unsigned int y = p2.y() / int(m_chunkSizeVer);
+
+ CanvasItemList result;
+ CanvasChunk *chunk = m_chunkManager.getChunk(x, y);
+ if(!chunk)
+ return result;
+
+ CanvasItemList list = chunk->list();
+ if(exact)
+ {
+ for(CanvasItemList::Iterator it = list.begin(); it != list.end(); ++it)
+ {
+ if((*it)->fillContains(p) || (*it)->strokeContains(p) || (*it)->bbox().contains(p))
+ result.append(*it);
+ }
+
+ return result;
+ }
+ else
+ return list;
+}
+
+void KSVGCanvas::blit(const QRect &rect, bool direct)
+{
+ if(m_drawWindow && m_width && m_height)
+ {
+ // clamp to viewport
+ int x0 = rect.x();
+ x0 = QMAX(x0, 0);
+ x0 = QMIN(x0, int(m_width - 1));
+
+ int y0 = rect.y();
+ y0 = QMAX(y0, 0);
+ y0 = QMIN(y0, int(m_height - 1));
+
+ int x1 = rect.x() + rect.width() + 1;
+ x1 = QMAX(x1, 0);
+ x1 = QMIN(x1, int(m_width));
+
+ int y1 = rect.y() + rect.height() + 1;
+ y1 = QMAX(y1, 0);
+ y1 = QMIN(y1, int(m_height));
+
+ xlib_draw_rgb_image(direct ? m_directWindow->handle() : m_drawWindow->handle(), m_gc, x0, y0, x1 - x0, y1 - y0, XLIB_RGB_DITHER_NONE, m_buffer + (m_width * y0 + x0) * m_nrChannels, m_width * m_nrChannels);
+ }
+}
+
+void KSVGCanvas::blit()
+{
+ return blit(QRect(0, 0, m_width, m_height), false);
+}
+
+void KSVGCanvas::ChunkManager::addChunk(CanvasChunk *chunk)
+{
+ QString key = QString("%1 %2").arg(chunk->x()).arg(chunk->y());
+// kdDebug(26005) << k_funcinfo << "Adding chunk : " << chunk << endl;
+ m_chunks.insert(key, chunk);
+}
+
+CanvasChunk *KSVGCanvas::ChunkManager::getChunk(short x, short y) const
+{
+// kdDebug(26005) << k_funcinfo << "getting chunk from : " << x << ", " << y << endl;
+ QString key = QString("%1 %2").arg(x).arg(y);
+ return m_chunks[key];
+}
+
+void KSVGCanvas::ChunkManager::clear()
+{
+ m_chunks.clear();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGCanvas.h b/ksvg/core/KSVGCanvas.h
new file mode 100644
index 00000000..7b26997c
--- /dev/null
+++ b/ksvg/core/KSVGCanvas.h
@@ -0,0 +1,190 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGCANVAS_H
+#define KSVGCANVAS_H
+
+#include <qmap.h>
+#include <qdict.h>
+#include <qcolor.h>
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qdict.h>
+
+#include <Converter.h>
+
+namespace KSVG
+{
+
+class SVGShapeImpl;
+class SVGMatrixImpl;
+class SVGStylableImpl;
+class SVGElementImpl;
+class SVGTextElementImpl;
+class SVGRectElementImpl;
+class SVGLineElementImpl;
+class SVGPathElementImpl;
+class SVGImageElementImpl;
+class SVGCircleElementImpl;
+class SVGMarkerElementImpl;
+class SVGEllipseElementImpl;
+class SVGPolygonElementImpl;
+class SVGPolylineElementImpl;
+class SVGClipPathElementImpl;
+
+class CanvasItem;
+class CanvasChunk;
+class CanvasItemList;
+class CanvasClipPath;
+class CanvasPaintServer;
+
+// Must be a QObject to be able to be loaded by KLibLoader...
+class KSVGCanvas : public QObject
+{
+Q_OBJECT
+public:
+ KSVGCanvas(unsigned int width, unsigned int height);
+ virtual ~KSVGCanvas();
+
+ void setViewportDimension(unsigned int w, unsigned int h);
+
+ void setup(QPaintDevice *drawWidget, QPaintDevice *directWindow);
+ void setup(unsigned char *buffer, unsigned int width = 0, unsigned int height = 0);
+
+ void reset();
+ void update();
+ void update(float zoomFactor);
+ void update(const QPoint &panPoint, bool erase = true);
+ void resize(unsigned int w, unsigned int h);
+ void retune(unsigned int csh, unsigned int csv);
+ void invalidate(CanvasItem *item, bool recalc = true);
+ CanvasItemList collisions(const QPoint &p, bool exact = false) const;
+
+ void setBackgroundColor(const QColor &c) { m_backgroundColor = c; }
+ void blit();
+ void blit(const QRect &rect, bool direct);
+
+ float zoom() const { return m_zoom; }
+ QPoint pan() const { return m_pan; }
+ void setPan(const QPoint &pan) { m_pan = pan; }
+
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+
+ virtual void setRenderBufferSize(int w, int h);
+ void clipToBuffer(int &x0, int &y0, int &x1, int &y1) const;
+
+ // creating canvas items
+ virtual CanvasItem *createRectangle(SVGRectElementImpl *rect) = 0;
+ virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse) = 0;
+ virtual CanvasItem *createCircle(SVGCircleElementImpl *circle) = 0;
+ virtual CanvasItem *createLine(SVGLineElementImpl *line) = 0;
+ virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly) = 0;
+ virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly) = 0;
+ virtual CanvasItem *createPath(SVGPathElementImpl *path) = 0;
+ virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath) = 0;
+ virtual CanvasItem *createImage(SVGImageElementImpl *image) = 0;
+ virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker) = 0;
+ virtual CanvasItem *createText(SVGTextElementImpl *text) = 0;
+ virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver) = 0;
+
+ void insert(CanvasItem *item, int z = -1);
+ void removeItem(CanvasItem *);
+
+ // Enable to have the canvas updated and blitted on item insertion.
+ void setImmediateUpdate(bool immediateUpdate) { m_immediateUpdate = immediateUpdate; }
+ bool immediateUpdate() const { return m_immediateUpdate; }
+
+ QPtrList<CanvasItem> allItems() const { return m_items; }
+
+ unsigned char *renderingBuffer() const { return m_buffer; }
+ unsigned int nrChannels() const { return m_nrChannels; }
+ unsigned int rowStride() const { return m_nrChannels * m_width; }
+
+ T2P::Converter *fontContext() { return m_fontContext; }
+ QPaintDevice *drawWindow() { return m_drawWindow; }
+ QPaintDevice *directWindow() { return m_directWindow; }
+
+ T2P::FontVisualParams *fontVisualParams(SVGStylableImpl *style) const;
+ virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const { Q_UNUSED(item); return 0; }
+
+ // Assign z indices to the element and its children, starting with z, and
+ // return the next z value to be used.
+ unsigned int setElementItemZIndexRecursive(SVGElementImpl *element, unsigned int z);
+
+protected:
+ void addToChunks(CanvasItem *item);
+ void removeFromChunks(CanvasItem *item);
+
+ void initVars();
+
+ void fill();
+ void clear(const QRect &r);
+
+ virtual void setBuffer(unsigned char *buffer);
+
+protected:
+ class ChunkManager
+ {
+ public:
+ ChunkManager() { m_chunks.setAutoDelete(true); }
+ void addChunk(CanvasChunk *chunk);
+ CanvasChunk *getChunk(short x, short y) const;
+
+ void clear();
+
+ private:
+ QDict<CanvasChunk> m_chunks;
+ } m_chunkManager;
+
+ QValueList<CanvasChunk *> m_dirtyChunks;
+
+ QMap<CanvasItem *, QPtrList<CanvasChunk> > m_chunksByItem;
+ QPtrList<CanvasItem> m_items;
+
+ QDict<CanvasClipPath> m_clipPaths;
+
+ unsigned int m_viewportWidth, m_viewportHeight;
+ int m_width, m_height;
+ int m_chunkSizeHor, m_chunkSizeVer;
+
+ QPaintDevice *m_drawWindow;
+ QPaintDevice *m_directWindow;
+
+ float m_zoom;
+ QPoint m_pan;
+
+ GC m_gc;
+
+ T2P::Converter *m_fontContext;
+
+ unsigned char *m_buffer;
+ unsigned int m_nrChannels;
+
+ QColor m_backgroundColor;
+
+ bool m_immediateUpdate;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGHelper.cpp b/ksvg/core/KSVGHelper.cpp
new file mode 100644
index 00000000..86d111a6
--- /dev/null
+++ b/ksvg/core/KSVGHelper.cpp
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include "KSVGHelper.h"
+
+using namespace KSVG;
+
+bool KSVGHelper::m_initialised = false;
+
+int KSVGHelper::m_linearRGBFromsRGB[256];
+int KSVGHelper::m_sRGBFromLinearRGB[256];
+
+// Force initialisation of the lookup tables
+static KSVGHelper ksvgHelper;
+
+KSVGHelper::KSVGHelper()
+{
+ if(!m_initialised)
+ {
+ initialise();
+ m_initialised = true;
+ }
+}
+
+void KSVGHelper::initialise()
+{
+ // Set up linearRGB - sRGB conversion tables
+ for(int i = 0; i < 256; i++)
+ {
+ m_linearRGBFromsRGB[i] = calcLinearRGBFromsRGB(i);
+ m_sRGBFromLinearRGB[i] = calcSRGBFromLinearRGB(i);
+ }
+}
+
+int KSVGHelper::calcLinearRGBFromsRGB(int sRGB8bit)
+{
+ double sRGB = sRGB8bit / 255.0;
+ double linearRGB;
+
+ if(sRGB <= 0.04045)
+ linearRGB = sRGB / 12.92;
+ else
+ linearRGB = pow((sRGB + 0.055) / 1.055, 2.4);
+
+ return static_cast<int>(linearRGB * 255 + 0.5);
+}
+
+int KSVGHelper::calcSRGBFromLinearRGB(int linearRGB8bit)
+{
+ double linearRGB = linearRGB8bit / 255.0;
+ double sRGB;
+
+ if(linearRGB <= 0.0031308)
+ sRGB = linearRGB * 12.92;
+ else
+ sRGB = 1.055 * pow(linearRGB, 1 / 2.4) - 0.055;
+
+ return static_cast<int>(sRGB * 255 + 0.5);
+}
+
+extern "C"
+int linearRGBFromsRGB(int sRGB8bit)
+{
+ return KSVGHelper::linearRGBFromsRGB(sRGB8bit);
+}
+
+extern "C"
+int sRGBFromLinearRGB(int linearRGB8bit)
+{
+ return KSVGHelper::sRGBFromLinearRGB(linearRGB8bit);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGHelper.h b/ksvg/core/KSVGHelper.h
new file mode 100644
index 00000000..e310889f
--- /dev/null
+++ b/ksvg/core/KSVGHelper.h
@@ -0,0 +1,144 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGHelper_H
+#define KSVGHelper_H
+
+#ifdef __cplusplus
+
+#include <qcolor.h>
+#include <qvaluevector.h>
+#include "Affine.h"
+#include "Point.h"
+#include "SVGMatrixImpl.h"
+
+namespace KSVG
+{
+
+class KSVGHelper
+{
+public:
+ KSVGHelper();
+
+ static void matrixToAffine(SVGMatrixImpl *matrix, double affine[6])
+ {
+ affine[0] = matrix->a();
+ affine[1] = matrix->b();
+ affine[2] = matrix->c();
+ affine[3] = matrix->d();
+ affine[4] = matrix->e();
+ affine[5] = matrix->f();
+ }
+
+ static void matrixToAffine(const SVGMatrixImpl *matrix, double affine[6])
+ {
+ KSVGHelper::matrixToAffine(const_cast<SVGMatrixImpl *>(matrix), affine);
+ }
+
+ static void matrixToAffine(const SVGMatrixImpl *matrix, T2P::Affine &affine)
+ {
+ KSVGHelper::matrixToAffine(const_cast<SVGMatrixImpl *>(matrix), affine.data());
+ }
+
+ static void matrixToAffine(SVGMatrixImpl *matrix, T2P::Affine &affine)
+ {
+ KSVGHelper::matrixToAffine(matrix, affine.data());
+ }
+
+ static QString toColorString(QColor color)
+ {
+ int r = color.red();
+ int g = color.green();
+ int b = color.blue();
+
+ return "rgb(" + QString::number(r) + "," + QString::number(g) + "," + QString::number(b) + ")";
+ }
+
+ static unsigned int toArtColor(const QColor &color)
+ {
+ return (qRed(color.rgb()) << 24) | (qGreen(color.rgb()) << 16) | ( qBlue(color.rgb()) << 8) | (qAlpha(color.rgb()));
+ }
+
+ static unsigned int toArtColor(const QColor &color, short opacity)
+ {
+ return (qRed(color.rgb()) << 24) | (qGreen(color.rgb()) << 16) | ( qBlue(color.rgb()) << 8) | (opacity);
+ }
+
+ static int linearRGBFromsRGB(int sRGB8bit) { return m_linearRGBFromsRGB[sRGB8bit]; }
+ static int sRGBFromLinearRGB(int linearRGB8bit) { return m_sRGBFromLinearRGB[linearRGB8bit]; }
+
+private:
+ static void initialise();
+ static int calcLinearRGBFromsRGB(int sRGB8bit);
+ static int calcSRGBFromLinearRGB(int linearRGB8bit);
+
+ static bool m_initialised;
+
+ static int m_linearRGBFromsRGB[256];
+ static int m_sRGBFromLinearRGB[256];
+};
+
+typedef T2P::Point KSVGPoint;
+
+class KSVGPolygon
+{
+public:
+ KSVGPolygon() {}
+
+ void addPoint(const KSVGPoint& point) { m_points.append(point); }
+ void addPoint(double x, double y) { m_points.append(KSVGPoint(x, y)); }
+
+ KSVGPoint point(unsigned int index) const { return index < m_points.count() ? m_points[index] : KSVGPoint(); }
+
+ unsigned int numPoints() const { return m_points.count(); }
+ bool isEmpty() const { return m_points.isEmpty(); }
+
+ void clear() { m_points.clear(); }
+
+private:
+ QValueVector<KSVGPoint> m_points;
+};
+
+class KSVGRectangle : public KSVGPolygon
+{
+public:
+ KSVGRectangle() { addPoint(0, 0); addPoint(0, 0); addPoint(0, 0); addPoint(0, 0); }
+
+ // Convenience constructor for an axis-aligned rectangle
+ KSVGRectangle(double x, double y, double width, double height)
+ { addPoint(KSVGPoint(x, y)); addPoint(KSVGPoint(x, y + height)); addPoint(KSVGPoint(x + width, y + height)); addPoint(KSVGPoint(x + width, y)); }
+
+};
+}
+
+extern "C"
+{
+#endif // __cplusplus
+
+int linearRGBFromsRGB(int sRGB8bit);
+int sRGBFromLinearRGB(int linearRGB8bit);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGLoader.cpp b/ksvg/core/KSVGLoader.cpp
new file mode 100644
index 00000000..7f7591d7
--- /dev/null
+++ b/ksvg/core/KSVGLoader.cpp
@@ -0,0 +1,449 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qxml.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qbuffer.h>
+
+#include <kurl.h>
+#include <kdebug.h>
+#include <kio/job.h>
+#include <kfilterdev.h>
+#include <kio/netaccess.h>
+
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGImageElementImpl.h"
+
+#include "KSVGLoader.moc"
+
+using namespace KSVG;
+
+KSVGLoader::KSVGLoader() : m_data(0)
+{
+ m_job = 0;
+}
+
+KSVGLoader::~KSVGLoader()
+{
+}
+
+QString KSVGLoader::loadXML(::KURL url)
+{
+ QString tmpFile;
+ if(KIO::NetAccess::download(url, tmpFile, 0))
+ {
+ QIODevice *dev = KFilterDev::deviceForFile(tmpFile, "application/x-gzip", true);
+ QByteArray contents;
+ if(dev->open(IO_ReadOnly))
+ contents = dev->readAll();
+ delete dev;
+ KIO::NetAccess::removeTempFile(tmpFile);
+ return QString(contents);
+ }
+
+ return QString::null;
+}
+
+void KSVGLoader::getSVGContent(::KURL url)
+{
+ if(!url.prettyURL().isEmpty())
+ {
+ if(m_job == 0)
+ m_job = KIO::get(url, false, false);
+
+ m_job->setAutoErrorHandlingEnabled(true);
+
+ connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &)));
+ connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *)));
+ }
+}
+
+void KSVGLoader::newImageJob(SVGImageElementImpl *image, ::KURL baseURL)
+{
+ if(image && image->fileName().isEmpty())
+ {
+ kdDebug(26001) << "Image Element has no URL!" << endl;
+ return;
+ }
+
+ ImageStreamMap *map = new ImageStreamMap();
+ map->data = new QByteArray();
+ map->imageElement = image;
+
+ KIO::TransferJob *imageJob = KIO::get(::KURL(baseURL, map->imageElement->fileName()), false, false);
+ connect(imageJob, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &)));
+ connect(imageJob, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *)));
+
+ m_imageJobs.insert(imageJob, map);
+}
+
+void KSVGLoader::slotData(KIO::Job *job, const QByteArray &data)
+{
+ if(job == m_job)
+ {
+ QDataStream dataStream(m_data, IO_WriteOnly | IO_Append);
+ dataStream.writeRawBytes(data.data(), data.size());
+ }
+ else
+ {
+ QMap<KIO::TransferJob *, ImageStreamMap *>::Iterator it;
+ for(it = m_imageJobs.begin(); it != m_imageJobs.end(); ++it)
+ {
+ if(it.key() == job)
+ {
+ QDataStream dataStream(*(it.data())->data, IO_WriteOnly | IO_Append);
+ dataStream.writeRawBytes(data.data(), data.size());
+ break;
+ }
+ }
+ }
+}
+
+void KSVGLoader::slotResult(KIO::Job *job)
+{
+ if(job == m_job)
+ {
+ if(m_job->error() == 0)
+ {
+ QString check = static_cast<KIO::TransferJob *>(job)->url().prettyURL();
+ if(check.contains(".svgz") || check.contains(".svg.gz"))
+ {
+ // decode the gzipped svg and emit it
+ QIODevice *dev = KFilterDev::device(new QBuffer(m_data), "application/x-gzip");
+ dev->open(IO_ReadOnly);
+ emit gotResult(dev);
+ }
+ else
+ {
+ m_job = 0;
+ emit gotResult(new QBuffer(m_data));
+ m_data.resize(0);
+ }
+ }
+ }
+ else if(m_postUrlData.job == job)
+ {
+ // Notify that we're done
+ KJS::List callBackArgs;
+ callBackArgs.append(*m_postUrlData.status);
+
+ m_postUrlData.status->put(m_postUrlData.exec, KJS::Identifier("success"), KJS::Boolean(true));
+ m_postUrlData.callBackFunction->call(m_postUrlData.exec, *m_postUrlData.callBackFunction, callBackArgs);
+ }
+ else
+ {
+ QMap<KIO::TransferJob *, ImageStreamMap *>::Iterator it;
+ for(it = m_imageJobs.begin(); it != m_imageJobs.end(); ++it)
+ {
+ if(it.key() == job)
+ {
+ ImageStreamMap *streamMap = it.data();
+
+ QBuffer buffer(*(streamMap->data));
+
+ if(buffer.open(IO_ReadOnly))
+ {
+ const char *imageFormat = QImageIO::imageFormat(&buffer);
+
+ if(imageFormat != 0)
+ {
+ QImageIO imageIO(&buffer, imageFormat);
+
+ // Gamma correction
+ imageIO.setGamma(1/0.45454);
+
+ if(imageIO.read())
+ {
+ QImage *image = new QImage(imageIO.image());
+ image->detach();
+ (streamMap->imageElement)->setImage(image);
+ }
+ }
+
+ buffer.close();
+ }
+
+ (streamMap->data)->resize(0);
+
+ m_imageJobs.remove(static_cast<KIO::TransferJob *>(job));
+
+ emit imageReady(streamMap->imageElement);
+ break;
+ }
+ }
+ }
+}
+
+QString KSVGLoader::getUrl(::KURL url, bool local)
+{
+ // Security issue: Only retrieve http and https
+ if(local || (!url.prettyURL().isEmpty()) && ((url.protocol() == "http") || (url.protocol() == "https")))
+ return loadXML(url);
+
+ return QString::null;
+}
+
+void KSVGLoader::postUrl(::KURL url, const QByteArray &data, const QString &mimeType, KJS::ExecState *exec, KJS::Object &callBackFunction, KJS::Object &status)
+{
+ KIO::TransferJob *job = KIO::http_post(url, data, false);
+ job->addMetaData("content-type", mimeType);
+
+ m_postUrlData.job = job;
+ m_postUrlData.exec = exec;
+ m_postUrlData.status = &status;
+ m_postUrlData.callBackFunction = &callBackFunction;
+
+ connect(job, SIGNAL(result(KIO::Job *)), SLOT(slotResult(KIO::Job *)));
+}
+
+class CharacterDataSearcher : public QXmlDefaultHandler
+{
+public:
+ CharacterDataSearcher(const QString &id) : m_id(id) { }
+
+ virtual bool startDocument()
+ {
+ m_foundCount = 0;
+ return true;
+ }
+
+ virtual bool startElement(const QString &, const QString &, const QString &qName, const QXmlAttributes &atts)
+ {
+ kdDebug(26001) << "CharacterDataSearcher::startElement, qName " << qName << endl;
+
+ int pos = atts.index("id");
+ if(pos > -1 && atts.value(pos) == m_id)
+ {
+ m_foundCount++;
+ m_tagFound = qName;
+ }
+
+ return true;
+ }
+
+ virtual bool endElement(const QString &, const QString &, const QString &qName)
+ {
+ if(m_tagFound == qName && m_foundCount > 0)
+ {
+ m_foundCount--;
+ if(m_foundCount == 0)
+ return false; // done!
+ }
+
+ return true;
+ }
+
+ virtual bool characters(const QString &ch)
+ {
+ kdDebug(26001) << "CharacterDataSearcher::characters, read " << ch.latin1() << endl;
+
+ if(m_tagFound != 0)
+ m_result += ch;
+
+ return true;
+ }
+
+ QString result() { return m_result; }
+
+private:
+ QString m_id, m_result, m_tagFound;
+ int m_foundCount;
+};
+
+QString KSVGLoader::getCharacterData(::KURL url, const QString &id)
+{
+ QXmlSimpleReader reader;
+
+ CharacterDataSearcher searcher(id);
+ reader.setContentHandler(&searcher);
+ reader.setErrorHandler(&searcher);
+
+ QString s = loadXML(url);
+
+ QXmlInputSource source;
+ source.setData(s);
+
+ reader.parse(&source);
+
+ return searcher.result();
+}
+
+
+
+class SVGFragmentSearcher : public QXmlDefaultHandler
+{
+public:
+ SVGFragmentSearcher(SVGDocumentImpl *doc, const QString &id, ::KURL url) : m_id(id), m_url(url), m_doc(doc) { }
+
+ virtual bool startDocument()
+ {
+ m_result = 0;
+ m_currentNode = 0;
+
+ return true;
+ }
+
+ virtual bool startElement(const QString &namespaceURI, const QString &, const QString &qName, const QXmlAttributes &attrs)
+ {
+ kdDebug(26001) << "SVGFragmentSearcher::startElement, namespaceURI " << namespaceURI << ", qName " << qName << endl;
+ bool parse = m_result;
+ if(!parse)
+ {
+ int pos = attrs.index("id");
+ if(pos > -1 && attrs.value(pos) == m_id)
+ parse = true;
+ }
+
+ if(parse)
+ {
+ DOM::Element impl = static_cast<DOM::Document *>(m_doc)->createElementNS(namespaceURI, qName);
+ SVGElementImpl *newElement = SVGDocumentImpl::createElement(qName, impl, m_doc);
+ newElement->setViewportElement(m_doc->rootElement());
+
+ if(m_currentNode)
+ m_currentNode->appendChild(*newElement);
+ else
+ m_result = newElement;
+
+ QXmlAttributes newAttrs;
+
+ for(int i = 0; i < attrs.count(); i++)
+ {
+ QString name = attrs.localName(i);
+ QString value = attrs.value(i);
+
+ if(name == "id")
+ {
+ value = "@fragment@" + m_url.prettyURL() + "@" + value;
+ m_idMap[value] = newElement;
+ }
+ else
+ if(name == "href")
+ {
+ value.stripWhiteSpace();
+
+ if(value.startsWith("#"))
+ {
+ value.remove(0, 1);
+
+ // Convert the id to its mangled version.
+ QString id = "@fragment@" + m_url.prettyURL() + "@" + value;
+
+ if(m_idMap.contains(id))
+ {
+ // This is a local reference to an element within the fragment.
+ // Just convert the href.
+ value = id;
+ }
+ else
+ {
+ // This is a local reference to an id outside of the fragment.
+ // Change it into an absolute href.
+ value = m_url.prettyURL() + "#" + value;
+ }
+ }
+ }
+
+ newAttrs.append(attrs.qName(i), attrs.uri(i), attrs.localName(i), value);
+ }
+
+ newElement->setAttributes(newAttrs);
+ m_currentNode = newElement;
+ }
+
+ return true;
+ }
+
+ virtual bool endElement(const QString &, const QString &, const QString &)
+ {
+ if(m_result)
+ {
+ m_parentNode = m_currentNode->parentNode();
+
+ if(m_parentNode.isNull())
+ return false; // done!
+
+ m_currentNode = &m_parentNode;
+ }
+
+ return true;
+ }
+
+ virtual bool characters(const QString &ch)
+ {
+ kdDebug(26001) << "SVGFragmentSearcher::characters, read " << ch.latin1() << endl;
+
+ if(m_result)
+ {
+ SVGElementImpl *element = m_result->ownerDoc()->getElementFromHandle(m_currentNode->handle());
+ if(element)
+ {
+ QString t = ch;
+
+ SVGLangSpaceImpl *langSpace = dynamic_cast<SVGLangSpaceImpl *>(element);
+ if(langSpace)
+ t = langSpace->handleText(ch);
+
+ if(!t.isEmpty())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(m_result->ownerDoc())->createTextNode(t);
+ element->appendChild(impl);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ SVGElementImpl *result() { return m_result; }
+
+private:
+ QString m_id;
+ ::KURL m_url;
+
+ SVGDocumentImpl *m_doc;
+ SVGElementImpl *m_result;
+
+ DOM::Node *m_currentNode, m_parentNode;
+ QMap<QString, SVGElementImpl *> m_idMap;
+};
+
+SVGElementImpl *KSVGLoader::getSVGFragment(::KURL url, SVGDocumentImpl *doc, const QString &id)
+{
+ QXmlSimpleReader reader;
+
+ kdDebug(26001) << "getSVGFragment: " << url.prettyURL() << "#" << id << endl;
+ SVGFragmentSearcher searcher(doc, id, url);
+ reader.setContentHandler(&searcher);
+ reader.setErrorHandler(&searcher);
+
+ QString s = loadXML(url);
+
+ QXmlInputSource source;
+ source.setData(s);
+
+ reader.parse(&source);
+
+ return searcher.result();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGLoader.h b/ksvg/core/KSVGLoader.h
new file mode 100644
index 00000000..d0418411
--- /dev/null
+++ b/ksvg/core/KSVGLoader.h
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGLoader_H
+#define KSVGLoader_H
+
+#include <qobject.h>
+
+class KURL;
+
+namespace KIO
+{
+ class Job;
+ class TransferJob;
+}
+
+namespace KJS
+{
+ class Object;
+ class ExecState;
+}
+
+namespace KSVG
+{
+
+struct ImageStreamMap;
+
+typedef struct
+{
+ KIO::Job *job;
+ KJS::ExecState *exec;
+ KJS::Object *callBackFunction, *status;
+} PostUrlData;
+
+class SVGImageElementImpl;
+class SVGElementImpl;
+class SVGDocumentImpl;
+class KSVGLoader : public QObject
+{
+Q_OBJECT
+public:
+ KSVGLoader();
+ ~KSVGLoader();
+
+ void getSVGContent(::KURL url);
+ void newImageJob(SVGImageElementImpl *impl, ::KURL url);
+
+ static QString getUrl(::KURL url, bool local = false);
+ void postUrl(::KURL url, const QByteArray &data, const QString &mimeType, KJS::ExecState *exec, KJS::Object &callBackFunction, KJS::Object &status);
+ static QString getCharacterData(::KURL url, const QString &id);
+ static SVGElementImpl *getSVGFragment(::KURL, SVGDocumentImpl *doc, const QString &id);
+
+signals:
+ void gotResult(QIODevice *);
+ void imageReady(SVGImageElementImpl *);
+
+private slots:
+ void slotData(KIO::Job *, const QByteArray &);
+ void slotResult(KIO::Job *);
+
+private:
+ static QString loadXML(::KURL);
+
+ PostUrlData m_postUrlData;
+
+ QByteArray m_data;
+ KIO::TransferJob *m_job;
+ QMap<KIO::TransferJob *, ImageStreamMap *> m_imageJobs;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGReader.cc b/ksvg/core/KSVGReader.cc
new file mode 100644
index 00000000..dd73e420
--- /dev/null
+++ b/ksvg/core/KSVGReader.cc
@@ -0,0 +1,500 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dom/dom_exception.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qmap.h>
+#include <ksimpleconfig.h>
+#include <KSVGCanvas.h>
+#include "KSVGReader.moc"
+#include "SVGSVGElementImpl.h"
+#include "SVGViewSpecImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGLengthImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGUseElementImpl.h"
+
+namespace KSVG
+{
+
+class Helper
+{
+public:
+ static Helper *self(KSVGReader *reader = 0);
+
+ void destroy();
+
+ void setFit(bool bFit = true) { m_bFit = bFit; }
+ bool fit() { return m_bFit; }
+
+ SVGDocumentImpl *doc() const { return m_reader->doc(); }
+ KSVGCanvas *canvas() const { return m_reader->canvas(); }
+
+ void addSVGElement(SVGSVGElementImpl *one, DOM::NodeImpl *two) { m_svgMap.insert(two, one); }
+ SVGSVGElementImpl *nextSVGElement(SVGElementImpl *elem);
+ SVGSVGElementImpl *nextSVGElement(DOM::Node elem);
+ void setFinished(bool error, const QString &errorDesc = "") { m_reader->setFinished(error, errorDesc); }
+
+ // Error handling
+ void setErrorDescription(const QString &err) { m_errorDesc = err; }
+ QString errorDescription() { return m_errorDesc; }
+ bool hasError() const { return !m_errorDesc.isEmpty(); }
+
+ bool getURLMode() const { return m_getURLMode; }
+ void setGetURLMode(bool mode) { m_getURLMode = mode; }
+
+ QString SVGFragmentId() const { return m_SVGFragmentId; }
+ void setSVGFragmentId(const QString &SVGFragmentId) { m_SVGFragmentId = SVGFragmentId; }
+
+protected:
+ Helper(KSVGReader *reader);
+
+private:
+ Helper();
+ Helper(const Helper &rhs);
+ Helper &operator=(const Helper &rhs);
+
+ static Helper *m_instance;
+ QMap<DOM::NodeImpl *, SVGSVGElementImpl *> m_svgMap;
+ KSVGReader *m_reader;
+ bool m_bFit;
+ bool m_getURLMode;
+ QString m_errorDesc;
+ QString m_SVGFragmentId;
+};
+
+class InputHandler : public QXmlDefaultHandler
+{
+public:
+ virtual bool startDocument();
+ virtual bool endDocument();
+ virtual bool startElement(const QString &namespaceURI,
+ const QString &localName,
+ const QString &qName,
+ const QXmlAttributes &atts);
+ virtual bool endElement(const QString &namespaceURI,
+ const QString &localName,
+ const QString &qName);
+ virtual bool characters(const QString &ch);
+ virtual bool warning(const QXmlParseException &e);
+ virtual bool error(const QXmlParseException &e);
+ virtual bool fatalError(const QXmlParseException &e);
+
+private:
+ DOM::Node *m_rootNode;
+ DOM::Node *m_currentNode;
+ DOM::Node m_parentNode;
+
+ bool m_noRendering, m_progressive;
+};
+
+}
+
+using namespace KSVG;
+
+Helper *Helper::m_instance = 0;
+
+Helper::Helper(KSVGReader *reader)
+{
+ m_reader = reader;
+}
+
+Helper *Helper::self(KSVGReader *reader)
+{
+ if(m_instance && reader != 0)
+ m_instance->m_reader = reader;
+ if(!m_instance)
+ {
+ Q_ASSERT(reader != 0);
+ m_instance = new Helper(reader);
+ }
+
+ return m_instance;
+}
+
+void Helper::destroy()
+{
+ m_svgMap.clear();
+}
+
+SVGSVGElementImpl *Helper::nextSVGElement(SVGElementImpl *elem)
+{
+ return nextSVGElement(*elem);
+}
+
+SVGSVGElementImpl *Helper::nextSVGElement(DOM::Node elem)
+{
+ DOM::Node foundSVG;
+ DOM::Node shape = elem.parentNode();
+
+ for(; !shape.isNull(); shape = shape.parentNode())
+ {
+ if(reinterpret_cast<DOM::Element &>(shape).nodeName() == "svg")
+ {
+ foundSVG = shape;
+ break;
+ }
+ }
+
+ SVGSVGElementImpl *svg = m_svgMap[foundSVG.handle()];
+ return svg;
+}
+
+bool InputHandler::startDocument()
+{
+ m_rootNode = 0;
+ m_currentNode = 0;
+ m_noRendering = false;
+
+ KSimpleConfig config("ksvgpluginrc");
+ config.setGroup("Rendering");
+ m_progressive = config.readBoolEntry("ProgressiveRendering", true);
+
+ if(Helper::self()->canvas())
+ Helper::self()->canvas()->setImmediateUpdate(m_progressive);
+
+ return true;
+}
+
+bool InputHandler::endDocument()
+{
+ Helper::self()->setFinished(false);
+ if (Helper::self()->canvas())
+ Helper::self()->canvas()->setImmediateUpdate(false);
+
+ return true;
+}
+
+bool InputHandler::characters(const QString &ch)
+{
+ kdDebug(26001) << "InputHandler::characters, read " << ch << endl;
+
+ if(ch.simplifyWhiteSpace().isEmpty())
+ return true;
+
+ QString t = ch;
+
+ SVGSVGElementImpl *root = Helper::self()->nextSVGElement(*m_currentNode);
+ if(root)
+ {
+ SVGElementImpl *element = root->ownerDoc()->getElementFromHandle(m_currentNode->handle());
+ SVGLangSpaceImpl *langSpace = dynamic_cast<SVGLangSpaceImpl *>(element);
+
+ if(langSpace)
+ t = langSpace->handleText(ch);
+ }
+
+ if(!t.isEmpty())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(Helper::self()->doc())->createTextNode(t);
+ m_currentNode->appendChild(impl);
+ }
+
+ return true;
+}
+
+bool InputHandler::startElement(const QString &namespaceURI, const QString &, const QString &qName, const QXmlAttributes &attrs)
+{
+ kdDebug(26001) << "InputHandler::startElement, namespaceURI " << namespaceURI << " qName " << qName << endl;
+
+ SVGElementImpl *newElement = 0;
+ SVGSVGElementImpl *svg = 0;
+
+ if(qName == "svg")
+ {
+ DOM::Element impl = static_cast<DOM::Document *>(Helper::self()->doc())->createElementNS(namespaceURI, qName);
+ newElement = SVGDocumentImpl::createElement(qName, impl, Helper::self()->doc());
+ svg = dynamic_cast<SVGSVGElementImpl *>(newElement);
+
+ Helper::self()->addSVGElement(svg, impl.handle());
+
+ // Need this before we can find our ownerSVGElement (AP)
+ if(m_currentNode != 0)
+ m_currentNode->appendChild(*svg);
+ else
+ // TODO: Those set/get attribute callls have NO effect anymore
+ // Convert to the new system, Rob? (Niko)
+ {
+ if(Helper::self()->fit())
+ { // handle fitting of svg into small drawing area(thumb)
+ // TODO : aspectratio? and what about svgs that dont provide width and height?
+ if(svg->getAttribute("viewBox").string().isEmpty())
+ {
+ SVGLengthImpl *width = SVGSVGElementImpl::createSVGLength();
+ SVGLengthImpl *height = SVGSVGElementImpl::createSVGLength();
+ width->setValueAsString(svg->getAttribute("width").string());
+ height->setValueAsString(svg->getAttribute("height").string());
+ QString viewbox = QString("0 0 %1 %2").arg(width->value()).arg(height->value());
+ //kdDebug(26001) << "VIEWBOX : " << viewbox.latin1() << endl;
+ svg->setAttribute("viewBox", viewbox);
+ width->deref();
+ height->deref();
+ }
+ svg->setAttribute("width", QString::number(Helper::self()->canvas()->width()));
+ svg->setAttribute("height", QString::number(Helper::self()->canvas()->height()));
+ }
+
+ if(!Helper::self()->SVGFragmentId().isEmpty())
+ {
+ if(svg->currentView()->parseViewSpec(Helper::self()->SVGFragmentId()))
+ svg->setUseCurrentView(true);
+ }
+ }
+
+ if(m_rootNode == 0)
+ {
+ Helper::self()->doc()->appendChild(*svg);
+ Helper::self()->doc()->setRootElement(svg);
+
+ m_rootNode = svg;
+ }
+ }
+ else
+ {
+ if(!m_rootNode && !Helper::self()->getURLMode())
+ {
+ Helper::self()->setErrorDescription(i18n("A legal svg document requires a <svg> root element"));
+ return false;
+ }
+
+ DOM::Element impl = static_cast<DOM::Document *>(Helper::self()->doc())->createElementNS(namespaceURI, qName);
+ newElement = SVGDocumentImpl::createElement(qName, impl, Helper::self()->doc());
+
+ // m_currentNode == 0 if we are dynamically extending the dom (parsexml...)
+ // and the file doesn't have a root element
+ if(m_currentNode != 0)
+ m_currentNode->appendChild(*newElement);
+ else
+ Helper::self()->doc()->appendChild(*newElement);
+
+ // Special logics:
+ if(qName == "switch" || qName == "pattern" || qName == "mask")
+ m_noRendering = true;
+ }
+
+ newElement->setOwnerSVGElement(Helper::self()->nextSVGElement(newElement));
+ newElement->setViewportElement(newElement->ownerSVGElement());
+
+ newElement->setAttributes(attrs);
+
+ if(svg && svg->ownerSVGElement() == 0)
+ {
+ SVGImageElementImpl *parentImage = Helper::self()->doc()->parentImage();
+
+ if(parentImage)
+ {
+ // We're being displayed in a document via an 'image' element. Set
+ // us up to fit into it's rectangle.
+ parentImage->setupSVGElement(svg);
+ }
+ }
+
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(newElement);
+
+ if(locatable)
+ {
+ // Set up the cached screenCTM
+ SVGLocatableImpl *locatableParent = 0;
+ DOM::Node parentNode = newElement->parentNode();
+
+ if(!parentNode.isNull())
+ {
+ SVGElementImpl *parent = Helper::self()->doc()->getElementFromHandle(parentNode.handle());
+
+ if(parent)
+ locatableParent = dynamic_cast<SVGLocatableImpl *>(parent);
+ }
+
+ SVGMatrixImpl *parentMatrix = 0;
+
+ if(locatableParent)
+ parentMatrix = locatableParent->getScreenCTM();
+ else
+ parentMatrix = SVGSVGElementImpl::createSVGMatrix();
+
+ locatable->updateCachedScreenCTM(parentMatrix);
+ parentMatrix->deref();
+ }
+
+ m_currentNode = newElement;
+ return !Helper::self()->hasError();
+}
+
+bool InputHandler::endElement(const QString &, const QString &, const QString &qName)
+{
+ kdDebug(26001) << "InputHandler::endElement, qName " << qName << endl;
+
+ bool haveCanvas = Helper::self()->canvas();
+
+ SVGSVGElementImpl *root = Helper::self()->nextSVGElement(*m_currentNode);
+ SVGElementImpl *element = root ? root->ownerDoc()->getElementFromHandle(m_currentNode->handle()) : Helper::self()->doc()->getElementFromHandle(m_currentNode->handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(element);
+
+ if(qName != "script" && !m_noRendering && !Helper::self()->getURLMode())
+ {
+ if(!root)
+ {
+ if(haveCanvas)
+ {
+ if(!m_progressive)
+ Helper::self()->canvas()->update();
+
+ Helper::self()->canvas()->blit();
+
+ QValueList<SVGUseElementImpl *> forwardReferencingUseElements = Helper::self()->doc()->forwardReferencingUseElements();
+
+ if(!forwardReferencingUseElements.isEmpty())
+ {
+ // Create the elements again now that we have parsed the whole document.
+ QValueList<SVGUseElementImpl *>::iterator it;
+
+ Helper::self()->canvas()->setImmediateUpdate(false);
+
+ for(it = forwardReferencingUseElements.begin(); it != forwardReferencingUseElements.end(); it++)
+ (*it)->createItem(Helper::self()->canvas());
+
+ // The newly created items will need to be moved into their correct z-order positions.
+ Helper::self()->doc()->resortZIndicesOnFinishedLoading();
+ }
+ }
+
+ return true; // we have reached the bottom
+ }
+
+ if(haveCanvas && (tests ? tests->ok() : true))
+ {
+ if((shape && !shape->isContainer()) || (!shape && element))
+ element->createItem();
+ }
+ }
+
+ // Special logics:
+ if(qName == "switch" || qName == "pattern" || qName == "mask")
+ {
+ m_noRendering = false;
+ bool ok = tests ? tests->ok() : true;
+
+ if(haveCanvas && element && style && ok && style->getDisplay() && style->getVisible() && qName == "pattern" || (shape && shape->directRender()))
+ element->createItem();
+ }
+
+ m_parentNode = m_currentNode->parentNode(); // this is needed since otherwise we get temporary vars
+ m_currentNode = &m_parentNode;
+
+ return true;
+}
+
+bool InputHandler::warning(const QXmlParseException &e)
+{
+ kdDebug(26001) << "[" << e.lineNumber() << ":" << e.columnNumber() << "]: WARNING: " << e.message() << endl;
+ return true;
+}
+
+bool InputHandler::error(const QXmlParseException &e)
+{
+ kdDebug(26001) << "[" << e.lineNumber() << ":" << e.columnNumber() << "]: ERROR: " << e.message() << endl;
+ return true;
+}
+
+bool InputHandler::fatalError(const QXmlParseException &e)
+{
+ QString error;
+
+ if(Helper::self()->hasError())
+ {
+ error = Helper::self()->errorDescription();
+ Helper::self()->setErrorDescription(QString::null);
+ }
+ else
+ error = QString("[%1:%2]: FATAL ERROR: %3").arg(e.lineNumber()).arg(e.columnNumber()).arg(e.message());
+
+ kdDebug(26001) << "InputHandler::fatalError, " << error << endl;
+
+ Helper::self()->setFinished(true, error);
+ return true;
+}
+
+struct KSVGReader::Private
+{
+ QXmlSimpleReader *reader;
+ InputHandler *inputHandler;
+ SVGDocumentImpl *doc;
+ KSVGCanvas *canvas;
+};
+
+KSVGReader::KSVGReader(SVGDocumentImpl *doc, KSVGCanvas *canvas, ParsingArgs args) : QObject(), d(new Private)
+{
+ d->doc = doc;
+ d->canvas = canvas;
+
+ d->reader = new QXmlSimpleReader();
+ d->inputHandler = new InputHandler();
+
+ Helper::self(this);
+ Helper::self()->setFit(args.fit);
+ Helper::self()->setGetURLMode(args.getURLMode);
+ Helper::self()->setSVGFragmentId(args.SVGFragmentId);
+
+ d->reader->setContentHandler(d->inputHandler);
+ d->reader->setErrorHandler(d->inputHandler);
+}
+
+KSVGReader::~KSVGReader()
+{
+ Helper::self()->destroy();
+
+ delete d->reader;
+ delete d->inputHandler;
+ delete d;
+}
+
+void KSVGReader::parse(QXmlInputSource *source)
+{
+ d->reader->parse(source);
+}
+
+void KSVGReader::finishParsing(bool, const QString &errorDesc)
+{
+ Helper::self()->setErrorDescription(errorDesc);
+}
+
+void KSVGReader::setFinished(bool error, const QString &errorDesc)
+{
+ kdDebug(26001) << "KSVGReader::setFinished" << endl;
+ emit finished(error, errorDesc);
+}
+
+SVGDocumentImpl *KSVGReader::doc()
+{
+ return d->doc;
+}
+
+KSVG::KSVGCanvas *KSVGReader::canvas()
+{
+ return d->canvas;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGReader.h b/ksvg/core/KSVGReader.h
new file mode 100644
index 00000000..722720e1
--- /dev/null
+++ b/ksvg/core/KSVGReader.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGReader_H
+#define KSVGReader_H
+
+#include <qxml.h>
+#include <qobject.h>
+
+namespace KSVG
+{
+
+class SVGDocumentImpl;
+class KSVGReader : public QObject
+{
+Q_OBJECT
+public:
+ struct ParsingArgs
+ {
+ bool fit;
+ bool getURLMode;
+
+ QString SVGFragmentId;
+ };
+
+ KSVGReader(SVGDocumentImpl *doc, KSVGCanvas *canvas, ParsingArgs args);
+ virtual ~KSVGReader();
+
+ void parse(QXmlInputSource *source);
+ void finishParsing(bool, const QString &);
+
+signals:
+ void finished(bool, const QString &);
+
+protected:
+ friend class Helper;
+
+ SVGDocumentImpl *doc();
+ KSVGCanvas *canvas();
+
+ void setFinished(bool error, const QString &errorDesc = 0);
+
+private:
+ struct Private;
+ Private *d;
+};
+
+}
+
+#endif
diff --git a/ksvg/core/KSVGTextChunk.cpp b/ksvg/core/KSVGTextChunk.cpp
new file mode 100644
index 00000000..b8eddcad
--- /dev/null
+++ b/ksvg/core/KSVGTextChunk.cpp
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTextContentElementImpl.h"
+#include "SVGTextPositioningElementImpl.h"
+#include "KSVGTextChunk.h"
+
+using namespace KSVG;
+
+// Text chunks (class to store text data)
+KSVGTextChunk::KSVGTextChunk()
+{
+}
+
+KSVGTextChunk::~KSVGTextChunk()
+{
+}
+
+unsigned int KSVGTextChunk::count() const
+{
+ return m_text.count();
+}
+
+QString KSVGTextChunk::getText(unsigned int index) const
+{
+ return m_text[index];
+}
+
+SVGTextPositioningElementImpl *KSVGTextChunk::getTextElement(unsigned int index)
+{
+ SVGTextContentElementImpl *content = getTextContentElement(index);
+ return dynamic_cast<SVGTextPositioningElementImpl *>(content);
+}
+
+SVGTextContentElementImpl *KSVGTextChunk::getTextContentElement(unsigned int index)
+{
+ return m_textElements.at(index);
+}
+
+void KSVGTextChunk::clear()
+{
+ m_text.clear();
+ m_textElements.clear();
+}
+
+void KSVGTextChunk::addText(const QString &text, SVGTextContentElementImpl *textElement)
+{
+ m_text.append(text);
+ m_textElements.append(textElement);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGTextChunk.h b/ksvg/core/KSVGTextChunk.h
new file mode 100644
index 00000000..d684087a
--- /dev/null
+++ b/ksvg/core/KSVGTextChunk.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGTEXTCHUNK_H
+#define KSVGTEXTCHUNK_H
+
+#include <qstringlist.h>
+
+namespace KSVG
+{
+
+class SVGTextContentElementImpl;
+class SVGTextPositioningElementImpl;
+class KSVGTextChunk
+{
+public:
+ KSVGTextChunk();
+ ~KSVGTextChunk();
+
+ unsigned int count() const;
+ QString getText(unsigned int index) const;
+ SVGTextPositioningElementImpl *getTextElement(unsigned int index);
+ SVGTextContentElementImpl *getTextContentElement(unsigned int index);
+
+ void clear();
+ void addText(const QString &text, SVGTextContentElementImpl *textElement);
+
+private:
+ QStringList m_text;
+ QPtrList<SVGTextContentElementImpl> m_textElements;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/Makefile.am b/ksvg/core/Makefile.am
new file mode 100644
index 00000000..e1867428
--- /dev/null
+++ b/ksvg/core/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libksvgcore.la
+
+libksvgcore_la_SOURCES = KSVGLoader.cpp KSVGCanvas.cpp KSVGReader.cc KSVGTextChunk.cpp CanvasFactory.cpp CanvasItems.cpp KSVGHelper.cpp DocumentFactory.cpp
+libksvgcore_la_METASOURCES = AUTO
+
+servicetypedir = $(kde_servicetypesdir)
+servicetype_DATA = ksvgrenderer.desktop
+
+ksvginclude_HEADERS = KSVGCanvas.h CanvasItems.h CanvasItem.h CanvasFactory.h DocumentFactory.h
+ksvgincludedir = $(includedir)/ksvg
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+INCLUDES = $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes)
+
+KDE_OPTIONS = nofinal
+
diff --git a/ksvg/core/ksvgrenderer.desktop b/ksvg/core/ksvgrenderer.desktop
new file mode 100644
index 00000000..f9307621
--- /dev/null
+++ b/ksvg/core/ksvgrenderer.desktop
@@ -0,0 +1,56 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KSVG/Renderer
+X-KDE-Derived=
+Comment=KSVG Rendering Backend
+Comment[ar]=خلفية رسم KSVG
+Comment[bs]=KSVG renderiranje
+Comment[ca]=Representació en segon pla de KSVG
+Comment[cs]=Vykreslovací nástroj KSVG
+Comment[cy]=Ôl-wyneb Llunio KSVG
+Comment[da]=Underliggende program for KSVG-visning
+Comment[de]=KSVG-Darstellungsmodul
+Comment[el]=Σύστημα υποστήριξης αποτύπωσης του KSVG
+Comment[es]=Motor de procesado de KSVG
+Comment[et]=KSVG renderdamise taustarakendus
+Comment[eu]=KSVG errendatze programa
+Comment[fa]=پایانۀ پشتیبانی پرداخت KSVG
+Comment[fi]=KSVG-piirtäjän taustaohjelma
+Comment[fr]=Moteur de rendu KSVG
+Comment[ga]=Inneall Rindreála KSVG
+Comment[gl]=Backend de Renderizado KSVG
+Comment[he]=מנוע רינדור KSVG
+Comment[hi]=के-एसवीजी रेंडरिंग बैकएण्ड
+Comment[hu]=KSVG megjelenítőmotor
+Comment[is]=KSVG teiknari
+Comment[it]=Backend di KSVG per il rendering
+Comment[ja]=KSVG レンダリングバックエンド
+Comment[kk]=KSVG кескіндеу бағдарламасы
+Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG
+Comment[lt]=KSVG atkūrimo programinė sąsaja
+Comment[ms]=Tepi Belakang Menrealisasi KSVG
+Comment[nb]=Modul for KSVG-tegning
+Comment[nds]=KSVG-Dorstellhölper
+Comment[ne]=KSVG रेन्डरिङ ब्याकइन्ड
+Comment[nl]=KSVG weergavecomponent
+Comment[nn]=Modul for KSVG-teikning
+Comment[pl]=Narzędzie do renderowania KSVG
+Comment[pt]=Infra-Estrutura de Desenho KSVG
+Comment[pt_BR]=Estrutura de Renderização do KSVG
+Comment[ro]=Motorul de randare KSVG
+Comment[ru]=Движок прорисовки KSVG
+Comment[sk]=Nástroj pre zobrazovanie KSVG
+Comment[sl]=Izrisovalnik KSVG
+Comment[sr]=KSVG-ов позадински систем за рендеровање
+Comment[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje
+Comment[sv]=KSVG-uppritningsmodul
+Comment[ta]=KSVG வழங்கும் பின் அமைப்பு
+Comment[tg]=Лағжандаи тасовироти KSVG
+Comment[tr]=KSVG Tarama Arkayüzü
+Comment[uk]=Інтерфейс відтворення KSVG
+Comment[zh_CN]=KSVG 渲染后端
+Comment[zh_HK]=KSVG 合成後端
+Comment[zh_TW]=KSVG 上色後端介面
+
+[PropertyDef::X-KSVG-InternalName]
+Type=QString