summaryrefslogtreecommitdiffstats
path: root/ksvg/plugin/backends
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit47d455dd55be855e4cc691c32f687f723d9247ee (patch)
tree52e236aaa2576bdb3840ebede26619692fed6d7d /ksvg/plugin/backends
downloadtdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.tar.gz
tdegraphics-47d455dd55be855e4cc691c32f687f723d9247ee.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdegraphics@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'ksvg/plugin/backends')
-rw-r--r--ksvg/plugin/backends/Makefile.am1
-rw-r--r--ksvg/plugin/backends/agg/AggCanvas.cpp130
-rw-r--r--ksvg/plugin/backends/agg/AggCanvas.h77
-rw-r--r--ksvg/plugin/backends/agg/AggCanvasFactory.cpp45
-rw-r--r--ksvg/plugin/backends/agg/AggCanvasFactory.h45
-rw-r--r--ksvg/plugin/backends/agg/AggCanvasItems.cpp1747
-rw-r--r--ksvg/plugin/backends/agg/AggCanvasItems.h500
-rw-r--r--ksvg/plugin/backends/agg/BezierPathAgg.cpp126
-rw-r--r--ksvg/plugin/backends/agg/BezierPathAgg.h83
-rw-r--r--ksvg/plugin/backends/agg/GlyphTracerAgg.cpp113
-rw-r--r--ksvg/plugin/backends/agg/GlyphTracerAgg.h49
-rw-r--r--ksvg/plugin/backends/agg/Makefile.am15
-rw-r--r--ksvg/plugin/backends/agg/ksvgaggcanvas.desktop101
-rw-r--r--ksvg/plugin/backends/libart/BezierPathLibart.cpp160
-rw-r--r--ksvg/plugin/backends/libart/BezierPathLibart.h52
-rw-r--r--ksvg/plugin/backends/libart/GlyphTracerLibart.cpp177
-rw-r--r--ksvg/plugin/backends/libart/GlyphTracerLibart.h50
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvas.cpp425
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvas.h84
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvasFactory.cpp45
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvasFactory.h45
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvasItems.cpp2209
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvasItems.h414
-rw-r--r--ksvg/plugin/backends/libart/Makefile.am11
-rw-r--r--ksvg/plugin/backends/libart/ksvglibartcanvas.desktop101
25 files changed, 6805 insertions, 0 deletions
diff --git a/ksvg/plugin/backends/Makefile.am b/ksvg/plugin/backends/Makefile.am
new file mode 100644
index 00000000..eb3c3089
--- /dev/null
+++ b/ksvg/plugin/backends/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libart #agg
diff --git a/ksvg/plugin/backends/agg/AggCanvas.cpp b/ksvg/plugin/backends/agg/AggCanvas.cpp
new file mode 100644
index 00000000..245d36e1
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvas.cpp
@@ -0,0 +1,130 @@
+/*
+ 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 "AggCanvas.h"
+#include "SVGShapeImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGPaint.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include <kdebug.h>
+
+#include "AggCanvasItems.h"
+#include "GlyphTracerAgg.h"
+
+#include "agg_vertex_iterator.h"
+#include "agg_bounding_rect.h"
+
+using namespace KSVG;
+
+AggCanvas::AggCanvas(unsigned int width, unsigned int height) : KSVGCanvas(width, height)
+{
+ m_fontContext = new T2P::Converter(new T2P::GlyphTracerAgg());
+}
+
+void AggCanvas::setRenderBufferSize(int w, int h)
+{
+ KSVGCanvas::setRenderBufferSize(w, h);
+ m_buf.attach(m_buffer, m_width, m_height, m_width * m_nrChannels);
+}
+
+void AggCanvas::setBuffer(unsigned char *buffer)
+{
+ KSVGCanvas::setBuffer(buffer);
+ m_buf.attach(m_buffer, m_width, m_height, m_width * m_nrChannels);
+}
+
+T2P::BezierPath *AggCanvas::toBezierPath(CanvasItem *item) const
+{
+ // Only handle AggPath items
+ return dynamic_cast<AggPath *>(item);
+}
+
+// drawing primitives
+CanvasItem *AggCanvas::createRectangle(SVGRectElementImpl *rect)
+{
+ return new AggRectangle(this, rect);
+}
+
+CanvasItem *AggCanvas::createEllipse(SVGEllipseElementImpl *ellipse)
+{
+ return new AggEllipse(this, ellipse);
+}
+
+CanvasItem *AggCanvas::createCircle(SVGCircleElementImpl *circle)
+{
+ return new AggCircle(this, circle);
+}
+
+CanvasItem *AggCanvas::createLine(SVGLineElementImpl *line)
+{
+ return new AggLine(this, line);
+}
+
+CanvasItem *AggCanvas::createPolyline(SVGPolylineElementImpl *poly)
+{
+ return new AggPolyline(this, poly);
+}
+
+CanvasItem *AggCanvas::createPolygon(SVGPolygonElementImpl *poly)
+{
+ return new AggPolygon(this, poly);
+}
+
+CanvasItem *AggCanvas::createPath(SVGPathElementImpl *path)
+{
+ return new AggPath(this, path);
+}
+
+CanvasItem *AggCanvas::createClipPath(SVGClipPathElementImpl *)
+{
+ return 0;
+}
+
+CanvasItem *AggCanvas::createImage(SVGImageElementImpl *image)
+{
+ return new AggImage(this, image);
+}
+
+CanvasItem *AggCanvas::createCanvasMarker(SVGMarkerElementImpl *marker)
+{
+ return new AggMarker(this, marker);
+}
+
+CanvasItem *AggCanvas::createText(SVGTextElementImpl *text)
+{
+ return new AggText(this, text);
+}
+
+CanvasPaintServer *AggCanvas::createPaintServer(SVGElementImpl *pserver)
+{
+ AggPaintServer *result = 0;
+ if(dynamic_cast<SVGLinearGradientElementImpl *>(pserver))
+ result = new AggLinearGradient(dynamic_cast<SVGLinearGradientElementImpl *>(pserver));
+ else if(dynamic_cast<SVGRadialGradientElementImpl *>(pserver))
+ result = new AggRadialGradient(dynamic_cast<SVGRadialGradientElementImpl *>(pserver));
+ else if(dynamic_cast<SVGPatternElementImpl *>(pserver))
+ result = new AggPattern(dynamic_cast<SVGPatternElementImpl *>(pserver));
+ return result;
+}
+
diff --git a/ksvg/plugin/backends/agg/AggCanvas.h b/ksvg/plugin/backends/agg/AggCanvas.h
new file mode 100644
index 00000000..9df7a826
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvas.h
@@ -0,0 +1,77 @@
+/*
+ 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 AGGCANVAS_H
+#define AGGCANVAS_H
+
+#include "KSVGCanvas.h"
+
+#include "agg_basics.h"
+#include "agg_rendering_buffer.h"
+#include "agg_path_storage.h"
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_scanline_u.h"
+#include "agg_renderer_scanline.h"
+#include "agg_pixfmt_rgb24.h"
+
+namespace KSVG
+{
+
+class AggPaintServer;
+class SVGElementImpl;
+class AggCanvas : public KSVGCanvas
+{
+public:
+ AggCanvas(unsigned int width, unsigned int height);
+
+ virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const;
+
+ // creating canvas items
+ virtual CanvasItem *createRectangle(SVGRectElementImpl *rect);
+ virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse);
+ virtual CanvasItem *createCircle(SVGCircleElementImpl *circle);
+ virtual CanvasItem *createLine(SVGLineElementImpl *line);
+ virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly);
+ virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly);
+ virtual CanvasItem *createPath(SVGPathElementImpl *path);
+ virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath);
+ virtual CanvasItem *createImage(SVGImageElementImpl *image);
+ virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker);
+ virtual CanvasItem *createText(SVGTextElementImpl *text);
+ virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver);
+
+ virtual void setRenderBufferSize(int w, int h);
+
+ agg::rendering_buffer &buf() { return m_buf; }
+
+ float zoom() const { return m_zoom; }
+
+ agg::rasterizer_scanline_aa<> m_ras;
+
+protected:
+ virtual void setBuffer(unsigned char *buffer);
+
+protected:
+ agg::rendering_buffer m_buf;
+};
+
+};
+
+#endif
diff --git a/ksvg/plugin/backends/agg/AggCanvasFactory.cpp b/ksvg/plugin/backends/agg/AggCanvasFactory.cpp
new file mode 100644
index 00000000..439623ad
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvasFactory.cpp
@@ -0,0 +1,45 @@
+/*
+ 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 <kdebug.h>
+
+#include "AggCanvas.h"
+#include "AggCanvasFactory.h"
+
+using namespace KSVG;
+
+K_EXPORT_COMPONENT_FACTORY(libksvgrendereragg, AggCanvasFactory)
+
+AggCanvasFactory::AggCanvasFactory()
+{
+}
+
+AggCanvasFactory::~AggCanvasFactory()
+{
+}
+
+QObject *AggCanvasFactory::createObject(QObject *, const char *, const char *, const QStringList &args)
+{
+ unsigned int width = (*args.at(1)).toUInt();
+ unsigned int height = (*args.at(0)).toUInt();
+ return new AggCanvas(width, height);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/AggCanvasFactory.h b/ksvg/plugin/backends/agg/AggCanvasFactory.h
new file mode 100644
index 00000000..9fb3ffbf
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvasFactory.h
@@ -0,0 +1,45 @@
+/*
+ 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 AGGCANVASFACTORY_H
+#define AGGCANVASFACTORY_H
+
+#include <klibloader.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+namespace KSVG
+{
+
+class AggCanvasFactory : public KLibFactory
+{
+public:
+ AggCanvasFactory();
+ virtual ~AggCanvasFactory();
+
+ virtual QObject *createObject(QObject *parent = 0, const char *pname = 0, const char *name = "QObject", const QStringList &args = QStringList());
+};
+
+};
+
+#endif
+
+/// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/AggCanvasItems.cpp b/ksvg/plugin/backends/agg/AggCanvasItems.cpp
new file mode 100644
index 00000000..4ceb6109
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvasItems.cpp
@@ -0,0 +1,1747 @@
+/*
+ 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 <qimage.h>
+
+#include "SVGPaint.h"
+#include "SVGRectImpl.h"
+#include "SVGAngleImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGUnitTypes.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGPointListImpl.h"
+#include "SVGMarkerElement.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPathSegListImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGAnimatedAngleImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGPolygonElementImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGPolylineElementImpl.h"
+#include "SVGStopElementImpl.h"
+#include "SVGGradientElement.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGUnitConverter.h"
+
+#include "Glyph.h"
+#include "Converter.h"
+#include "KSVGTextChunk.h"
+
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_scanline_u.h"
+#include "agg_scanline_p.h"
+#include "agg_bounding_rect.h"
+#include "agg_ellipse.h"
+#include "agg_span_image_filter_rgba32.h"
+#include "agg_color_rgba8.h"
+#include "agg_gray8.h"
+#include "agg_span_gradient.h"
+#include "agg_span_interpolator_linear.h"
+#include "agg_span_pattern_rgba32.h"
+#include "agg_renderer_scanline.h"
+
+#include "AggCanvas.h"
+#include "AggCanvasItems.h"
+
+extern "C"
+{
+/* These are in KSVGHelper.cpp */
+int linearRGBFromsRGB(int sRGB8bit);
+int sRGBFromLinearRGB(int linearRGB8bit);
+}
+
+struct color_function_profile
+{
+ color_function_profile() {}
+ color_function_profile(const agg::rgba8 *colors) :
+ m_colors(colors) {}
+
+ const agg::rgba8& operator [] (unsigned v) const
+ {
+ return m_colors[v];
+ }
+
+ const agg::rgba8 *m_colors;
+};
+
+using namespace KSVG;
+
+// agg2 helpers
+
+agg::vcgen_stroke::line_cap_e toAggLineCap(PathStrokeCapType cap)
+{
+ if(cap == PATH_STROKE_CAP_BUTT)
+ return agg::vcgen_stroke::butt_cap;
+ else if(cap == PATH_STROKE_CAP_ROUND)
+ return agg::vcgen_stroke::round_cap;
+ else
+ return agg::vcgen_stroke::square_cap;
+}
+
+template<class Source>
+stroke<Source>::stroke(Source& src, KSVG::SVGStylableImpl *style) : m_s(src)
+{
+ m_s.width(style->getStrokeWidth()->baseVal()->value());
+ m_s.line_join((agg::vcgen_stroke::line_join_e)style->getJoinStyle());
+ m_s.miter_limit(style->getStrokeMiterlimit());
+ m_s.line_cap(toAggLineCap(style->getCapStyle()));
+}
+
+template<class Source>
+dash_stroke<Source>::dash_stroke(Source& src, KSVG::SVGStylableImpl *style) : m_d(src), m_ds(m_d)
+{
+ unsigned int dashLength = style->getDashArray() ? style->getDashArray()->baseVal()->numberOfItems() : 0;
+ // there are dashes to be rendered
+ unsigned int count = (dashLength % 2) == 0 ? dashLength : dashLength * 2;
+ for(unsigned int i = 0; i < count; i += 2)
+ m_d.add_dash(style->getDashArray()->baseVal()->getItem(i % dashLength)->value(),
+ style->getDashArray()->baseVal()->getItem((i + 1) % dashLength)->value());
+ m_d.dash_start(style->getDashOffset()->baseVal()->value());
+ m_ds.width(style->getStrokeWidth()->baseVal()->value());
+ m_ds.line_join((agg::vcgen_stroke::line_join_e)style->getJoinStyle());
+ m_ds.miter_limit(style->getStrokeMiterlimit());
+ m_ds.line_cap(toAggLineCap(style->getCapStyle()));
+}
+
+template<class Source>
+dash_stroke_simple<Source>::dash_stroke_simple(Source& src, KSVG::SVGStylableImpl *style)
+{
+ //if(style->isStroked() && style->getStrokeWidth()->baseVal()->value() > 0)
+ //{
+ unsigned int dashLength = style->getDashArray() ? style->getDashArray()->baseVal()->numberOfItems() : 0;
+ if(dashLength > 0)
+ impl = new dash_stroke<Source>(src, style);
+ else
+ impl = new stroke<Source>(src, style);
+ //}
+ //else
+ //impl = 0;
+}
+
+void renderPathSolid(AggCanvas *canvas, const agg::rgba8 &color)
+{
+ agg::scanline_p8 sl;
+ if(canvas->nrChannels() == 3)
+ {
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_p_solid<renderer_base> renderer_solid;
+
+ pixfmt pixf(canvas->buf());
+ renderer_base rb(pixf);
+ renderer_solid ren(rb);
+
+ ren.color(color);
+ canvas->m_ras.render(sl, ren);
+ }
+ else
+ {
+ typedef agg::pixfmt_rgba32 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_p_solid<renderer_base> renderer_solid;
+
+ pixfmt pixf(canvas->buf());
+ renderer_base rb(pixf);
+ renderer_solid ren(rb);
+
+ ren.color(color);
+ canvas->m_ras.render(sl, ren);
+ }
+}
+
+// #####
+
+BezierPathAggStroked::BezierPathAggStroked(SVGStylableImpl *style)
+: T2P::BezierPathAgg(), m_curved_trans_clipped(m_curved_trans), m_curved_stroked(m_curved, style), m_curved_stroked_trans(m_curved_stroked, m_transform), m_curved_stroked_trans_clipped(m_curved_stroked_trans), m_style(style)
+{
+}
+
+BezierPathAggStroked::BezierPathAggStroked(const T2P::BezierPathAgg &other, SVGStylableImpl *style)
+: T2P::BezierPathAgg(other), m_curved_trans_clipped(m_curved_trans), m_curved_stroked(m_curved, style), m_curved_stroked_trans(m_curved_stroked, m_transform), m_curved_stroked_trans_clipped(m_curved_stroked_trans), m_style(style)
+{
+}
+
+AggShape::AggShape(AggCanvas *c, SVGStylableImpl *style) : CanvasItem(), BezierPathAggStroked(style), m_canvas(c)
+{
+ m_context = NORMAL;
+ m_fillPainter = 0;
+ m_strokePainter = 0;
+}
+
+AggShape::~AggShape()
+{
+ freeSVPs();
+ delete m_fillPainter;
+ delete m_strokePainter;
+}
+
+QRect AggShape::bbox() const
+{
+ return m_bbox;
+}
+
+bool AggShape::fillContains(const QPoint &p)
+{
+ agg::rasterizer_scanline_aa<> ras;
+ ras.filling_rule(m_style->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero);
+ ras.add_path(m_curved_trans);
+ bool b = ras.hit_test(p.x(), p.y());
+ return b;
+}
+
+bool AggShape::strokeContains(const QPoint &p)
+{
+ agg::rasterizer_scanline_aa<> ras;
+ ras.add_path(m_curved_stroked_trans);
+ bool b = ras.hit_test(p.x(), p.y());
+ return b;
+}
+
+void AggShape::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(reason == UPDATE_STYLE)
+ {
+ if(!m_fillPainter || !m_strokePainter)
+ AggShape::init();
+ if(m_fillPainter)
+ m_fillPainter->update(m_style);
+ if(m_strokePainter)
+ m_strokePainter->update(m_style);
+ m_canvas->invalidate(this, false);
+ }
+ else if(reason == UPDATE_TRANSFORM)
+ {
+ freeSVPs();
+ init();
+ m_canvas->invalidate(this, true);
+ }
+ else if(reason == UPDATE_ZOOM)
+ init();
+ else if(reason == UPDATE_PAN)
+ {
+ agg::trans_affine mtx(1, 0, 0, 1, param1, param2);
+ m_transform *= mtx;
+ }
+ else if(reason == UPDATE_LINEWIDTH)
+ {
+ init();
+ m_canvas->invalidate(this, true);
+ }
+}
+
+void AggShape::draw(SVGShapeImpl *shape)
+{
+ if(!m_referenced && (!m_style->getVisible() || !m_style->getDisplay() || !shape->directRender()))
+ return;
+
+ //if(!m_strokeSVP && (!m_fillSVP || !m_style->isFilled()))
+ // init();
+ agg::rect cb;
+ if(m_canvas->nrChannels() == 3)
+ {
+ agg::pixfmt_rgb24 pixf(m_canvas->buf());
+ agg::renderer_base<agg::pixfmt_rgb24> rb(pixf);
+ cb = rb.clip_box();
+ }
+ else
+ {
+ agg::pixfmt_rgba32 pixf(m_canvas->buf());
+ agg::renderer_base<agg::pixfmt_rgba32> rb(pixf);
+ cb = rb.clip_box();
+ }
+
+ m_curved_trans_clipped.clip_box(cb.x1, cb.y1, cb.x2 + 1, cb.y2 + 1);
+ m_curved_stroked_trans_clipped.clip_box(cb.x1, cb.y1, cb.x2 + 1, cb.y2 + 1);
+
+ double x1, y1, x2, y2;
+ agg::bounding_rect(m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2);
+ m_bbox = QRect(int(x1), int(y1), int(x2 - x1), int(y2 - y1));
+
+ m_curved.approximation_scale(pow(m_transform.scale(), 0.75));
+
+ if(m_fillPainter)
+ m_fillPainter->draw(m_canvas, m_curved_trans, m_style, shape);
+ if(m_strokePainter)
+ m_strokePainter->draw(m_canvas, m_curved_stroked_trans, m_style, shape);
+}
+
+bool AggShape::isVisible(SVGShapeImpl *shape)
+{
+ return m_referenced || (m_style->getVisible() && m_style->getDisplay() && shape->directRender());
+}
+
+void AggShape::calcSVPs(const SVGMatrixImpl *matrix)
+{
+ // transform
+ m_transform = agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f());
+
+ double x1, y1, x2, y2;
+ agg::bounding_rect(m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2);
+ m_bbox = QRect(int(x1), int(y1), int(x2 - x1), int(y2 - y1));
+}
+
+void AggShape::init(const SVGMatrixImpl *)
+{
+}
+
+void AggShape::init()
+{
+ if(m_style->isFilled())
+ {
+ if(m_fillPainter == 0)
+ m_fillPainter = new AggFillPaintServer(m_style);
+ }
+ else
+ {
+ delete m_fillPainter;
+ m_fillPainter = 0;
+ }
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0)
+ {
+ if(m_strokePainter == 0)
+ m_strokePainter = new AggStrokePaintServer(m_style);
+ }
+ else
+ {
+ delete m_strokePainter;
+ m_strokePainter = 0;
+ }
+}
+
+void AggShape::freeSVPs()
+{
+ m_storage.remove_all();
+}
+
+// #####
+
+AggStrokePaintServer::AggStrokePaintServer(SVGStylableImpl *style)
+{
+ update(style);
+}
+
+void AggStrokePaintServer::update(SVGStylableImpl *style)
+{
+ if(style->getStrokeColor()->paintType() != SVG_PAINTTYPE_URI)
+ {
+ QColor qcolor;
+ if(style->getStrokeColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR)
+ qcolor = style->getColor()->rgbColor().color();
+ else
+ qcolor = style->getStrokeColor()->rgbColor().color();
+
+ short opacity = static_cast<short>(style->getStrokeOpacity() * style->getOpacity() * 255);
+
+ // Spec: clamping
+ opacity = opacity < 0 ? 0 : opacity;
+ opacity = opacity > 255 ? 255 : opacity;
+
+ m_color = agg::rgba8(qcolor.red(), qcolor.green(), qcolor.blue());
+ m_color.opacity(style->getStrokeOpacity() * style->getOpacity());
+ }
+}
+
+template<class VertexSource>
+void AggStrokePaintServer::draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape)
+{
+ canvas->m_ras.reset();
+ if(style->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI)
+ {
+ AggPaintServer *pserver = static_cast<AggPaintServer *>(SVGPaintServerImpl::paintServer(shape->ownerDoc(), style->getStrokeColor()->uri().string()));
+ if(!pserver) return;
+ pserver->setBBoxTarget(shape);
+
+ // TODO : Clipping
+ if(!pserver->finalized())
+ pserver->finalizePaintServer();
+ canvas->m_ras.add_path(vs);
+ pserver->render(canvas);
+ }
+ else
+ {
+ canvas->m_ras.add_path(vs);
+ renderPathSolid(canvas, m_color);
+ }
+}
+
+AggFillPaintServer::AggFillPaintServer(SVGStylableImpl *style)
+{
+ update(style);
+}
+
+void AggFillPaintServer::update(SVGStylableImpl *style)
+{
+ if(style->getFillColor()->paintType() != SVG_PAINTTYPE_URI)
+ {
+ QColor qcolor;
+ if(style->getFillColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR)
+ qcolor = style->getColor()->rgbColor().color();
+ else
+ qcolor = style->getFillColor()->rgbColor().color();
+
+ short opacity = static_cast<short>(style->getFillOpacity() * style->getOpacity() * 255);
+
+ // Spec: clamping
+ opacity = opacity < 0 ? 0 : opacity;
+ opacity = opacity > 255 ? 255 : opacity;
+
+ m_color = agg::rgba8(qcolor.red(), qcolor.green(), qcolor.blue());
+ m_color.opacity(style->getFillOpacity() * style->getOpacity());
+ }
+}
+
+template<class VertexSource>
+void AggFillPaintServer::draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape)
+{
+ canvas->m_ras.reset();
+ if(style->getFillColor()->paintType() == SVG_PAINTTYPE_URI)
+ {
+ AggPaintServer *pserver = static_cast<AggPaintServer *>(SVGPaintServerImpl::paintServer(shape->ownerDoc(), style->getFillColor()->uri().string()));
+ if(!pserver) return;
+ pserver->setBBoxTarget(shape);
+
+ // TODO : Clipping
+ if(!pserver->finalized())
+ pserver->finalizePaintServer();
+ canvas->m_ras.add_path(vs);
+ pserver->render(canvas);
+ }
+ else
+ {
+ canvas->m_ras.filling_rule(style->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero);
+ canvas->m_ras.add_path(vs);
+ renderPathSolid(canvas, m_color);
+ }
+}
+
+// #####
+
+AggRectangle::AggRectangle(AggCanvas *c, SVGRectElementImpl *rect)
+: AggShape(c, rect), m_rect(rect)
+{
+ init();
+}
+
+void AggRectangle::draw()
+{
+ if(isVisible())
+ AggShape::draw(m_rect);
+}
+
+bool AggRectangle::isVisible()
+{
+ // Spec: a value of zero disables rendering
+ return AggShape::isVisible(m_rect) && m_rect->width()->baseVal()->value() > 0 && m_rect->height()->baseVal()->value() > 0;
+}
+
+void AggRectangle::init()
+{
+ init(m_rect->screenCTM());
+}
+
+void AggRectangle::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ double x = m_rect->x()->baseVal()->value();
+ double y = m_rect->y()->baseVal()->value();
+ double width = m_rect->width()->baseVal()->value();
+ double height = m_rect->height()->baseVal()->value();
+ double rx = m_rect->rx()->baseVal()->value();
+ double ry = m_rect->ry()->baseVal()->value();
+
+ // Spec: If there is no rx or ry specified, draw a normal rect
+ if(rx == -1 && ry == -1)
+ {
+ m_storage.move_to(x, y);
+ m_storage.line_to(x + width, y);
+ m_storage.line_to(x + width, y + height);
+ m_storage.line_to(x, y + height);
+ }
+ else
+ {
+ int i = 0;
+
+ // Spec: If rx isn't specified, but ry, set rx to ry
+ if(rx == -1)
+ rx = ry;
+
+ // Spec: If ry isn't specified, but rx, set ry to rx
+ if(ry == -1)
+ ry = rx;
+
+ // Spec: If rx is greater than half of the width of the rectangle
+ // then set rx to half of the width
+ if(rx > width / 2)
+ rx = width / 2;
+
+ // Spec: If ry is greater than half of the height of the rectangle
+ // then set ry to half of the height
+ if(ry > height / 2)
+ ry = height / 2;
+
+ m_storage.move_to(x + rx, y);
+
+ i++;
+ m_storage.curve4(x + rx * (1 - 0.552), y, x, y + ry * (1 - 0.552), x, y + ry);
+ i++;
+ if(ry < height / 2)
+ {
+ m_storage.line_to(x, y + height - ry);
+ i++;
+ }
+ m_storage.curve4(x, y + height - ry * (1 - 0.552), x + rx * (1 - 0.552), y + height, x + rx, y + height);
+ i++;
+ if(rx < width / 2)
+ {
+ m_storage.line_to(x + width - rx, y + height);
+ i++;
+ }
+ m_storage.curve4(x + width - rx * (1 - 0.552), y + height, x + width, y + height - ry * (1 - 0.552), x + width, y + height - ry);
+ i++;
+ if(ry < height / 2)
+ {
+ m_storage.line_to(x + width, y + ry);
+ i++;
+ }
+ m_storage.curve4(x + width, y + ry * (1 - 0.552), x + width - rx * (1 - 0.552), y, x + width - rx, y);
+ i++;
+ if(rx < width / 2)
+ {
+ m_storage.line_to(x + rx, y);
+ i++;
+ }
+ }
+ m_storage.close_polygon();
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(vec, m_rect, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggEllipse::AggEllipse(AggCanvas *c, SVGEllipseElementImpl *ellipse)
+: AggShape(c, ellipse), m_ellipse(ellipse)
+{
+ init();
+}
+
+void AggEllipse::draw()
+{
+ if(isVisible())
+ AggShape::draw(m_ellipse);
+}
+
+bool AggEllipse::isVisible()
+{
+ // Spec: dont render when rx and/or ry is zero
+ return AggShape::isVisible(m_ellipse) && m_ellipse->rx()->baseVal()->value() > 0 && m_ellipse->ry()->baseVal()->value() > 0;
+}
+
+void AggEllipse::init()
+{
+ init(m_ellipse->screenCTM());
+}
+
+void AggEllipse::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ double rx = m_ellipse->rx()->baseVal()->value();
+ double ry = m_ellipse->ry()->baseVal()->value();
+ double cx = m_ellipse->cx()->baseVal()->value();
+ double cy = m_ellipse->cy()->baseVal()->value();
+
+ agg::ellipse ell(cx, cy, rx, ry, 100);
+ ell.rewind(0);
+ double x, y;
+ unsigned int cmd;
+ while((cmd = ell.vertex(&x, &y)) != agg::path_cmd_stop)
+ m_storage.add_vertex(x, y, cmd);
+ m_storage.close_polygon();
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(vec2, m_ellipse, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggCircle::AggCircle(AggCanvas *c, SVGCircleElementImpl *circle)
+: AggShape(c, circle), m_circle(circle)
+{
+ init();
+}
+
+void AggCircle::draw()
+{
+ if(isVisible())
+ AggShape::draw(m_circle);
+}
+
+bool AggCircle::isVisible()
+{
+ // Spec: a value of zero disables rendering
+ return AggShape::isVisible(m_circle) && m_circle->r()->baseVal()->value() > 0;
+}
+
+void AggCircle::init()
+{
+ init(m_circle->screenCTM());
+}
+
+void AggCircle::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ double r = m_circle->r()->baseVal()->value();
+ double cx = m_circle->cx()->baseVal()->value();
+ double cy = m_circle->cy()->baseVal()->value();
+
+ agg::ellipse ell(cx, cy, r, r, 100);
+ ell.rewind(0);
+ double x, y;
+ unsigned int cmd;
+ while((cmd = ell.vertex(&x, &y)) != agg::path_cmd_stop)
+ m_storage.add_vertex(x, y, cmd);
+ m_storage.close_polygon();
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(vec2, m_ellipse, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggLine::AggLine(AggCanvas *c, SVGLineElementImpl *line)
+: AggShape(c, line), MarkerHelper(), m_line(line)
+{
+ init();
+}
+
+AggLine::~AggLine()
+{
+}
+
+void AggLine::draw()
+{
+ if(isVisible())
+ {
+ // transform ( zoom?)
+ //agg::trans_affine transform = m_transform;
+ //agg::trans_affine mtx(m_canvas->zoom(), 0, 0, m_canvas->zoom(), m_canvas->pan().x(), m_canvas->pan().y());
+ //m_transform *= mtx;
+ //m_curved.approximation_scale(pow(m_transform.scale(), 0.75));
+
+ if(m_style->isStroked())
+ {
+ m_canvas->m_ras.reset();
+ m_canvas->m_ras.add_path(m_curved_stroked_trans);
+ QColor qcolor;
+ if(m_style->getStrokeColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR)
+ qcolor = m_style->getColor()->rgbColor().color();
+ else
+ qcolor = m_style->getStrokeColor()->rgbColor().color();
+ agg::rgba8 color(qcolor.red(), qcolor.green(), qcolor.blue());
+ color.opacity(m_style->getStrokeOpacity() * m_style->getOpacity());
+ renderPathSolid(m_canvas, color);
+ }
+ //m_transform = transform;
+
+ if(m_line->hasMarkers())
+ {
+ double x1 = m_line->x1()->baseVal()->value();
+ double y1 = m_line->y1()->baseVal()->value();
+ double x2 = m_line->x2()->baseVal()->value();
+ double y2 = m_line->y2()->baseVal()->value();
+ double slope = SVGAngleImpl::todeg(atan2(y2 - y1, x2 - x1));
+
+ if(m_line->hasStartMarker())
+ doStartMarker(m_line, m_line, x1, y1, slope);
+ if(m_line->hasEndMarker())
+ doEndMarker(m_line, m_line, x2, y2, slope);
+ }
+ }
+}
+
+bool AggLine::isVisible()
+{
+ return AggShape::isVisible(m_line);
+}
+
+void AggLine::init()
+{
+ init(m_line->screenCTM());
+}
+
+void AggLine::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ m_storage.move_to(m_line->x1()->baseVal()->value(), m_line->y1()->baseVal()->value());
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ double x2 = m_line->x2()->baseVal()->value();
+ double y2 = m_line->y2()->baseVal()->value();
+ if(x2 == m_line->x1()->baseVal()->value() && y2 == m_line->y1()->baseVal()->value() && m_line->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ m_storage.line_to(x2 + .5, y2);
+ else
+ m_storage.line_to(x2, y2);
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+AggPoly::AggPoly(AggCanvas *c, SVGPolyElementImpl *poly)
+: AggShape(c, poly), MarkerHelper(), m_poly(poly)
+{
+}
+
+AggPoly::~AggPoly()
+{
+}
+
+void AggPoly::init()
+{
+ init(m_poly->screenCTM());
+}
+
+void AggPoly::draw()
+{
+ if(isVisible())
+ {
+ AggShape::draw(m_poly);
+
+ if(m_poly->hasMarkers())
+ m_poly->drawMarkers();
+ }
+}
+
+bool AggPoly::isVisible()
+{
+ return AggShape::isVisible(m_poly);
+}
+
+// #####
+AggPolyline::AggPolyline(AggCanvas *c, SVGPolylineElementImpl *poly)
+: AggPoly(c, poly)
+{
+ AggPoly::init();
+}
+
+AggPolyline::~AggPolyline()
+{
+}
+
+void AggPolyline::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ unsigned int numberOfPoints = m_poly->points()->numberOfItems();
+
+ if(numberOfPoints < 1)
+ return;
+
+ m_storage.move_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y());
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(numberOfPoints == 2)
+ {
+ double x1 = m_poly->points()->getItem(1)->x();
+ double y1 = m_poly->points()->getItem(1)->y();
+ if(x1 == m_poly->points()->getItem(0)->x() && y1 == m_poly->points()->getItem(0)->y() && m_poly->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ m_storage.line_to(m_poly->points()->getItem(1)->x() + .5, m_poly->points()->getItem(1)->y());
+ else
+ m_storage.line_to(m_poly->points()->getItem(1)->x(), m_poly->points()->getItem(1)->y());
+ }
+ else
+ {
+ unsigned int index;
+ for(index = 1; index < numberOfPoints; index++)
+ m_storage.line_to(m_poly->points()->getItem(index)->x(), m_poly->points()->getItem(index)->y());
+ }
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggPolygon::AggPolygon(AggCanvas *c, SVGPolygonElementImpl *poly)
+: AggPoly(c, poly)
+{
+ AggPoly::init();
+}
+
+AggPolygon::~AggPolygon()
+{
+}
+
+void AggPolygon::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ int numberOfPoints = m_poly->points()->numberOfItems();
+
+ if(numberOfPoints < 1)
+ return;
+
+ m_storage.move_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y());
+
+ int index;
+ for(index = 1; index < numberOfPoints; index++)
+ m_storage.line_to(m_poly->points()->getItem(index)->x(), m_poly->points()->getItem(index)->y());
+
+ m_storage.line_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y());
+ m_storage.close_polygon();
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(polygon, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggPath::AggPath(AggCanvas *c, SVGPathElementImpl *path)
+: AggShape(c, path), SVGPathParser(), MarkerHelper(), m_path(path)
+{
+ init();
+}
+
+AggPath::~AggPath()
+{
+}
+
+void AggPath::draw()
+{
+ AggShape::draw(m_path);
+
+ if(m_path->hasMarkers())
+ {
+ SVGPathElementImpl::MarkerData markers = m_path->markerData();
+ int numMarkers = markers.numMarkers();
+
+ if(m_path->hasStartMarker())
+ doStartMarker(m_path, m_path, markers.marker(0).x, markers.marker(0).y, markers.marker(0).angle);
+
+ for(int i = 1; i < numMarkers - 1; i++)
+ {
+ if(m_path->hasMidMarker())
+ doMidMarker(m_path, m_path, markers.marker(i).x, markers.marker(i).y, markers.marker(i).angle);
+ }
+
+ if(m_path->hasEndMarker())
+ doEndMarker(m_path, m_path, markers.marker(numMarkers - 1).x, markers.marker(numMarkers - 1).y, markers.marker(numMarkers - 1).angle);
+ }
+}
+
+bool AggPath::isVisible()
+{
+ return AggShape::isVisible(m_path);
+}
+
+void AggPath::init()
+{
+ init(m_path->screenCTM());
+}
+
+void AggPath::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ if(!m_path->getAttribute("d").string().isEmpty())
+ {
+ m_storage.start_new_path();
+ parseSVG(m_path->getAttribute("d").string(), true);
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(m_storage.total_vertices() == 2 && agg::is_line_to(m_storage.command(1)))
+ {
+ double x1, y1;
+ double x2, y2;
+ m_storage.vertex(0, &x1, &y1);
+ m_storage.vertex(1, &x2, &y2);
+ if(x1 == x2 && y1 == y2 && m_path->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ m_storage.modify_vertex(1, x2 + .5, y2);
+ }
+ // TODO : handle filled paths that are not closed explicitly
+ }
+ }
+
+ // There are pure-moveto paths which reference paint servers *bah*
+ // Do NOT render them
+ bool dontrender = m_storage.total_vertices() == 1 && agg::is_move_to((*m_storage.begin()).cmd);
+ if(!dontrender && m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP);
+}
+
+void AggPath::svgMoveTo(double x1, double y1, bool, bool)
+{
+ m_storage.move_to(x1, y1);
+}
+
+void AggPath::svgLineTo(double x1, double y1, bool)
+{
+ m_storage.line_to(x1, y1);
+}
+
+void AggPath::svgCurveToCubic(double x1, double y1, double x2, double y2, double x3, double y3, bool)
+{
+ m_storage.curve4(x1, y1, x2, y2, x3, y3);
+}
+
+void AggPath::svgClosePath()
+{
+ m_storage.close_polygon();
+}
+
+// #####
+
+AggMarker::AggMarker(AggCanvas *c, SVGMarkerElementImpl *marker)
+: CanvasMarker(marker), m_canvas(c)//, m_clippingRectangle(0)
+{
+}
+
+AggMarker::~AggMarker()
+{
+ //if(m_clippingRectangle)
+ // art_svp_free(m_clippingRectangle);
+}
+
+void AggMarker::init()
+{
+}
+
+void AggMarker::draw()
+{
+}
+
+void AggMarker::draw(SVGShapeImpl * /*obj*/, int /*x*/, int /*y*/, float /*lwidth*/, double /*angle*/)
+{
+}
+
+// #####
+
+AggImage::AggImage(AggCanvas *c, SVGImageElementImpl *image)
+: m_canvas(c), m_image(image)
+{
+}
+
+AggImage::~AggImage()
+{
+}
+
+void AggImage::draw()
+{
+ if(isVisible())
+ {
+ //KSVGPolygon clippingPolygon = m_image->clippingShape();
+
+ QImage *img = m_image->image();
+ if(!img) return;
+ QImage image = m_image->scaledImage();
+ agg::rendering_buffer source_buffer;
+ source_buffer.attach(image.bits(), image.width(), image.height(), image.width() * 4);
+
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+
+ pixfmt pixf(m_canvas->buf());
+ renderer_base rb(pixf);
+
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ typedef agg::span_image_filter_rgba32_bilinear<agg::order_bgra32, interpolator_type> span_gen_type;
+ typedef agg::renderer_scanline_u<renderer_base, span_gen_type> renderer_type;
+ SVGMatrixImpl *ctm = m_image->scaledImageMatrix();
+ agg::trans_affine img_mtx(ctm->a(), ctm->b(), ctm->c(), ctm->d(), ctm->e(), ctm->f());
+ kdDebug() << "ctm->e() : " << ctm->e() << endl;
+ kdDebug() << "ctm->f() : " << ctm->f() << endl;
+ double x1 = 0;
+ double y1 = 0;
+ double x2 = image.width();
+ double y2 = image.height();
+ img_mtx.transform(&x1, &y1);
+ img_mtx.transform(&x2, &y2);
+ img_mtx.invert();
+
+ interpolator_type interpolator(img_mtx);
+ agg::span_allocator<agg::rgba8> sa;
+ span_gen_type sg(sa, source_buffer, agg::rgba(1, 1, 1, 0), interpolator);
+ renderer_type ri(rb, sg);
+
+ agg::scanline_u8 sl;
+
+ //rb.reset_clipping(true);
+ // Clip image against buffer
+ agg::path_storage viewp;
+ viewp.move_to(x1, y1);
+ viewp.line_to(x1, y2);
+ viewp.line_to(x2, y2);
+ viewp.line_to(x2, y1);
+ viewp.close_polygon();
+ m_canvas->m_ras.add_path(viewp);
+ m_canvas->m_ras.render(sl, ri);
+
+ ctm->deref();
+ }
+}
+
+bool AggImage::isVisible()
+{
+ return (m_referenced || (m_image->getVisible() && m_image->getDisplay() && m_image->directRender())) && m_image->image();
+}
+
+void AggImage::init()
+{
+}
+
+QRect AggImage::bbox() const
+{
+ QRect bbox(static_cast<int>(m_image->x()->baseVal()->value()),
+ static_cast<int>(m_image->y()->baseVal()->value()),
+ static_cast<int>(m_image->width()->baseVal()->value()),
+ static_cast<int>(m_image->height()->baseVal()->value()));
+
+
+ return SVGHelperImpl::fromUserspace(m_image, bbox);
+}
+
+// #####
+
+AggText::AggText(AggCanvas *c, SVGTextElementImpl *text)
+: CanvasText(text), m_canvas(c)
+{
+ init();
+ m_drawItems.setAutoDelete(true);
+}
+
+AggText::~AggText()
+{
+}
+
+bool AggText::fillContains(const QPoint &p)
+{
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *fill = it.current();
+ while(fill)
+ {
+ if(fill->svp)
+ {
+ agg::rasterizer_scanline_aa<> ras;
+ ras.filling_rule(fill->element->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero);
+ ras.add_path(fill->svp->m_curved_trans);
+ if(ras.hit_test(p.x(), p.y()))
+ return true;
+ }
+
+ fill = ++it;
+ }
+
+ return false;
+}
+
+bool AggText::strokeContains(const QPoint &p)
+{
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *stroke = it.current();
+ while(stroke)
+ {
+ if(stroke->svp)
+ {
+ agg::rasterizer_scanline_aa<> ras;
+ ras.filling_rule(stroke->element->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero);
+ ras.add_path(stroke->svp->m_curved_stroked_trans);
+ if(ras.hit_test(p.x(), p.y()))
+ return true;
+ }
+
+ stroke = ++it;
+ }
+
+ return false;
+}
+
+QRect AggText::bbox() const
+{
+ QRect result, rect;
+
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *elem = it.current();
+ while(elem)
+ {
+ double x1, y1, x2, y2;
+ if(elem && elem->svp)
+ {
+ if(agg::bounding_rect(elem->svp->m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2))
+ {
+ rect.setX(int(x1));
+ rect.setY(int(y1));
+ rect.setWidth(int(x2 - x1));
+ rect.setHeight(int(y2 - y1));
+
+ result = result.unite(rect);
+ }
+ }
+ elem = ++it;
+ }
+ return result;
+}
+
+void AggText::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(reason == UPDATE_STYLE)
+ {
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *svpelement = it.current();
+ SVGTextContentElementImpl *text;
+ while(svpelement)
+ {
+ text = svpelement->element;
+ if(svpelement->fillPainter)
+ svpelement->fillPainter->update(text);
+ if(svpelement->strokePainter)
+ svpelement->strokePainter->update(text);
+
+ svpelement = ++it;
+ }
+ m_canvas->invalidate(this, false);
+ }
+ else if(reason == UPDATE_TRANSFORM)
+ {
+ clearCurved();
+ init();
+ m_canvas->invalidate(this, true);
+ }
+ else if(reason == UPDATE_ZOOM)
+ {
+ clearCurved();
+ init();
+ }
+ else if(reason == UPDATE_PAN)
+ {
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *svpelement = it.current();
+ T2P::BezierPathAgg *bpath;
+ while(svpelement)
+ {
+ bpath = svpelement->svp;
+ agg::trans_affine mtx(1, 0, 0, 1, param1, param2);
+ bpath->m_transform *= mtx;
+
+ svpelement = ++it;
+ }
+ }
+ /*
+ else if(reason == UPDATE_LINEWIDTH)
+ {
+ }*/
+}
+
+void AggText::draw()
+{
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *svpelement = it.current();
+ BezierPathAggStroked *bpath;
+ SVGTextContentElementImpl *text;
+
+ while(svpelement)
+ {
+ bpath = svpelement->svp;
+ text = svpelement->element;
+ if(!text->getVisible() || !text->getDisplay() || !text->directRender())
+ return;
+
+ bpath->m_curved.approximation_scale(pow(bpath->m_transform.scale(), 1.25));
+
+ if(svpelement->fillPainter)
+ svpelement->fillPainter->draw(m_canvas, bpath->m_curved_trans, text, text);
+ if(svpelement->strokePainter)
+ svpelement->strokePainter->draw(m_canvas, bpath->m_curved_stroked_trans, text, text);
+
+ svpelement = ++it;
+ }
+}
+
+bool AggText::isVisible()
+{
+ bool foundVisible = false;
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *svpelement = it.current();
+ SVGTextContentElementImpl *text;
+
+ while(svpelement)
+ {
+ text = svpelement->element;
+ if(text->getVisible() && text->getDisplay() && text->directRender())
+ {
+ foundVisible = true;
+ break;
+ }
+
+ svpelement = ++it;
+ }
+
+ return foundVisible;
+}
+
+void AggText::init()
+{
+ init(m_text->screenCTM());
+}
+
+void AggText::renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const
+{
+ for(unsigned int i = 0; i < glyph->glyphCount(); i++)
+ {
+ T2P::GlyphAffinePair *glyphAffine = glyph->set().at(i);
+ T2P::BezierPathAgg *bpath = const_cast<T2P::BezierPathAgg *>(static_cast<const T2P::BezierPathAgg *>(glyphAffine->transformatedPath()));
+
+ // text-anchor/baseline-shift support
+ if(!params->tb())
+ bpath->m_transform = agg::trans_affine(screenCTM->a(), screenCTM->b(), screenCTM->c(), screenCTM->d(), screenCTM->e() - anchor * screenCTM->a(), screenCTM->f());
+ else
+ bpath->m_transform = agg::trans_affine(screenCTM->a(), screenCTM->b(), screenCTM->c(), screenCTM->d(), screenCTM->e(), screenCTM->f() - anchor * screenCTM->d());
+
+ SVPElement *svpelement = new SVPElement();
+ svpelement->svp = new BezierPathAggStroked(*bpath, element);
+ svpelement->element = element;
+
+ if(element->isFilled())
+ svpelement->fillPainter = new AggFillPaintServer(element);
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0)
+ svpelement->strokePainter = new AggStrokePaintServer(element);
+ m_drawItems.append(svpelement);
+ }
+}
+
+void AggText::init(const SVGMatrixImpl *screenCTM)
+{
+ int curx = 0, cury = 0, endx = 0, endy = 0;
+ KSVGTextChunk *textChunk = CanvasText::createTextChunk(m_canvas, screenCTM, curx, cury, endx, endy);
+
+ if(textChunk->count() > 0)
+ CanvasText::createGlyphs(textChunk, m_canvas, screenCTM, curx, cury, endx, endy);
+
+ delete textChunk;
+}
+
+void AggText::clearCurved()
+{
+ m_drawItems.clear();
+ // TODO: Huh - nobody does anything with the *trans* objects?:
+}
+
+void AggText::addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double width, double height) const
+{
+ if(element->isFilled() || element->isStroked())
+ {
+ // compute rect
+ BezierPathAggStroked *bpath = new BezierPathAggStroked(element);
+ bpath->m_storage.move_to(x, y);
+ bpath->m_storage.line_to(x + width, y);
+ bpath->m_storage.line_to(x + width, y + height);
+ bpath->m_storage.line_to(x, y + height);
+
+ const SVGMatrixImpl *mat = m_text->screenCTM();
+ bpath->m_transform = agg::trans_affine(mat->a(), mat->b(), mat->c(), mat->d(), mat->e(), mat->f());
+
+ SVPElement *svpelement = new SVPElement();
+ svpelement->svp = bpath;
+ svpelement->element = element;
+
+ if(element->isFilled())
+ svpelement->fillPainter = new AggFillPaintServer(element);
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0)
+ svpelement->strokePainter = new AggStrokePaintServer(element);
+
+ m_drawItems.append(svpelement);
+ }
+}
+
+AggText::SVPElement::~SVPElement()
+{
+ delete svp;
+ delete fillPainter;
+ delete strokePainter;
+}
+
+// ###
+
+AggGradient::AggGradient(SVGGradientElementImpl *gradient) : m_gradient(gradient)
+{
+}
+
+void AggGradient::parseGradientStops(SVGGradientElementImpl *gradient)
+{
+ bool srgb = m_gradient->getColorInterpolation() == CI_SRGB;
+ int r = 0, g = 0, b = 0, a = 255, r1 = 0, g1 = 0, b1 = 0, a1 = 255;
+ unsigned int end = 255;
+ float oldOffset = -1, newOffset = -1;
+ for(DOM::Node node = gradient->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGStopElementImpl *elem = dynamic_cast<SVGStopElementImpl *>(gradient->ownerDoc()->getElementFromHandle(node.handle()));
+ if(node.nodeName() == "stop" && elem)
+ {
+ oldOffset = newOffset;
+ newOffset = elem->offset()->baseVal();
+
+ // Spec: skip double offset specifications
+ if(oldOffset == newOffset)
+ continue;
+
+ //offsets++;
+
+ // Get color
+ QColor qStopColor;
+
+ if(elem->getStopColor()->colorType() == SVG_COLORTYPE_CURRENTCOLOR)
+ qStopColor = elem->getColor()->rgbColor().color();
+ else
+ qStopColor = elem->getStopColor()->rgbColor().color();
+
+ // Convert in an agg suitable form
+ QString tempName = qStopColor.name();
+ const char *str = tempName.latin1();
+
+ // We need to take into account fill/stroke opacity, if available (Rob)
+ float opacity = 1.0;
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(getBBoxTarget());
+ if(style)
+ opacity = style->getFillOpacity() * style->getOpacity();
+ int stopColor = 0;
+
+ for(int i = 1; str[i]; i++)
+ {
+ int hexval;
+ if(str[i] >= '0' && str[i] <= '9')
+ hexval = str[i] - '0';
+ else if (str[i] >= 'A' && str[i] <= 'F')
+ hexval = str[i] - 'A' + 10;
+ else if (str[i] >= 'a' && str[i] <= 'f')
+ hexval = str[i] - 'a' + 10;
+ else
+ break;
+
+ stopColor = (stopColor << 4) + hexval;
+ }
+
+ // Apply stop-opacity
+ opacity *= elem->stopOpacity();
+
+ // Get rgba color including stop-opacity
+ Q_UINT32 rgba = (stopColor << 8) | int(floor(int(opacity * 255.0) + 0.5));
+
+ // Convert from separated to premultiplied alpha
+ a = rgba & 0xff;
+ r = !srgb ? linearRGBFromsRGB((rgba >> 24)) : (rgba >> 24);
+ g = !srgb ? linearRGBFromsRGB(((rgba >> 16) & 0xff)) : (rgba >> 16) & 0xff;
+ b = !srgb ? linearRGBFromsRGB(((rgba >> 8) & 0xff)) : (rgba >> 8) & 0xff;
+
+ end = int(newOffset * 255);
+ // interpolate
+ unsigned int start = (oldOffset == -1) ? 0 : int(oldOffset * 255);
+ if(oldOffset == -1)
+ {
+ r1 = r;
+ g1 = g;
+ b1 = b;
+ a1 = a;
+ }
+ int diffr = r - r1;
+ int diffg = g - g1;
+ int diffb = b - b1;
+ int diffa = a - a1;
+ unsigned int nsteps = end - start;
+ for(unsigned int i = 0;i <= nsteps;i++)
+ {
+ double diff = double(i) / double(nsteps);
+ m_colorprofile[start + i].r = !srgb ? sRGBFromLinearRGB(int(r1 + diff * diffr)) : int(r1 + diff * diffr);
+ m_colorprofile[start + i].g = !srgb ? sRGBFromLinearRGB(int(g1 + diff * diffg)) : int(g1 + diff * diffg);
+ m_colorprofile[start + i].b = !srgb ? sRGBFromLinearRGB(int(b1 + diff * diffb)) : int(b1 + diff * diffb);
+ m_colorprofile[start + i].a = !srgb ? sRGBFromLinearRGB(int(a1 + diff * diffa)) : int(a1 + diff * diffa);
+ }
+ r1 = r;
+ g1 = g;
+ b1 = b;
+ a1 = a;
+ }
+ }
+ // last section
+ for(unsigned int i = end;i <= 255;i++)
+ {
+ m_colorprofile[i].r = r;
+ m_colorprofile[i].g = g;
+ m_colorprofile[i].b = b;
+ m_colorprofile[i].a = a;
+ }
+}
+
+void AggGradient::finalizePaintServer()
+{
+ parseGradientStops(m_gradient->stopsSource());
+
+ QString _href = SVGURIReferenceImpl::getTarget(m_gradient->href()->baseVal().string());
+ if(!_href.isEmpty())
+ reference(_href);
+
+ setFinalized();
+}
+
+void AggGradient::reference(const QString &/*href*/)
+{
+}
+
+void AggLinearGradient::render(AggCanvas *c)
+{
+ SVGLinearGradientElementImpl *linear = dynamic_cast<SVGLinearGradientElementImpl *>(m_gradient);
+
+ linear->converter()->finalize(getBBoxTarget(), linear->ownerSVGElement(), linear->gradientUnits()->baseVal());
+
+ double _x1 = linear->x1()->baseVal()->value();
+ double _y1 = linear->y1()->baseVal()->value();
+ double _x2 = linear->x2()->baseVal()->value();
+ double _y2 = linear->y2()->baseVal()->value();
+
+ // Adjust to gradient transform
+ SVGMatrixImpl *gradTrans = linear->gradientTransform()->baseVal()->concatenate();
+ if(gradTrans)
+ {
+ QWMatrix m = gradTrans->qmatrix();
+ m.map(_x1, _y1, &_x1, &_y1);
+ m.map(_x2, _y2, &_x2, &_y2);
+ gradTrans->deref();
+ }
+
+ // Get the basic bbox that will be the rendering area
+ SVGRectImpl *userBBox = getBBoxTarget()->getBBox();
+
+ // Compute x1, y1, x2 and y2
+ bool objectbbox = (linear->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+
+ // Respect current transformation matrix (so gradients zoom with...)
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(getBBoxTarget());
+ const SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->screenCTM();
+
+ if(objectbbox)
+ {
+ _x1 += userBBox->x();
+ _y1 += userBBox->y();
+ _x2 += userBBox->x();
+ _y2 += userBBox->y();
+ }
+
+ userBBox->deref();
+
+ gradient_polymorphic_wrapper_base* gr_ptr = &m_linPad;
+ if(linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT)
+ gr_ptr = &m_linRepeat;
+ else if(linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT)
+ gr_ptr = &m_linReflect;
+
+ agg::trans_affine mtx_g1;
+ double dx = _x2 - _x1;
+ double dy = _y2 - _y1;
+ double angle = (atan2(dy, dx));
+ mtx_g1 *= agg::trans_affine_rotation(angle);
+ mtx_g1 *= agg::trans_affine_translation(_x1, _y1);
+ mtx_g1 *= agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f());
+ mtx_g1.invert();
+
+ double len = sqrt(dx * dx + dy * dy);
+ if(len > 0)
+ {
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ typedef agg::span_gradient<agg::rgba8,
+ interpolator_type,
+ gradient_polymorphic_wrapper_base,
+ color_function_profile> gradient_span_gen;
+ typedef agg::span_allocator<gradient_span_gen::color_type> gradient_span_alloc;
+ color_function_profile colors(m_colorprofile);
+ gradient_span_alloc span_alloc;
+ interpolator_type inter(mtx_g1);
+ gradient_span_gen span_gen(span_alloc, inter, *gr_ptr, colors, 0, len);
+
+ agg::scanline_u8 sl;
+
+ if(c->nrChannels() == 3)
+ {
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_u<renderer_base, gradient_span_gen> renderer_gradient;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+
+ renderer_gradient r1(rb, span_gen);
+ c->m_ras.render(sl, r1);
+ }
+ else
+ {
+ typedef agg::pixfmt_rgba32 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_u<renderer_base, gradient_span_gen> renderer_gradient;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+
+ renderer_gradient r1(rb, span_gen);
+ c->m_ras.render(sl, r1);
+ }
+ }
+}
+
+void AggRadialGradient::render(AggCanvas *c)
+{
+ SVGRadialGradientElementImpl *radial = dynamic_cast<SVGRadialGradientElementImpl *>(m_gradient);
+
+ radial->converter()->finalize(getBBoxTarget(), radial->ownerSVGElement(), radial->gradientUnits()->baseVal());
+
+ double _cx = radial->cx()->baseVal()->value();
+ double _cy = radial->cy()->baseVal()->value();
+ double _fx = radial->fx()->baseVal()->value();
+ double _fy = radial->fy()->baseVal()->value();
+ double _r = radial->r()->baseVal()->value();
+
+ // Get the basic bbox that will be the rendering area
+ SVGRectImpl *screenBBox = getBBoxTarget()->getBBoxInternal();
+
+ if(screenBBox->width() == 0 || screenBBox->height() == 0)
+ {
+ screenBBox->deref();
+ return;
+ }
+
+ screenBBox->deref();
+
+ // Compute x1, y1, x2 and y2
+ bool objectbbox = (radial->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+
+ SVGRectImpl *userBBox = getBBoxTarget()->getBBox();
+ float width = userBBox->width();
+ float height = userBBox->height();
+
+ if(objectbbox)
+ {
+ _cx += userBBox->x();
+ _cy += userBBox->y();
+ _fx += userBBox->x();
+ _fy += userBBox->y();
+ }
+
+ gradient_polymorphic_wrapper_base* gr_ptr = &m_radialPad;
+ if(radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT)
+ gr_ptr = &m_radialRepeat;
+ else if(radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT)
+ gr_ptr = &m_radialReflect;
+
+ agg::trans_affine mtx_g1;
+
+
+ // Adjust to gradient transform
+ SVGMatrixImpl *gradTrans = radial->gradientTransform()->baseVal()->concatenate();
+ if(gradTrans)
+ {
+ agg::trans_affine mtx;
+ QWMatrix m = gradTrans->qmatrix();
+ mtx = agg::trans_affine(m.m11(), m.m12(), m.m21(), m.m22(), m.dx(), m.dy());
+ gradTrans->deref();
+ mtx_g1 *= mtx;
+ }
+
+ userBBox->deref();
+
+ int diff = int(width - height); // allow slight tolerance
+ if(objectbbox && !(diff > -2 && diff < 2))
+ {
+ // make elliptical or circular depending on bbox aspect ratio
+ float ratioX = (width / height) * sqrt(2);
+ float ratioY = (height / width) * sqrt(2);
+ mtx_g1 *= agg::trans_affine_scaling((width > height) ? sqrt(2) : ratioX, (width > height) ? ratioY :sqrt(2));
+ }
+
+ mtx_g1 *= agg::trans_affine_translation(_cx, _cy);
+
+ // Respect current transformation matrix (so gradients zoom with...)
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(getBBoxTarget());
+ const SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->screenCTM();
+
+ if(!matrix)
+ return;
+
+ mtx_g1 *= agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f());
+
+ mtx_g1.invert();
+
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ typedef agg::span_gradient<agg::rgba8,
+ interpolator_type,
+ gradient_polymorphic_wrapper_base,
+ color_function_profile> gradient_span_gen;
+ typedef agg::span_allocator<gradient_span_gen::color_type> gradient_span_alloc;
+ color_function_profile colors(m_colorprofile);
+ gradient_span_alloc span_alloc;
+ interpolator_type inter(mtx_g1);
+ gradient_span_gen span_gen(span_alloc, inter, *gr_ptr, colors, 0, _r);
+
+ agg::scanline_u8 sl;
+ if(c->nrChannels() == 3)
+ {
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_u<renderer_base, gradient_span_gen> renderer_gradient;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+
+ renderer_gradient r1(rb, span_gen);
+ c->m_ras.render(sl, r1);
+ }
+ else
+ {
+ typedef agg::pixfmt_rgba32 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_u<renderer_base, gradient_span_gen> renderer_gradient;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+
+ renderer_gradient r1(rb, span_gen);
+ c->m_ras.render(sl, r1);
+ }
+}
+
+AggPattern::AggPattern(SVGPatternElementImpl *pattern) : AggPaintServer(), m_pattern(pattern)
+{
+}
+
+void AggPattern::finalizePaintServer()
+{
+ m_pattern->finalizePaintServer();
+ setFinalized();
+}
+
+void AggPattern::reference(const QString &href)
+{
+ m_pattern->reference(href);
+}
+
+void AggPattern::render(AggCanvas *c)
+{
+ SVGPatternElementImpl::Tile tile = m_pattern->createTile(getBBoxTarget());
+
+ if(!tile.image().isNull())
+ {
+ QWMatrix m = tile.screenToTile();
+ double affine[6];
+
+ affine[0] = m.m11();
+ affine[1] = m.m12();
+ affine[2] = m.m21();
+ affine[3] = m.m22();
+ affine[4] = m.dx();
+ affine[5] = m.dy();
+
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_p_solid<renderer_base> renderer_solid;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+ renderer_solid rs(rb);
+ //double width = c->buf().width();
+ //double height = c->buf().height();
+
+ typedef agg::span_pattern_rgba32<agg::order_rgba32> span_gen_type;
+ typedef agg::renderer_scanline_u<renderer_base, span_gen_type> renderer_type;
+
+ SVGRectImpl *screenBBox = getBBoxTarget()->getBBoxInternal();
+ double offset_x = affine[4];
+ double offset_y = affine[5];
+ screenBBox->deref();
+ agg::rendering_buffer m_pattern_rbuf;
+ m_pattern_rbuf.attach(tile.image().bits(), tile.image().width(), tile.image().height(), tile.image().width() * 4);
+ agg::span_allocator<agg::rgba8> sa;
+ span_gen_type sg(sa, m_pattern_rbuf, unsigned(offset_x), unsigned(offset_y));
+
+ renderer_type rp(rb, sg);
+
+ agg::scanline_u8 sl;
+ rs.color(agg::rgba(0,0,0));
+ c->m_ras.render(sl, rp);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/AggCanvasItems.h b/ksvg/plugin/backends/agg/AggCanvasItems.h
new file mode 100644
index 00000000..a8c242ec
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvasItems.h
@@ -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
+ 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 AGGCANVASITEMS_H
+#define AGGCANVASITEMS_H
+
+#include "CanvasItem.h"
+#include "CanvasItems.h"
+#include "BezierPathAgg.h"
+
+#include "SVGPathElementImpl.h"
+#include "SVGPolyElementImpl.h"
+#include "SVGLineElementImpl.h"
+#include "SVGRectElementImpl.h"
+#include "SVGTextElementImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGCircleElementImpl.h"
+#include "SVGEllipseElementImpl.h"
+
+#include "agg_basics.h"
+#include "agg_conv_transform.h"
+#include "agg_conv_curve.h"
+#include "agg_conv_dash.h"
+#include "agg_conv_stroke.h"
+#include "agg_conv_clip_polygon.h"
+#include "agg_span_gradient.h"
+
+#include "SVGBBoxTarget.h"
+
+// gradient helpers
+
+//------------------------------------------------------------------------
+class gradient_polymorphic_wrapper_base
+{
+public:
+ virtual int calculate(int x, int y, int) const = 0;
+};
+
+template<class GradientF>
+class gradient_polymorphic_wrapper : public gradient_polymorphic_wrapper_base
+{
+public:
+ virtual int calculate(int x, int y, int d) const
+ {
+ return m_gradient.calculate(x, y, d);
+ }
+private:
+ GradientF m_gradient;
+};
+
+class gradient_radial_repeat
+{
+public:
+ int calculate(int x, int y, int d) const
+ {
+ return int(sqrt(pow(x, 2) + pow(y, 2))) % d;
+ }
+};
+
+class gradient_radial_reflect
+{
+public:
+ int calculate(int x, int y, int d) const
+ {
+ int dist = int(sqrt(pow(x, 2) + pow(y, 2)));
+ if((dist / d) % 2 == 0)
+ return dist % d;
+ else
+ return d - (dist % d);
+ }
+};
+
+class gradient_linear_repeat
+{
+public:
+ int calculate(int x, int y, int d) const
+ {
+ return (x < 0) ? (d - (-x % d)) : (x % d);
+ }
+};
+
+class gradient_linear_reflect
+{
+public:
+ int calculate(int x, int y, int d) const
+ {
+ if((abs(x) / d) % 2 == 0)
+ return (x < 0) ? (-x % d) : (x % d);
+ else
+ return (x > 0) ? (d - (x % d)) : (d - (-x % d));
+ }
+};
+
+
+#define AGG_CLASS(Class, Type, Member) \
+class Agg##Class : public AggShape \
+{ \
+public: \
+ Agg##Class(AggCanvas *c, Type *Member); \
+ virtual ~Agg##Class() { } \
+ virtual void draw(); \
+ virtual bool isVisible(); \
+ virtual void init(); \
+ virtual void init(const SVGMatrixImpl *screenCTM); \
+ virtual SVGElementImpl *element() const { return m_##Member; } \
+protected: \
+ Type *m_##Member; \
+};
+
+class stroke_dash_base
+{
+public:
+ virtual ~stroke_dash_base() {}
+
+ virtual void rewind(unsigned) = 0;
+ virtual unsigned vertex(double*, double*) = 0;
+};
+
+template<class Source>
+class stroke : public stroke_dash_base
+{
+public:
+ typedef agg::conv_stroke<Source> stroke_type;
+
+ stroke(Source& src, KSVG::SVGStylableImpl *style);
+
+ void rewind(unsigned id) { m_s.rewind(id); }
+ unsigned vertex(double* x, double* y) { return m_s.vertex(x, y); }
+
+private:
+ stroke_type m_s;
+};
+
+template<class Source>
+class dash_stroke : public stroke_dash_base
+{
+public:
+ typedef agg::conv_dash<Source> dash_type;
+ typedef agg::conv_stroke<dash_type> dash_stroke_type;
+
+ dash_stroke(Source& src, KSVG::SVGStylableImpl *style);
+
+ void rewind(unsigned id) { m_ds.rewind(id); }
+ unsigned vertex(double* x, double* y) { return m_ds.vertex(x, y); }
+
+private:
+ dash_type m_d;
+ dash_stroke_type m_ds;
+};
+
+template<class Source>
+class dash_stroke_simple
+{
+public:
+ dash_stroke_simple(Source& src, KSVG::SVGStylableImpl *style);
+ ~dash_stroke_simple() { delete impl; }
+
+ void rewind(unsigned id) { impl->rewind(id); }
+ unsigned vertex(double* x, double* y) { return impl->vertex(x, y); }
+
+private:
+ stroke_dash_base *impl;
+};
+
+typedef dash_stroke_simple<curved> curved_stroked;
+typedef agg::conv_transform<curved_stroked> curved_stroked_trans;
+typedef agg::conv_clip_polygon<curved_stroked_trans> curved_stroked_trans_clipped;
+typedef agg::conv_clip_polygon<curved_trans> curved_trans_clipped;
+//typedef agg::conv_contour<curved_trans> curved_trans_contour;
+//typedef agg::conv_clip_polygon<curved_trans_contour> curved_trans_contour_clipped;
+
+namespace KSVG
+{
+ class SVGGradientElementImpl;
+ class SVGRadialGradientElementImpl;
+ class SVGLinearGradientElementImpl;
+ class SVGPatternElementImpl;
+
+ class AggPaintServer : public CanvasPaintServer
+ {
+ public:
+ AggPaintServer() : CanvasPaintServer() {}
+ virtual ~AggPaintServer() {}
+
+ virtual void finalizePaintServer() = 0;
+ virtual void reference(const QString &href) = 0;
+
+ virtual void render(AggCanvas *c) = 0;
+ };
+
+ class AggGradient : public AggPaintServer
+ {
+ public:
+ AggGradient(SVGGradientElementImpl *gradient);
+ virtual ~AggGradient() {}
+
+ void parseGradientStops(SVGGradientElementImpl *gradient);
+
+ virtual void finalizePaintServer();
+ virtual void reference(const QString &href);
+
+ protected:
+ SVGGradientElementImpl *m_gradient;
+ agg::rgba8 m_colorprofile[256];
+ };
+
+ class AggLinearGradient : public AggGradient
+ {
+ public:
+ AggLinearGradient(SVGLinearGradientElementImpl *linear) : AggGradient(linear) {}
+
+ virtual void render(AggCanvas *c);
+
+ protected:
+ gradient_polymorphic_wrapper<agg::gradient_x> m_linPad;
+ gradient_polymorphic_wrapper<gradient_linear_repeat> m_linRepeat;
+ gradient_polymorphic_wrapper<gradient_linear_reflect> m_linReflect;
+ };
+
+ class AggRadialGradient : public AggGradient
+ {
+ public:
+ AggRadialGradient(SVGRadialGradientElementImpl *radial) : AggGradient(radial) {}
+
+ virtual void render(AggCanvas *c);
+
+ protected:
+ gradient_polymorphic_wrapper<agg::gradient_circle> m_radialPad;
+ gradient_polymorphic_wrapper<gradient_radial_repeat> m_radialRepeat;
+ gradient_polymorphic_wrapper<gradient_radial_reflect> m_radialReflect;
+ };
+
+ class AggPattern : public AggPaintServer
+ {
+ public:
+ AggPattern(SVGPatternElementImpl *pattern);
+ virtual ~AggPattern() {}
+
+ virtual void finalizePaintServer();
+ virtual void reference(const QString &);
+
+ virtual void render(AggCanvas *c);
+
+ protected:
+ SVGPatternElementImpl *m_pattern;
+ };
+
+ class AggCanvas;
+
+ class AggFillPaintServer
+ {
+ public:
+ AggFillPaintServer(SVGStylableImpl *style);
+ void update(SVGStylableImpl *style);
+ template<class VertexSource>
+ void draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape);
+
+ private:
+ agg::rgba8 m_color;
+ };
+
+ class AggStrokePaintServer
+ {
+ public:
+ AggStrokePaintServer(SVGStylableImpl *style);
+ void update(SVGStylableImpl *style);
+ template<class VertexSource>
+ void draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape);
+
+ private:
+ agg::rgba8 m_color;
+ };
+
+ class BezierPathAggStroked : public T2P::BezierPathAgg
+ {
+ public:
+ BezierPathAggStroked(SVGStylableImpl *style);
+ BezierPathAggStroked(const T2P::BezierPathAgg &other, SVGStylableImpl *style);
+
+ curved_trans_clipped m_curved_trans_clipped;
+ curved_stroked m_curved_stroked;
+ curved_stroked_trans m_curved_stroked_trans;
+ curved_stroked_trans_clipped m_curved_stroked_trans_clipped;
+ SVGStylableImpl *m_style;
+ };
+
+ class AggShape : public CanvasItem, public BezierPathAggStroked
+ {
+ public:
+ AggShape(AggCanvas *c, SVGStylableImpl *style);
+ virtual ~AggShape();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &p);
+ virtual bool strokeContains(const QPoint &p);
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0);
+ void draw(SVGShapeImpl *shape);
+ void calcSVPs(const SVGMatrixImpl *matrix);
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *);
+ bool isVisible(SVGShapeImpl *shape);
+
+ void setRenderContext(RenderContext context) { m_context = context; }
+
+ agg::path_storage &storage() { return m_storage; }
+ agg::trans_affine &transform() { return m_transform; }
+
+ protected:
+ void freeSVPs();
+
+ RenderContext m_context;
+ AggCanvas *m_canvas;
+ QRect m_bbox;
+ AggFillPaintServer *m_fillPainter;
+ AggStrokePaintServer *m_strokePainter;
+ };
+
+ AGG_CLASS(Rectangle, SVGRectElementImpl, rect)
+ AGG_CLASS(Ellipse, SVGEllipseElementImpl, ellipse)
+ AGG_CLASS(Circle, SVGCircleElementImpl, circle)
+
+ class AggLine : public AggShape, public MarkerHelper
+ {
+ public:
+ AggLine(AggCanvas *c, SVGLineElementImpl *line);
+ virtual ~AggLine();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual SVGElementImpl *element() const { return m_line; }
+
+ protected:
+ SVGLineElementImpl *m_line;
+ };
+
+ class AggPoly : public AggShape, public MarkerHelper
+ {
+ public:
+ AggPoly(AggCanvas *c, SVGPolyElementImpl *poly);
+ virtual ~AggPoly();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM) = 0;
+
+ virtual SVGElementImpl *element() const { return m_poly; }
+
+ protected:
+ SVGPolyElementImpl *m_poly;
+
+ };
+ class AggPolyline : public AggPoly
+ {
+ public:
+ AggPolyline(AggCanvas *c, SVGPolylineElementImpl *poly);
+ virtual ~AggPolyline();
+
+ virtual void init(const SVGMatrixImpl *screenCTM);
+ };
+
+ class AggPolygon : public AggPoly
+ {
+ public:
+ AggPolygon(AggCanvas *c, SVGPolygonElementImpl *poly);
+ virtual ~AggPolygon();
+
+ virtual void init(const SVGMatrixImpl *screenCTM);
+ };
+
+ class AggPath : public AggShape, public ::SVGPathParser, public MarkerHelper
+ {
+ public:
+ AggPath(AggCanvas *c, SVGPathElementImpl *path);
+ virtual ~AggPath();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual SVGElementImpl *element() const { return m_path; }
+
+ protected:
+ SVGPathElementImpl *m_path;
+
+ virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true);
+ virtual void svgLineTo(double x1, double y1, bool abs = true);
+ virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true);
+ virtual void svgClosePath();
+ };
+
+ class AggMarker : public CanvasMarker
+ {
+ public:
+ AggMarker(AggCanvas *c, SVGMarkerElementImpl *marker);
+ virtual ~AggMarker();
+
+ virtual QRect bbox() const { return QRect(); }
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int = 0, int = 0) { }
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible() { return false; }
+
+ void draw(SVGShapeImpl *obj, int x, int y, float lwidth = 1.0, double angle = 0.0);
+ //const ArtSVP *clippingRectangle() const { return m_clippingRectangle; }
+
+ protected:
+ AggCanvas *m_canvas;
+ //ArtSVP *m_clippingRectangle;
+ };
+
+ class AggImage : public CanvasItem
+ {
+ public:
+ AggImage(AggCanvas *c, SVGImageElementImpl *image);
+ virtual ~AggImage();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int = 0, int = 0) { }
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible();
+
+ virtual SVGElementImpl *element() const { return m_image; }
+
+ protected:
+ AggCanvas *m_canvas;
+ SVGImageElementImpl *m_image;
+ };
+
+ class AggText : public CanvasText
+ {
+ public:
+ AggText(AggCanvas *c, SVGTextElementImpl *text);
+ virtual ~AggText();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &p);
+ virtual bool strokeContains(const QPoint &p);
+ virtual void update(CanvasItemUpdate, int param1 = 0, int param2 = 0);
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const;
+
+ virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const;
+
+ unsigned operator [](unsigned) const { return 0; }
+
+ protected:
+ AggCanvas *m_canvas;
+
+ private:
+ void clearCurved();
+ class SVPElement
+ {
+ public:
+ SVPElement() { svp = 0; element = 0; fillPainter = 0; strokePainter = 0; }
+ ~SVPElement();
+
+ BezierPathAggStroked *svp;
+ SVGTextContentElementImpl *element;
+ AggFillPaintServer *fillPainter;
+ AggStrokePaintServer *strokePainter;
+ };
+
+ mutable QPtrList<SVPElement> m_drawItems;
+ };
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/BezierPathAgg.cpp b/ksvg/plugin/backends/agg/BezierPathAgg.cpp
new file mode 100644
index 00000000..10a75c1c
--- /dev/null
+++ b/ksvg/plugin/backends/agg/BezierPathAgg.cpp
@@ -0,0 +1,126 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ 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 <math.h>
+#include "Point.h"
+#include "BezierPathAgg.h"
+
+#include <kdebug.h>
+
+#include <agg_basics.h>
+#include <agg_bounding_rect.h>
+
+using namespace T2P;
+
+double BezierPathAgg::length(double t)
+{
+ if(m_length < 0.0)
+ {
+ double total = 0.0;
+ double x = 0.0, y = 0.0;
+ double x2, y2;
+ unsigned cmd;
+ unsigned int id = 0;
+ m_curved_trans.rewind(id);
+ while(!agg::is_stop(cmd = m_curved_trans.vertex(&x2, &y2)))
+ {
+ if(agg::is_move_to(cmd))
+ {
+ x = x2;
+ y = y2;
+ }
+ else if(agg::is_line_to(cmd))
+ {
+ double dx = x, dy = y;
+ dx = x2 - dx;
+ dy = y2 - dy;
+ total += sqrt(pow(dx, 2) + pow(dy, 2));
+ x = x2;
+ y = y2;
+ }
+ }
+ return total * t;
+ }
+ else
+ return m_length * t;
+}
+
+void BezierPathAgg::pointTangentNormalAt(double t, Point *p, Point *tn, Point *n)
+{
+ double totallen = length(t);
+ double total = 0.0;
+ double x = 0.0, y = 0.0;
+ double x2, y2;
+ unsigned cmd;
+ unsigned int id = 0;
+ m_curved_trans.rewind(id);
+ while(!agg::is_stop(cmd = m_curved_trans.vertex(&x2, &y2)))
+ {
+ if(agg::is_move_to(cmd))
+ {
+ x = x2;
+ y = y2;
+ }
+ else if(agg::is_line_to(cmd))
+ {
+ double dx = x, dy = y;
+ x = x2;
+ y = y2;
+ dx = x - dx;
+ dy = y - dy;
+ double seg_len = sqrt(pow(dx, 2) + pow(dy, 2));
+ total += seg_len;
+ if(total >= totallen)
+ {
+ double fract = 1 - (totallen - (total - seg_len)) / seg_len;
+ if(p)
+ {
+ p->setX(x - dx * fract);
+ p->setY(y - dy * fract);
+ }
+ if(tn)
+ {
+ //kdDebug() << k_funcinfo << "dx : " << dx << endl;
+ //kdDebug() << k_funcinfo << "dy : " << dy << endl;
+ tn->setX(dx);
+ tn->setY(dy);
+ }
+ if(n)
+ {
+ // Calculate vector product of "binormal" x tangent
+ // (0,0,1) x (dx,dy,0), which is simply (dy,-dx,0).
+ n->setX(dy);
+ n->setY(-dx);
+ }
+ return;
+ }
+ }
+ }
+}
+
+void BezierPathAgg::boundingBox(Point *topLeft, Point *bottomRight)
+{
+ double x1, y1, x2, y2;
+ agg::bounding_rect(m_curved, *this, 0, 1, &x1, &y1, &x2, &y2);
+ *topLeft = Point(x1, y1);
+ *bottomRight = Point(x2, y2);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/BezierPathAgg.h b/ksvg/plugin/backends/agg/BezierPathAgg.h
new file mode 100644
index 00000000..21451aa9
--- /dev/null
+++ b/ksvg/plugin/backends/agg/BezierPathAgg.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ 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 T2P_BEZIERPATH_AGG_H
+#define T2P_BEZIERPATH_AGG_H
+
+#include <agg_curves.h>
+#include <agg_conv_curve.h>
+#include <agg_conv_stroke.h>
+#include <agg_path_storage.h>
+#include <agg_conv_transform.h>
+
+#include "Affine.h"
+#include "BezierPath.h"
+
+typedef agg::conv_curve<agg::path_storage> curved;
+typedef agg::conv_transform<curved> curved_trans;
+
+namespace T2P
+{
+ class BezierPathAgg : public BezierPath
+ {
+ public:
+ BezierPathAgg() : BezierPath(),
+ m_curved(m_storage), m_curved_trans(m_curved, m_transform)
+ {
+ m_length = -1;
+ }
+
+ ~BezierPathAgg() {}
+
+ BezierPathAgg(const BezierPathAgg &other) : BezierPath(), m_storage(other.m_storage),
+ m_curved(m_storage), m_curved_trans(m_curved, m_transform)
+ {
+ m_transform = other.m_transform;
+ m_length = other.m_length;
+ }
+
+ void copy_from(const agg::path_storage &ps, Affine &affine)
+ {
+ for(unsigned i = 0; i < ps.total_vertices(); i++)
+ {
+ double x, y;
+ unsigned cmd = ps.vertex(i, &x, &y);
+ m_storage.add_vertex(affine.dx() + x * affine.m11() + y * affine.m21(),
+ affine.dy() + x * affine.m12() + y * affine.m22(), cmd);
+ }
+ }
+
+ unsigned operator [](unsigned) { return 0; }
+
+ virtual double length(double t = 1.0);
+ virtual void pointTangentNormalAt(double t, Point *p = 0, Point *tn = 0, Point *n = 0);
+ virtual void boundingBox(Point *topLeft, Point *bottomRight);
+
+ agg::path_storage m_storage;
+ curved m_curved;
+ curved_trans m_curved_trans;
+ agg::trans_affine m_transform;
+ double m_length;
+ };
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp b/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp
new file mode 100644
index 00000000..39b00146
--- /dev/null
+++ b/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ 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 <iostream>
+
+#include "Glyph.h"
+#include "Point.h"
+#include "BezierPathAgg.h"
+#include "GlyphTracerAgg.h"
+
+using namespace T2P;
+
+int traceMoveto(FT_Vector *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ bpath->m_storage.move_to(p.x(), p.y());
+ return 0;
+}
+
+int traceLineto(FT_Vector *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ bpath->m_storage.line_to(p.x(), p.y());
+ return 0;
+}
+
+int traceConicBezier(FT_Vector *control, FT_Vector *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ Point c = affine.mapPoint(Point(control->x, control->y));
+ Point p = affine.mapPoint(Point(to->x, to->y));
+
+ double sx, sy;
+ bpath->m_storage.vertex(bpath->m_storage.total_vertices() - 1, &sx, &sy);
+ bpath->m_storage.curve4(c.x() - (c.x() - sx) / 3, c.y() - (c.y() - sy) / 3,
+ c.x() + (p.x() - c.x()) / 3, c.y() + (p.y() - c.y()) / 3, p.x(), p.y());
+
+ return 0;
+}
+
+int traceCubicBezier(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ Point c1 = affine.mapPoint(Point(control1->x, control1->y));
+ Point c2 = affine.mapPoint(Point(control2->x, control2->y));
+ bpath->m_storage.curve4(c1.x(), c1.y(), c2.x(), c2.y(), p.x(), p.y());
+ return 0;
+}
+
+GlyphTracerAgg::GlyphTracerAgg() : GlyphTracer()
+{
+ setMoveto(*traceMoveto);
+ setLineto(*traceLineto);
+ setConicBezier(*traceConicBezier);
+ setCubicBezier(*traceCubicBezier);
+}
+
+GlyphTracerAgg::~GlyphTracerAgg()
+{
+}
+
+void GlyphTracerAgg::correctGlyph(GlyphAffinePair *glyphAffine)
+{
+
+ // Take bezier path belonging to glyph (Note: that one is _UNMODIFIABLE_, once calculated)
+ const BezierPathAgg *path = static_cast<const BezierPathAgg *>(glyphAffine->glyph()->bezierPath());
+
+ BezierPathAgg *transformatedPath = static_cast<BezierPathAgg *>(allocBezierPath(0));
+ Affine &affine = glyphAffine->affine();
+ transformatedPath->copy_from(path->m_storage, affine);
+ glyphAffine->setTransformatedPath(transformatedPath);
+}
+
+BezierPath *GlyphTracerAgg::allocBezierPath(int)
+{
+ return new BezierPathAgg();
+}
+
+void GlyphTracerAgg::closePath(Glyph *glyph)
+{
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ bpath->m_storage.close_polygon();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/GlyphTracerAgg.h b/ksvg/plugin/backends/agg/GlyphTracerAgg.h
new file mode 100644
index 00000000..5fb24d4b
--- /dev/null
+++ b/ksvg/plugin/backends/agg/GlyphTracerAgg.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ 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 T2P_GLYPHTRACER_AGG_H
+#define T2P_GLYPHTRACER_AGG_H
+
+#include "GlyphTracer.h"
+
+// FreeType 2 includes
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace T2P
+{
+ class Glyph;
+ class BezierPath;
+
+ class GlyphTracerAgg : public GlyphTracer
+ {
+ public:
+ GlyphTracerAgg();
+ ~GlyphTracerAgg();
+
+ virtual void correctGlyph(GlyphAffinePair *glyphAffine);
+ virtual BezierPath *allocBezierPath(int size);
+ virtual void closePath(Glyph *glyph);
+ };
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/Makefile.am b/ksvg/plugin/backends/agg/Makefile.am
new file mode 100644
index 00000000..4e883809
--- /dev/null
+++ b/ksvg/plugin/backends/agg/Makefile.am
@@ -0,0 +1,15 @@
+kde_module_LTLIBRARIES = libksvgrendereragg.la
+
+# Damn agg2 has no configuration querying possibility!
+AGG_CFLAGS = -I/cvs/agg2/include/
+AGG_LIBS = /cvs/agg2/src/libagg.a
+
+libksvgrendereragg_la_SOURCES = BezierPathAgg.cpp GlyphTracerAgg.cpp AggCanvas.cpp AggCanvasItems.cpp AggCanvasFactory.cpp
+libksvgrendereragg_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libksvgrendereragg_la_LIBADD = ../../../libksvg.la $(AGG_LIBS)
+libksvgrendereragg_la_METASOURCES = AUTO
+
+kde_services_DATA = ksvgaggcanvas.desktop
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+INCLUDES = $(KDE_INCLUDES) $(AGG_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes)
diff --git a/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop b/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop
new file mode 100644
index 00000000..ac51836b
--- /dev/null
+++ b/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop
@@ -0,0 +1,101 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KSVG/Renderer
+X-KDE-Library=libksvgrendereragg
+X-KSVG-InternalName=agg
+Name=KSVG Rendering Backend - Anti Grain Geometry
+Name[ar]=خلفية رسم ل KSVG - هندسة Anti Grain
+Name[bs]=KSVG renderiranje - Anti Grain Geometry
+Name[ca]=Representació en segon pla de KSVG - Geometria anti gra
+Name[cs]=Vykreslovací nástroj KSVG - Anti Grain Geometry
+Name[cy]=Ôl-wyneb Llunio KSVG - Geometreg Wrth-Raen
+Name[da]=Underliggende program for KSVG-visning - antikorn geometri
+Name[de]=KSVG-Darstellungsmodul - Antikörnungs-Geometrie
+Name[el]= Σύστημα υποστήριξης αποτύπωσης του KSVG - Anti Grain Geometry
+Name[es]=Motor de procesado de KSVG - Geometría suavizada
+Name[et]=KSVG renderdamise taustarakendus - teralisusevastane geomeetria (AGG)
+Name[eu]=KSVG errendatze programa - Anti Grain geometriarekin
+Name[fa]=پایانۀ پشتیبانی پرداخت KSVG - هندسۀ ضد ذره
+Name[fi]=KSVG-piirtäjän taustaohjelma - sileä geometria
+Name[fr]=Moteur de rendu KSVG - Anti Grain Geometry
+Name[gl]=Mecanismo de Interpretación KSVG - Xeometría Anti-gran
+Name[he]=מנוע רינדור KSVG
+Name[hi]=के-एसवीजी रेंडरिंग बैकएण्ड- एन्टी ग्रेन ज्यामिती
+Name[hu]=KSVG megjelenítő motor - AGG (Anti Grain Geometry)
+Name[is]=KSVG teiknari - Anti Grain Geometry
+Name[it]=Backend KSVG per il rendering - Geometrie senza sgranature
+Name[ja]=KSVG レンダリングバックエンド - Anti Grain Geometry
+Name[kk]=KSVG кескіндеу бағдарламасы - қиыршықтыққа қарсы геометриясы
+Name[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG - រាង​មិន​គ្រើម
+Name[lt]=KSVG atkūrimo programinė sąsaja - Anti Grain geometrija
+Name[ms]=Tepi Belakang KSVG - Geometri Anti Bijian
+Name[nb]=Modul for KSVG-tegning – antikorngeometri
+Name[nds]=KSVG-Dorstellhölper - Antigrissel-Geometrie
+Name[ne]=KSVG रेन्डरिङ ब्याकइन्ड - एन्टि ग्रेन ज्योमेट्रि
+Name[nl]=KSVG weergavecomponent - Anti Grain Geometry
+Name[nn]=Modul for KSVG-teikning – antikorngeometri
+Name[pl]=Narzędzie do renderowania KSVG - nieziarnista geometria
+Name[pt]=Infra-Estrutura de Desenho do KSVG - Geometria Anti-Grão
+Name[pt_BR]=Estrutura de Renderização do KSVG - Geometria Anti-Grain
+Name[ro]=Motor de randare KSVG - Anti Grain Geometry
+Name[ru]=Движок отрисовки KSVG - противозернистая геометрия
+Name[sk]=Nástroj pre zobrazovanie KSVG - antigranularitná geometria
+Name[sl]=Izrisovalnik KSVG - Protizrnska geometrija
+Name[sr]=KSVG-ов позадински систем за рендеровање — Противзрнаста геометрија
+Name[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje — Protivzrnasta geometrija
+Name[sv]=KSVG-uppritningsmodul - geometri mot korninghet
+Name[ta]=KSVG வழங்கும் பின் அமைப்பு - ஆன்டி க்ரேன் ஜியோமெட்ரி
+Name[tg]=Лағжандаи тасовироти KSVG - геометрияи мутақобили гандумӣ
+Name[tr]=KSVG Derleme Aracı - Taneciksiz Geometri
+Name[uk]=Інтерфейс відтворення KSVG - AGG
+Name[zh_CN]=KSVG 渲染后端 - 反增长几何形状
+Name[zh_HK]=KSVG 合成後端 - Anti Grain Geometry
+Name[zh_TW]=KSVG 上色後端介面 - Anti Grain Geometry
+Comment=New, unstable ksvg rendering backend
+Comment[bs]=Novi, nestabilni ksvg renderiranje backend
+Comment[ca]=Nou, inestable representador en segon pla de ksvg
+Comment[cs]=Nový, nestabilní vykreslovací nástroj KSVG
+Comment[cy]=Ôl-wyneb llunio ksvg newydd, ansad
+Comment[da]=Nyt, ustabilt underliggende program til ksvg-visning
+Comment[de]=Neues, unausgereiftes KSVG-Darstellungsmodul
+Comment[el]=Νέο υπό ανάπτυξη σύστημα υποστήριξης αποτύπωσης
+Comment[es]=Nuevo motor de procesado de ksvg, inestable
+Comment[et]=Uus ebastabiilne ksvg renderdamise taustarakendus
+Comment[eu]=Berria, ksvg errendatze programa ezegonkorra
+Comment[fa]=جدید، پایانۀ پشتیبانی ناپایدار پرداخت ksvg
+Comment[fi]=Uusi epävakaa ksvg-piirtäjän taustaohjelma
+Comment[fr]=Nouveau moteur de rendu KSVG instable
+Comment[gl]=Novo e inestábel mecanismo de interpretación ksvg
+Comment[he]=חדש, מנוע רינדור לא יציב עבור KSVG
+Comment[hi]=नया, अस्थिर के-एसवीजी रेंडरिंग बैकएण्ड
+Comment[hu]=Új, még nem teljesen kiforrott megjelenítőmotor a KSVG-hez
+Comment[is]=Nýr og óstöðugur ksvg teiknari
+Comment[it]=Nuovo, instabile backend di KSVG per il rendering
+Comment[ja]=新しく、まだ開発途上の ksvg レンダリングバックエンド
+Comment[kk]=Жаңа, әлі тұрақсыз KSVG кескіндеу бағдарламасы
+Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ ksvg ថ្មី​តែ​មិន​សូវ​ឋិតថេរ
+Comment[lt]=Nauja, nestabili ksvg atkūrimo programinė sąsaja
+Comment[ms]=Tepi Belakang Menrealisasi ksvg yang baru dan tidak stabil
+Comment[nb]=Ny og ustabil modul for ksvg-tegning
+Comment[nds]=Nieg, nich stevig KSVG-Dorstellhölper
+Comment[ne]=नयाँ, अस्थिर ksvg रेन्डरिङ ब्याकइन्ड
+Comment[nl]=Nieuwe, niet stabiele KSVG weergavecomponent
+Comment[nn]=Ny og ustabil modul for ksvg-teikning
+Comment[pl]=Nowe, niestabilne, narzędzie do renderowania KSVG
+Comment[pt]=Uma infra-estrutura de desenho do ksvg, nova e instável
+Comment[pt_BR]=Nova e instável estrutura de renderização do ksvg
+Comment[ro]=Motor de randare KSVG nou, netestat suficient
+Comment[ru]=Новый, нестабильный движок прорисовки ksvg
+Comment[sk]=Nová, nestabilná verzia nástroja pre zobrazovanie ksvg
+Comment[sl]=Nov, nestabilen izrisovalnik KSVG
+Comment[sr]=Нов, нестабилан KSVG-ов позадински систем за рендеровање
+Comment[sr@Latn]=Nov, nestabilan KSVG-ov pozadinski sistem za renderovanje
+Comment[sv]=Ny, instabil KSVG-uppritningsmodul
+Comment[ta]=புதிய, நிலையில்லாத ksvg வழங்கும் பின் அமைப்பு
+Comment[tg]=Лағжандаи ғайриустувори тасовироти ksvg-и нав
+Comment[tr]=Yeni, stabil olmayan ksvg derleme aracı
+Comment[uk]=Новий, нестабільний інтерфейс відтворення KSVG
+Comment[zh_CN]=新的不稳定的 ksvg 渲染后端
+Comment[zh_HK]=新但不穩定的 ksvg 合成後端
+Comment[zh_TW]=新的,不穩定的 ksvg 上色後端介面
+author=Rob Buis <buis@kde.org>
diff --git a/ksvg/plugin/backends/libart/BezierPathLibart.cpp b/ksvg/plugin/backends/libart/BezierPathLibart.cpp
new file mode 100644
index 00000000..fb163952
--- /dev/null
+++ b/ksvg/plugin/backends/libart/BezierPathLibart.cpp
@@ -0,0 +1,160 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ 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 <math.h>
+#include "Point.h"
+#include "BezierPathLibart.h"
+
+#include <kdebug.h>
+
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_vpath_bpath.h>
+
+using namespace T2P;
+
+BezierPathLibart::BezierPathLibart() : BezierPath()
+{
+ m_array.resize(0);
+ m_length = -1;
+}
+
+BezierPathLibart::BezierPathLibart(ArtBpath *other) : BezierPath()
+{
+ int i = 0;
+ for(;other[i].code != ART_END; i++)
+ {
+ ensureSpace(m_array, i)
+ m_array[i] = other[i];
+ }
+ ensureSpace(m_array, i)
+ m_array[i].code = ART_END;
+}
+
+BezierPathLibart::~BezierPathLibart()
+{
+}
+
+double BezierPathLibart::length(double t)
+{
+ if(m_length < 0.0)
+ {
+ double total = 0.0;
+ // We cheat a bit...
+ ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25);
+ double x = 0.0, y = 0.0;
+ for(int i = 0; vpath[i].code != ART_END; i++)
+ {
+ if(vpath[i].code == ART_MOVETO)
+ {
+ x = vpath[i].x;
+ y = vpath[i].y;
+ }
+ else if(vpath[i].code == ART_LINETO)
+ {
+ double dx = x, dy = y;
+ x = vpath[i].x;
+ y = vpath[i].y;
+ dx = x - dx;
+ dy = y - dy;
+ total += sqrt(pow(dx, 2) + pow(dy, 2));
+ }
+ }
+ art_free(vpath);
+ return total * t;
+ }
+ else
+ return m_length * t;
+}
+
+void BezierPathLibart::pointTangentNormalAt(double t, Point *p, Point *tn, Point *n)
+{
+ double totallen = length(t);
+ // We cheat a bit...
+ ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25);
+ double total = 0.0;
+ double x = 0.0, y = 0.0;
+ for(int i = 0; vpath[i].code != ART_END; i++)
+ {
+ if(vpath[i].code == ART_MOVETO)
+ {
+ x = vpath[i].x;
+ y = vpath[i].y;
+ }
+ else if(vpath[i].code == ART_LINETO)
+ {
+ double dx = x, dy = y;
+ x = vpath[i].x;
+ y = vpath[i].y;
+ dx = x - dx;
+ dy = y - dy;
+ double seg_len = sqrt(pow(dx, 2) + pow(dy, 2));
+ total += seg_len;
+ if(total >= totallen)
+ {
+ double fract = 1 - (totallen - (total - seg_len)) / seg_len;
+ if(p)
+ {
+ p->setX(x - dx * fract);
+ p->setY(y - dy * fract);
+ }
+ // Calculate tangent
+ if(tn)
+ {
+ tn->setX(dx);
+ tn->setY(dy);
+ }
+ // Calculate normal vector.
+ if(n)
+ {
+ // Calculate vector product of "binormal" x tangent
+ // (0,0,1) x (dx,dy,0), which is simply (dy,-dx,0).
+ n->setX(dy);
+ n->setY(-dx);
+ }
+ return;
+ }
+ }
+ }
+ art_free(vpath);
+}
+
+void BezierPathLibart::boundingBox(Point *topLeft, Point *bottomRight)
+{
+ if(m_array.count() > 0)
+ {
+ // We cheat a bit...
+ ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25);
+
+ ArtDRect rect;
+ art_vpath_bbox_drect(vpath, &rect);
+ art_free(vpath);
+
+ *topLeft = Point(rect.x0, rect.y0);
+ *bottomRight = Point(rect.x1, rect.y1);
+ }
+ else
+ {
+ *topLeft = Point(0, 0);
+ *bottomRight = Point(0, 0);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/BezierPathLibart.h b/ksvg/plugin/backends/libart/BezierPathLibart.h
new file mode 100644
index 00000000..a6dfd2b9
--- /dev/null
+++ b/ksvg/plugin/backends/libart/BezierPathLibart.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ 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 T2P_BEZIERPATH_LIBART_H
+#define T2P_BEZIERPATH_LIBART_H
+
+#include "BezierPath.h"
+#include <qmemarray.h>
+
+class _ArtBpath;
+
+#define ensureSpace(vec, index) if((int)vec.size() == index) vec.resize(index + 1);
+
+namespace T2P
+{
+ class BezierPathLibart : public BezierPath
+ {
+ public:
+ BezierPathLibart();
+ BezierPathLibart(_ArtBpath *other);
+ ~BezierPathLibart();
+
+ virtual double length(double t = 1.0);
+ virtual void pointTangentNormalAt(double t, Point *p = 0, Point *tn = 0, Point *n = 0);
+ virtual void boundingBox(Point *topLeft, Point *bottomRight);
+
+ // Don't make those private members, these are all internal anyway...
+ QMemArray<_ArtBpath> m_array;
+ double m_length;
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp b/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp
new file mode 100644
index 00000000..b034c6e6
--- /dev/null
+++ b/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp
@@ -0,0 +1,177 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ 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 <iostream>
+
+#include <kdebug.h>
+
+#include "Glyph.h"
+#include "Point.h"
+#include "BezierPathLibart.h"
+#include "GlyphTracerLibart.h"
+
+#include <libart_lgpl/art_bpath.h>
+
+#include <config.h>
+
+#ifdef HAVE_FREETYPE_2_2_x
+ #define FT_VECTOR_PARAMETER const FT_Vector
+#else
+ #define FT_VECTOR_PARAMETER FT_Vector
+#endif
+
+using namespace T2P;
+
+int traceMoveto(FT_VECTOR_PARAMETER *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+
+ int index = path->m_array.count();
+ if(index == 0 ||
+ p.x() != path->m_array[index - 1].x3 ||
+ p.y() != path->m_array[index - 1].y3)
+ {
+ path->m_array.resize(index + 1);
+ path->m_array[index].code = ART_MOVETO;
+ path->m_array[index].x3 = p.x();
+ path->m_array[index].y3 = p.y();
+ }
+
+ return 0;
+}
+
+int traceLineto(FT_VECTOR_PARAMETER *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+
+ int index = path->m_array.count();
+ ArtBpath *last = &path->m_array[index - 1];
+
+ if((p.x() != last->x3) || (p.y() != last->y3))
+ {
+ path->m_array.resize(index + 1);
+ path->m_array[index].code = ART_LINETO;
+ path->m_array[index].x3 = p.x();
+ path->m_array[index].y3 = p.y();
+ }
+
+ return 0;
+}
+
+int traceConicBezier(FT_VECTOR_PARAMETER *control, FT_VECTOR_PARAMETER *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+
+ int index = path->m_array.count();
+ if(!(index > 0))
+ return -1;
+
+ path->m_array.resize(index + 1);
+ ArtBpath *s = &path->m_array[index - 1];
+ ArtBpath *e = &path->m_array[index];
+
+ e->code = ART_CURVETO;
+
+ Point c = affine.mapPoint(Point(control->x, control->y));
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ e->x3 = p.x();
+ e->y3 = p.y();
+
+ path->m_array[index].x1 = c.x() - (c.x() - s->x3) / 3;
+ path->m_array[index].y1 = c.y() - (c.y() - s->y3) / 3;
+ path->m_array[index].x2 = c.x() + (e->x3 - c.x()) / 3;
+ path->m_array[index].y2 = c.y() + (e->y3 - c.y()) / 3;
+
+ return 0;
+}
+
+int traceCubicBezier(FT_VECTOR_PARAMETER *control1, FT_VECTOR_PARAMETER *control2, FT_VECTOR_PARAMETER *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ Point c1 = affine.mapPoint(Point(control1->x, control1->y));
+ Point c2 = affine.mapPoint(Point(control2->x, control2->y));
+
+ int index = path->m_array.count();
+ path->m_array.resize(index + 1);
+ path->m_array[index].code = ART_CURVETO;
+ path->m_array[index].x1 = c1.x();
+ path->m_array[index].y1 = c1.y();
+ path->m_array[index].x2 = c2.x();
+ path->m_array[index].y2 = c2.y();
+ path->m_array[index].x3 = p.x();
+ path->m_array[index].y3 = p.y();
+
+ return 0;
+}
+
+GlyphTracerLibart::GlyphTracerLibart() : GlyphTracer()
+{
+ setMoveto(*traceMoveto);
+ setLineto(*traceLineto);
+ setConicBezier(*traceConicBezier);
+ setCubicBezier(*traceCubicBezier);
+}
+
+GlyphTracerLibart::~GlyphTracerLibart()
+{
+}
+
+void GlyphTracerLibart::correctGlyph(GlyphAffinePair *glyphAffine)
+{
+ // Take bezier path belonging to glyph (Note: that one is _UNMODIFIABLE_, once calculated)
+ const BezierPathLibart *path = static_cast<const BezierPathLibart *>(glyphAffine->glyph()->bezierPath());
+
+ // Create a new empty path with the same size
+ ArtBpath *transformed = art_bpath_affine_transform(path->m_array.data(), glyphAffine->affine().data());
+ BezierPathLibart *transformatedPath = new BezierPathLibart(transformed);
+ art_free(transformed);
+ glyphAffine->setTransformatedPath(transformatedPath);
+}
+
+BezierPath *GlyphTracerLibart::allocBezierPath(int)
+{
+ BezierPathLibart *bpath = new BezierPathLibart();
+ //if(size != 0)
+ // bpath->m_array.resize(size);
+
+ return bpath;
+}
+
+void GlyphTracerLibart::closePath(Glyph *glyph)
+{
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+ int index = path->m_array.count();
+ path->m_array.resize(index + 1);
+ path->m_array[index].code = ART_END;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/GlyphTracerLibart.h b/ksvg/plugin/backends/libart/GlyphTracerLibart.h
new file mode 100644
index 00000000..39b87490
--- /dev/null
+++ b/ksvg/plugin/backends/libart/GlyphTracerLibart.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ 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 T2P_GLYPHTRACER_LIBART_H
+#define T2P_GLYPHTRACER_LIBART_H
+
+#include "GlyphTracer.h"
+
+// FreeType 2 includes
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace T2P
+{
+ class Glyph;
+ class BezierPath;
+ class GlyphAffinePair;
+
+ class GlyphTracerLibart : public GlyphTracer
+ {
+ public:
+ GlyphTracerLibart();
+ virtual ~GlyphTracerLibart();
+
+ virtual void correctGlyph(GlyphAffinePair *glyphAffine);
+ virtual BezierPath *allocBezierPath(int size);
+ virtual void closePath(Glyph *glyph);
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvas.cpp b/ksvg/plugin/backends/libart/LibartCanvas.cpp
new file mode 100644
index 00000000..5697b623
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvas.cpp
@@ -0,0 +1,425 @@
+/*
+ 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 "LibartCanvas.h"
+#include "SVGMatrixImpl.h"
+#include "SVGRectImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGTextPositioningElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGMaskElementImpl.h"
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kgenericfactory.h>
+
+#include "SVGPaint.h"
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include <qimage.h>
+
+#include "KSVGHelper.h"
+#include "KSVGTextChunk.h"
+#include "LibartCanvasItems.h"
+
+#include <libart_lgpl/art_rgb.h>
+#include <libart_lgpl/art_affine.h>
+#include <libart_lgpl/art_alphagamma.h>
+#include <libart_lgpl/art_rgb_svp.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_ops.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_rect_svp.h>
+#include <libart_lgpl/art_svp_vpath.h>
+
+#include <libs/art_support/art_misc.h>
+#include <libs/art_support/art_rgba_svp.h>
+
+#include <Font.h>
+#include "BezierPathLibart.h"
+#include "GlyphTracerLibart.h"
+
+#include <fontconfig/fontconfig.h>
+
+ArtSVP *art_svp_from_rect(int x0, int y0, int x1, int y1)
+{
+ ArtVpath vpath[] =
+ {
+ { ART_MOVETO, x0, y0 },
+ { ART_LINETO, x0, y1 },
+ { ART_LINETO, x1, y1 },
+ { ART_LINETO, x1, y0 },
+ { ART_LINETO, x0, y0 },
+ { ART_END, 0, 0}
+ };
+
+ return art_svp_from_vpath(vpath);
+}
+
+ArtSVP *art_svp_from_irect(ArtIRect *bbox)
+{
+ return art_svp_from_rect(bbox->x0, bbox->y0, bbox->x1, bbox->y1);
+}
+
+ArtSVP *art_svp_from_qrect(const QRect& rect)
+{
+ return art_svp_from_rect(rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1);
+}
+
+using namespace KSVG;
+
+LibartCanvas::LibartCanvas(unsigned int width, unsigned int height) : KSVGCanvas(width, height)
+{
+ m_fontContext = new T2P::Converter(new T2P::GlyphTracerLibart());
+}
+
+T2P::BezierPath *LibartCanvas::toBezierPath(CanvasItem *item) const
+{
+ LibartPath *path = dynamic_cast<LibartPath *>(item);
+ if(!path)
+ return 0;
+
+ // Only handle LibartPath items
+ //T2P::BezierPathLibart *result = new T2P::BezierPathLibart(path->m_array.data());
+ return path;
+}
+
+// drawing primitives
+CanvasItem *LibartCanvas::createRectangle(SVGRectElementImpl *rect)
+{
+ return new LibartRectangle(this, rect);
+}
+
+CanvasItem *LibartCanvas::createEllipse(SVGEllipseElementImpl *ellipse)
+{
+ return new LibartEllipse(this, ellipse);
+}
+
+CanvasItem *LibartCanvas::createCircle(SVGCircleElementImpl *circle)
+{
+ return new LibartCircle(this, circle);
+}
+
+CanvasItem *LibartCanvas::createLine(SVGLineElementImpl *line)
+{
+ return new LibartLine(this, line);
+}
+
+CanvasItem *LibartCanvas::createPolyline(SVGPolylineElementImpl *poly)
+{
+ return new LibartPolyline(this, poly);
+}
+
+CanvasItem *LibartCanvas::createPolygon(SVGPolygonElementImpl *poly)
+{
+ return new LibartPolygon(this, poly);
+}
+
+CanvasItem *LibartCanvas::createPath(SVGPathElementImpl *path)
+{
+ return new LibartPath(this, path);
+}
+
+CanvasItem *LibartCanvas::createClipPath(SVGClipPathElementImpl *clippath)
+{
+ CanvasClipPath *result = new LibartClipPath(this, clippath);
+ QString index = clippath->id().string();
+ m_clipPaths.insert(index, result);
+ return result;
+}
+
+CanvasItem *LibartCanvas::createImage(SVGImageElementImpl *image)
+{
+ return new LibartImage(this, image);
+}
+
+CanvasItem *LibartCanvas::createCanvasMarker(SVGMarkerElementImpl *marker)
+{
+ return new LibartMarker(this, marker);
+}
+
+CanvasItem *LibartCanvas::createText(SVGTextElementImpl *text)
+{
+ return new LibartText(this, text);
+}
+
+CanvasPaintServer *LibartCanvas::createPaintServer(SVGElementImpl *pserver)
+{
+ LibartPaintServer *result;
+ if(dynamic_cast<SVGLinearGradientElementImpl *>(pserver))
+ result = new LibartLinearGradient(dynamic_cast<SVGLinearGradientElementImpl *>(pserver));
+ else if(dynamic_cast<SVGRadialGradientElementImpl *>(pserver))
+ result = new LibartRadialGradient(dynamic_cast<SVGRadialGradientElementImpl *>(pserver));
+ else if(dynamic_cast<SVGPatternElementImpl *>(pserver))
+ result = new LibartPattern(dynamic_cast<SVGPatternElementImpl *>(pserver));
+ return result;
+}
+
+void LibartCanvas::drawImage(QImage image, SVGStylableImpl *style, const SVGMatrixImpl *matrix, const KSVGPolygon& clippingPolygon)
+{
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(style);
+
+ if(shape)
+ {
+ if(image.depth() != 32)
+ image = image.convertDepth(32);
+
+ ArtSVP *imageBorder = svpFromPolygon(clippingPolygon);
+ ArtSVP *clipSvp = clipSingleSVP(imageBorder, shape);
+
+ ArtDRect bbox;
+ art_drect_svp(&bbox, clipSvp);
+
+ // clamp to viewport
+ int x0 = int(bbox.x0);
+ int y0 = int(bbox.y0);
+
+ // Use inclusive coords for x1/y1 for clipToBuffer
+ int x1 = int(ceil(bbox.x1)) - 1;
+ int y1 = int(ceil(bbox.y1)) - 1;
+
+ if(x0 < int(m_width) && y0 < int(m_height) && x1 >= 0 && y1 >= 0)
+ {
+ clipToBuffer(x0, y0, x1, y1);
+
+ QRect screenBBox(x0, y0, x1 - x0 + 1, y1 - y0 + 1);
+
+ QByteArray mask = SVGMaskElementImpl::maskRectangle(shape, screenBBox);
+
+ double affine[6];
+ KSVGHelper::matrixToAffine(matrix, affine);
+
+ ksvg_art_rgb_affine_clip(clipSvp, m_buffer + x0 * nrChannels() + y0 * rowStride(), x0, y0, x1 + 1, y1 + 1, rowStride(), nrChannels(), image.bits(), image.width(), image.height(), image.width() * 4, affine, int(style->getOpacity() * 255), (const art_u8 *)mask.data());
+ }
+
+ art_svp_free(imageBorder);
+ art_svp_free(clipSvp);
+ }
+}
+
+ArtSVP *LibartCanvas::clippingRect(const QRect &rect, const SVGMatrixImpl *ctm)
+{
+ ArtVpath *vec = allocVPath(6);
+ // Order of points in clipping rectangle must be counter-clockwise
+ bool flip = ((ctm->a() * ctm->d()) < (ctm->b() * ctm->c()));
+
+ vec[0].code = ART_MOVETO;
+ vec[0].x = rect.x();
+ vec[0].y = rect.y();
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = rect.x() + (flip ? rect.width() : 0);
+ vec[1].y = rect.y() + (flip ? 0 : rect.height());
+
+ vec[2].code = ART_LINETO;
+ vec[2].x = rect.x() + rect.width();
+ vec[2].y = rect.y() + rect.height();
+
+ vec[3].code = ART_LINETO;
+ vec[3].x = rect.x() + (flip ? 0 : rect.width());
+ vec[3].y = rect.y() + (flip ? rect.height() : 0);
+
+ vec[4].code = ART_LINETO;
+ vec[4].x = rect.x();
+ vec[4].y = rect.y();
+
+ vec[5].code = ART_END;
+
+ double affine[6];
+ KSVGHelper::matrixToAffine(ctm, affine);
+
+ ArtVpath *temp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+
+ ArtSVP *result = art_svp_from_vpath(temp);
+ art_free(temp);
+ return result;
+}
+
+ArtSVP *LibartCanvas::clipSingleSVP(ArtSVP *svp, SVGShapeImpl *shape)
+{
+ ArtSVP *clippedSvp = copy_svp(svp);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(shape);
+
+ if(style)
+ {
+ QString clipPathRef = style->getClipPath();
+
+ if(!clipPathRef.isEmpty())
+ {
+ CanvasClipPath *clipPath = m_clipPaths[clipPathRef];
+
+ if(clipPath)
+ {
+ LibartClipPath *lclip = dynamic_cast<LibartClipPath *>(clipPath);
+ reinterpret_cast<SVGClipPathElementImpl *>(clipPath->element())->setBBoxTarget(shape);
+
+ lclip->init();
+
+ if(lclip->clipSVP())
+ {
+ ArtSVP *s = art_svp_intersect(lclip->clipSVP(), clippedSvp);
+ art_svp_free(clippedSvp);
+ clippedSvp = s;
+ }
+ }
+ }
+ }
+
+ SVGSVGElementImpl *svg = dynamic_cast<SVGSVGElementImpl *>(shape);
+
+ // Clip outer svg, unless width and height not set
+ if(svg && (!svg->isRootElement() || !svg->getAttribute("width").isEmpty() || !svg->getAttribute("height").isEmpty()) && !svg->getOverflow())
+ {
+ ArtSVP *svgClip = clippingRect(svg->clip(), svg->screenCTM());
+ ArtSVP *s = art_svp_intersect(svgClip, clippedSvp);
+ art_svp_free(clippedSvp);
+ art_svp_free(svgClip);
+ clippedSvp = s;
+ }
+
+ if(dynamic_cast<SVGPatternElementImpl *>(shape) != 0)
+ {
+ // TODO: inherit clipping paths into tile space
+ }
+ else if(dynamic_cast<SVGMarkerElementImpl *>(shape) != 0)
+ {
+ SVGMarkerElementImpl *marker = static_cast<SVGMarkerElementImpl *>(shape);
+
+ if(!marker->clipShape().isEmpty())
+ {
+ ArtSVP *clipShape = svpFromPolygon(marker->clipShape());
+ ArtSVP *s = art_svp_intersect(clipShape, clippedSvp);
+ art_svp_free(clipShape);
+ art_svp_free(clippedSvp);
+ clippedSvp = s;
+ }
+
+ // TODO: inherit clipping paths into marker space
+ }
+ else
+ {
+ SVGElementImpl *element = dynamic_cast<SVGElementImpl *>(shape);
+ DOM::Node parentNode = element->parentNode();
+
+ if(!parentNode.isNull())
+ {
+ SVGElementImpl *parent = element->ownerDoc()->getElementFromHandle(parentNode.handle());
+
+ if(parent)
+ {
+ SVGShapeImpl *parentShape = dynamic_cast<SVGShapeImpl *>(parent);
+
+ if(parentShape)
+ {
+ // Clip against ancestor clipping paths
+ ArtSVP *parentClippedSvp = clipSingleSVP(clippedSvp, parentShape);
+ art_svp_free(clippedSvp);
+ clippedSvp = parentClippedSvp;
+ }
+ }
+ }
+ }
+
+ return clippedSvp;
+}
+
+void LibartCanvas::drawSVP(ArtSVP *svp, art_u32 color, QByteArray mask, QRect screenBBox)
+{
+ int x0 = screenBBox.left();
+ int y0 = screenBBox.top();
+ int x1 = screenBBox.right();
+ int y1 = screenBBox.bottom();
+
+ if(m_nrChannels == 3)
+ {
+ if(mask.data())
+ art_ksvg_rgb_svp_alpha_mask(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 3 + y0 * 3 * m_width, m_width * 3, 0, (art_u8 *)mask.data());
+ else
+ art_rgb_svp_alpha(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 3 + y0 * 3 * m_width, m_width * 3, 0);
+ }
+ else
+ art_ksvg_rgba_svp_alpha(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 4 + y0 * 4 * m_width, m_width * 4, 0, (art_u8 *)mask.data());
+}
+
+ArtSVP *LibartCanvas::copy_svp(const ArtSVP *svp)
+{
+ // No API to copy an SVP so do so without accessing the data structure directly.
+ ArtVpath *vec = allocVPath(1);
+
+ vec[0].code = ART_END;
+
+ ArtSVP *empty = art_svp_from_vpath(vec);
+ art_free(vec);
+
+ ArtSVP *result = art_svp_union(empty, svp);
+ art_svp_free(empty);
+
+ return result;
+}
+
+ArtSVP *LibartCanvas::svpFromPolygon(const KSVGPolygon& polygon)
+{
+ if(polygon.numPoints() > 2)
+ {
+ ArtVpath *points = new ArtVpath[polygon.numPoints() + 2];
+
+ points[0].code = ART_MOVETO;
+ points[0].x = polygon.point(0).x();
+ points[0].y = polygon.point(0).y();
+
+ unsigned int i;
+
+ for(i = 1; i < polygon.numPoints(); i++)
+ {
+ points[i].code = ART_LINETO;
+ points[i].x = polygon.point(i).x();
+ points[i].y = polygon.point(i).y();
+ }
+
+ points[i].code = ART_LINETO;
+ points[i].x = polygon.point(0).x();
+ points[i].y = polygon.point(0).y();
+
+ points[i + 1].code = ART_END;
+
+ ArtSVP *svp = art_svp_from_vpath(points);
+ delete [] points;
+
+ return svp;
+ }
+ else
+ return 0;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvas.h b/ksvg/plugin/backends/libart/LibartCanvas.h
new file mode 100644
index 00000000..e0da1682
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvas.h
@@ -0,0 +1,84 @@
+/*
+ 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 LIBARTCANVAS_H
+#define LIBARTCANVAS_H
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_config.h>
+
+#include <Glyph.h>
+#include <Converter.h>
+#include "GlyphTracerLibart.h"
+
+class QString;
+class QImage;
+
+struct _ArtSVP;
+
+namespace KSVG
+{
+
+class LibartPaintServer;
+class SVGElementImpl;
+class SVGStylableImpl;
+class SVGSVGElementImpl;
+class KSVGPolygon;
+class LibartCanvas : public KSVGCanvas
+{
+public:
+ LibartCanvas(unsigned int width, unsigned int height);
+
+ void drawSVP(_ArtSVP *svp, art_u32 color, QByteArray mask, QRect screenBBox);
+ void drawImage(QImage image, SVGStylableImpl *style, const SVGMatrixImpl *matrix, const KSVGPolygon& clippingPolygon);
+
+ virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const;
+
+ // creating canvas items
+ virtual CanvasItem *createRectangle(SVGRectElementImpl *rect);
+ virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse);
+ virtual CanvasItem *createCircle(SVGCircleElementImpl *circle);
+ virtual CanvasItem *createLine(SVGLineElementImpl *line);
+ virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly);
+ virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly);
+ virtual CanvasItem *createPath(SVGPathElementImpl *path);
+ virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath);
+ virtual CanvasItem *createImage(SVGImageElementImpl *image);
+ virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker);
+ virtual CanvasItem *createText(SVGTextElementImpl *text);
+ virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver);
+
+ _ArtSVP *clippingRect(const QRect &rect, const SVGMatrixImpl *ctm);
+ _ArtSVP *svpFromPolygon(const KSVGPolygon& polygon);
+
+ static ArtSVP *copy_svp(const ArtSVP *svp);
+
+ _ArtSVP *clipSingleSVP(_ArtSVP *svp, SVGShapeImpl *clipShape);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp b/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp
new file mode 100644
index 00000000..48d37f05
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp
@@ -0,0 +1,45 @@
+/*
+ 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 <kdebug.h>
+
+#include "LibartCanvas.h"
+#include "LibartCanvasFactory.h"
+
+using namespace KSVG;
+
+K_EXPORT_COMPONENT_FACTORY(libksvgrendererlibart, LibartCanvasFactory)
+
+LibartCanvasFactory::LibartCanvasFactory()
+{
+}
+
+LibartCanvasFactory::~LibartCanvasFactory()
+{
+}
+
+QObject *LibartCanvasFactory::createObject(QObject *, const char *, const char *, const QStringList &args)
+{
+ int width = (*args.at(1)).toInt();
+ int height = (*args.at(0)).toInt();
+ return new LibartCanvas(width, height);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvasFactory.h b/ksvg/plugin/backends/libart/LibartCanvasFactory.h
new file mode 100644
index 00000000..5b3ed0b3
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvasFactory.h
@@ -0,0 +1,45 @@
+/*
+ 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 LIBARTCANVASFACTORY_H
+#define LIBARTCANVASFACTORY_H
+
+#include <klibloader.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+namespace KSVG
+{
+
+class LibartCanvasFactory : public KLibFactory
+{
+public:
+ LibartCanvasFactory();
+ virtual ~LibartCanvasFactory();
+
+ virtual QObject *createObject(QObject *parent = 0, const char *pname = 0, const char *name = "QObject", const QStringList &args = QStringList());
+};
+
+}
+
+#endif
+
+/// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvasItems.cpp b/ksvg/plugin/backends/libart/LibartCanvasItems.cpp
new file mode 100644
index 00000000..5dd97be1
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvasItems.cpp
@@ -0,0 +1,2209 @@
+/*
+ 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 <cfloat>
+
+#include <qimage.h>
+#include <qwmatrix.h>
+
+#include "SVGPaint.h"
+#include "SVGRectImpl.h"
+#include "SVGAngleImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGUnitTypes.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGPointListImpl.h"
+#include "SVGMarkerElement.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPathSegListImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGAnimatedAngleImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGPolygonElementImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGPolylineElementImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGGradientElement.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGPatternElement.h"
+#include "SVGStopElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGUnitConverter.h"
+#include "SVGTextPathElementImpl.h"
+#include "SVGMaskElementImpl.h"
+
+#include "KSVGHelper.h"
+#include "LibartCanvasItems.h"
+#include "KSVGTextChunk.h"
+
+#include "art_misc.h"
+#include "art_render_misc.h"
+#include "BezierPathLibart.h"
+#include "Point.h"
+
+#include <dom/dom_node.h>
+
+
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_affine.h>
+#include <libart_lgpl/art_svp_ops.h>
+#include <libart_lgpl/art_svp_point.h>
+#include <libart_lgpl/art_vpath_svp.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_svp_vpath.h>
+#include <libart_lgpl/art_svp_vpath_stroke.h>
+#include <libart_lgpl/art_rect_svp.h>
+#include <libart_lgpl/art_vpath_dash.h>
+#include <libart_lgpl/art_render.h>
+#include <libart_lgpl/art_rect_svp.h>
+#include <libart_lgpl/art_render_gradient.h>
+#include <libart_lgpl/art_render_svp.h>
+#include <libart_lgpl/art_render_mask.h>
+
+using namespace KSVG;
+
+LibartShape::LibartShape(LibartCanvas *c, SVGStylableImpl *style) : m_canvas(c), m_style(style)
+{
+ m_fillSVP = 0;
+ m_strokeSVP = 0;
+ m_fillPainter = 0;
+ m_strokePainter = 0;
+}
+
+LibartShape::~LibartShape()
+{
+ freeSVPs();
+ delete m_fillPainter;
+ delete m_strokePainter;
+}
+
+QRect LibartShape::bbox() const
+{
+ QRect rect;
+ if(m_strokeSVP || m_fillSVP)
+ {
+ ArtIRect *irect = new ArtIRect();
+ ArtVpath *vpath = art_vpath_from_svp(m_strokeSVP ? m_strokeSVP : m_fillSVP);
+ art_vpath_bbox_irect(vpath, irect);
+ art_free(vpath);
+
+ rect.setX(irect->x0);
+ rect.setY(irect->y0);
+ rect.setWidth(irect->x1 - irect->x0);
+ rect.setHeight(irect->y1 - irect->y0);
+
+ delete irect;
+ }
+
+ return rect;
+}
+
+bool LibartShape::isVisible(SVGShapeImpl *shape)
+{
+ return m_referenced || (m_style->getVisible() && m_style->getDisplay() && shape->directRender());
+}
+
+bool LibartShape::fillContains(const QPoint &p)
+{
+ if(m_fillSVP)
+ return art_svp_point_wind(m_fillSVP, p.x(), p.y()) != 0;
+ else
+ return false;
+}
+
+bool LibartShape::strokeContains(const QPoint &p)
+{
+ if(m_strokeSVP)
+ return art_svp_point_wind(m_strokeSVP, p.x(), p.y()) != 0;
+ else
+ return false;
+}
+
+void LibartShape::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(reason == UPDATE_STYLE)
+ {
+ if(!m_fillPainter || !m_strokePainter)
+ LibartShape::init();
+ if(m_fillPainter)
+ m_fillPainter->update(m_style);
+ if(m_strokePainter)
+ m_strokePainter->update(m_style);
+ m_canvas->invalidate(this, false);
+ }
+ else if(reason == UPDATE_TRANSFORM)
+ {
+ reset();
+ m_canvas->invalidate(this, true);
+ }
+ else if(reason == UPDATE_ZOOM)
+ reset();
+ else if(reason == UPDATE_PAN)
+ {
+ if(m_fillSVP)
+ ksvg_art_svp_move(m_fillSVP, param1, param2);
+ if(m_strokeSVP)
+ ksvg_art_svp_move(m_strokeSVP, param1, param2);
+ }
+ else if(reason == UPDATE_LINEWIDTH)
+ {
+ if(m_strokeSVP)
+ {
+ art_svp_free(m_strokeSVP);
+ m_strokeSVP = 0;
+ }
+ init();
+ m_canvas->invalidate(this, true);
+ }
+}
+
+void LibartShape::draw(SVGShapeImpl *shape)
+{
+ if(!m_referenced && (!m_style->getVisible() || !m_style->getDisplay() || !shape->directRender()))
+ return;
+
+ bool fillOk = m_fillSVP && m_style->isFilled();
+ bool strokeOk = m_strokeSVP && m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted.
+
+ if(fillOk || strokeOk)
+ {
+ if(m_fillPainter && m_fillSVP)
+ m_fillPainter->draw(m_canvas, m_fillSVP, m_style, shape);
+
+ if(m_strokePainter && m_strokeSVP)
+ m_strokePainter->draw(m_canvas, m_strokeSVP, m_style, shape);
+ }
+}
+
+void LibartShape::init(const SVGMatrixImpl *)
+{
+}
+
+void LibartPainter::update(SVGStylableImpl *style)
+{
+ if(paintType(style) != SVG_PAINTTYPE_URI)
+ {
+ QColor qcolor;
+ if(paintType(style) == SVG_PAINTTYPE_CURRENTCOLOR)
+ qcolor = style->getColor()->rgbColor().color();
+ else
+ qcolor = color(style);
+
+ short _opacity = static_cast<short>(opacity(style) * 255 + 0.5);
+
+ // Spec: clamping
+ _opacity = _opacity < 0 ? 0 : _opacity;
+ _opacity = _opacity > 255 ? 255 : _opacity;
+
+ m_color = KSVGHelper::toArtColor(qcolor, _opacity);
+ }
+}
+
+void LibartPainter::draw(LibartCanvas *canvas, _ArtSVP *svp, SVGStylableImpl *style, SVGShapeImpl *shape)
+{
+ ArtSVP *clippedSvp = canvas->clipSingleSVP(svp, shape);
+
+ // Clipping
+ ArtDRect bbox;
+ art_drect_svp(&bbox, clippedSvp);
+
+ // clamp to viewport
+ int x0 = int(bbox.x0);
+ int y0 = int(bbox.y0);
+
+ // Use inclusive coords for x1/y1 for clipToBuffer
+ int x1 = int(ceil(bbox.x1)) - 1;
+ int y1 = int(ceil(bbox.y1)) - 1;
+
+ if(x0 < int(canvas->width()) && y0 < int(canvas->height()) && x1 > -1 && y1 > -1)
+ {
+ canvas->clipToBuffer(x0, y0, x1, y1);
+
+ QRect screenBBox(x0, y0, x1 - x0 + 1, y1 - y0 + 1);
+
+ QByteArray mask = SVGMaskElementImpl::maskRectangle(shape, screenBBox);
+
+ if(paintType(style) == SVG_PAINTTYPE_URI)
+ {
+ LibartPaintServer *pserver = static_cast<LibartPaintServer *>(SVGPaintServerImpl::paintServer(shape->ownerDoc(), paintUri(style)));
+
+ if(pserver)
+ {
+ pserver->setBBoxTarget(shape);
+ if(!pserver->finalized())
+ pserver->finalizePaintServer();
+ pserver->render(canvas, clippedSvp, opacity(style), mask, screenBBox);
+ }
+ }
+ else
+ canvas->drawSVP(clippedSvp, m_color, mask, screenBBox);
+ }
+
+ art_svp_free(clippedSvp);
+}
+
+LibartStrokePainter::LibartStrokePainter(SVGStylableImpl *style)
+{
+ update(style);
+}
+
+LibartFillPainter::LibartFillPainter(SVGStylableImpl *style)
+{
+ update(style);
+}
+
+void LibartShape::init()
+{
+ if(m_style->isFilled())
+ {
+ if(m_fillPainter == 0)
+ m_fillPainter = new LibartFillPainter(m_style);
+ }
+ else
+ {
+ delete m_fillPainter;
+ m_fillPainter = 0;
+ }
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0)
+ {
+ if(m_strokePainter == 0)
+ m_strokePainter = new LibartStrokePainter(m_style);
+ }
+ else
+ {
+ delete m_strokePainter;
+ m_strokePainter = 0;
+ }
+}
+
+void LibartShape::initClipItem()
+{
+ init();
+}
+
+ArtSVP *LibartShape::clipSVP()
+{
+ return m_fillSVP;
+}
+
+void LibartShape::freeSVPs()
+{
+ if(m_fillSVP)
+ art_svp_free(m_fillSVP);
+ if(m_strokeSVP)
+ art_svp_free(m_strokeSVP);
+
+ m_fillSVP = 0;
+ m_strokeSVP = 0;
+}
+
+void LibartShape::calcClipSVP(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **clipSVP)
+{
+ double affine[6];
+ KSVGHelper::matrixToAffine(matrix, affine);
+
+ if(!style)
+ {
+ art_free(vec);
+ return;
+ }
+
+ ArtVpath *vtemp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+ vec = vtemp;
+
+ ArtSVP *temp;
+ ArtSvpWriter *swr;
+ temp = art_svp_from_vpath(vec);
+
+ if(style->getClipRule() == RULE_EVENODD)
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN);
+ else
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_NONZERO);
+
+ art_svp_intersector(temp, swr);
+ *clipSVP = art_svp_writer_rewind_reap(swr);
+
+ art_svp_free(temp);
+ art_free(vec);
+}
+
+void LibartShape::calcSVPs(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, ArtSVP **strokeSVP, ArtSVP **fillSVP)
+{
+ if(style)
+ {
+ double affine[6];
+ KSVGHelper::matrixToAffine(matrix, affine);
+
+ ArtVpath *temp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+ vec = temp;
+ calcSVPInternal(vec, style, affine, strokeSVP, fillSVP);
+ }
+ else
+ art_free(vec);
+}
+
+void LibartShape::calcSVPs(ArtBpath *bpath, SVGStylableImpl *style, const SVGMatrixImpl *matrix, ArtSVP **strokeSVP, ArtSVP **fillSVP)
+{
+ if(style)
+ {
+ double affine[6];
+ KSVGHelper::matrixToAffine(matrix, affine);
+
+ ArtBpath *temp = art_bpath_affine_transform(bpath, affine);
+ ArtVpath *vec = ksvg_art_bez_path_to_vec(temp, 0.25);
+ art_free(temp);
+ calcSVPInternal(vec, style, affine, strokeSVP, fillSVP);
+ }
+}
+
+void LibartShape::calcSVPInternal(ArtVpath *vec, SVGStylableImpl *style, double *affine, ArtSVP **strokeSVP, ArtSVP **fillSVP)
+{
+ ArtSVP *svp;
+
+ // Filling
+ {
+ ArtSvpWriter *swr;
+ ArtSVP *temp;
+ temp = art_svp_from_vpath(vec);
+
+ if(style->getFillRule() == RULE_EVENODD)
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN);
+ else
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_NONZERO);
+
+ art_svp_intersector(temp, swr);
+ svp = art_svp_writer_rewind_reap(swr);
+
+ *fillSVP = svp;
+ art_svp_free(temp);
+ }
+
+ // Stroking
+ if(style->isStroked() || style->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI)
+ {
+ double ratio = art_affine_expansion(affine);
+
+ unsigned int dashLength;
+ if(style->getDashArray() && (dashLength = style->getDashArray()->baseVal()->numberOfItems()) > 0)
+ {
+ // HACK: libart will hang in art_vpath_dash() if passed an array with only zeroes.
+ bool allZeroes = true;
+
+ // there are dashes to be rendered
+ ArtVpathDash dash;
+ dash.offset = int(style->getDashOffset()->baseVal()->value()) * ratio;
+ dash.n_dash = dashLength;
+ double *dashes = new double[dashLength];
+ for(unsigned int i = 0; i < dashLength; i++)
+ {
+ dashes[i] = style->getDashArray()->baseVal()->getItem(i)->value() * ratio;
+ if(dashes[i] != 0.0)
+ allZeroes = false;
+ }
+ dash.dash = dashes;
+
+ if(!allZeroes)
+ {
+ // get the dashed VPath and use that for the stroke render operation
+ ArtVpath *vec2 = art_vpath_dash(vec, &dash);
+ art_free(vec);
+ vec = vec2;
+ }
+
+ // reset the dashes
+ delete [] dashes;
+ }
+
+ double penWidth = style->getStrokeWidth()->baseVal()->value() * ratio;
+ svp = art_svp_vpath_stroke(vec, (ArtPathStrokeJoinType)style->getJoinStyle(), (ArtPathStrokeCapType)style->getCapStyle(), penWidth, style->getStrokeMiterlimit(), 0.25);
+
+ *strokeSVP = svp;
+ }
+ art_free(vec);
+}
+
+// #####
+
+LibartRectangle::LibartRectangle(LibartCanvas *c, SVGRectElementImpl *rect)
+: LibartShape(c, rect), m_rect(rect)
+{
+ init();
+}
+
+void LibartRectangle::draw()
+{
+ if(isVisible())
+ LibartShape::draw(m_rect);
+}
+
+bool LibartRectangle::isVisible()
+{
+ // Spec: a value of zero disables rendering
+ return LibartShape::isVisible(m_rect) && m_rect->width()->baseVal()->value() > 0 && m_rect->height()->baseVal()->value() > 0;
+}
+
+void LibartRectangle::init()
+{
+ init(m_rect->screenCTM());
+}
+
+void LibartRectangle::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ double x = m_rect->x()->baseVal()->value();
+ double y = m_rect->y()->baseVal()->value();
+ double width = m_rect->width()->baseVal()->value();
+ double height = m_rect->height()->baseVal()->value();
+ double rx = m_rect->rx()->baseVal()->value();
+ double ry = m_rect->ry()->baseVal()->value();
+
+ // Spec: If there is no rx or ry specified, draw a normal rect
+ if(rx == -1 && ry == -1)
+ {
+ ArtVpath *vec = allocVPath(6);
+
+ vec[0].code = ART_MOVETO;
+ vec[0].x = x;
+ vec[0].y = y;
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = x;
+ vec[1].y = y + height;
+
+ vec[2].code = ART_LINETO;
+ vec[2].x = x + width;
+ vec[2].y = y + height;
+
+ vec[3].code = ART_LINETO;
+ vec[3].x = x + width;
+ vec[3].y = y;
+
+ vec[4].code = ART_LINETO;
+ vec[4].x = x;
+ vec[4].y = y;
+
+ vec[5].code = ART_END;
+
+ if(m_context == NORMAL)
+ calcSVPs(vec, m_rect, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(vec, m_rect, screenCTM, &m_fillSVP);
+ }
+ else
+ {
+ ArtVpath *res;
+ ArtBpath *vec = allocBPath(10);
+
+ int i = 0;
+
+ // Spec: If rx isn't specified, but ry, set rx to ry
+ if(rx == -1)
+ rx = ry;
+
+ // Spec: If ry isn't specified, but rx, set ry to rx
+ if(ry == -1)
+ ry = rx;
+
+ // Spec: If rx is greater than half of the width of the rectangle
+ // then set rx to half of the width
+ if(rx > width / 2)
+ rx = width / 2;
+
+ // Spec: If ry is greater than half of the height of the rectangle
+ // then set ry to half of the height
+ if(ry > height / 2)
+ ry = height / 2;
+
+ vec[i].code = ART_MOVETO_OPEN;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y;
+
+ i++;
+
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + rx * (1 - 0.552);
+ vec[i].y1 = y;
+ vec[i].x2 = x;
+ vec[i].y2 = y + ry * (1 - 0.552);
+ vec[i].x3 = x;
+ vec[i].y3 = y + ry;
+
+ i++;
+
+ if(ry < height / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x;
+ vec[i].y3 = y + height - ry;
+
+ i++;
+ }
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x;
+ vec[i].y1 = y + height - ry * (1 - 0.552);
+ vec[i].x2 = x + rx * (1 - 0.552);
+ vec[i].y2 = y + height;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y + height;
+
+ i++;
+
+ if(rx < width / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + width - rx;
+ vec[i].y3 = y + height;
+
+ i++;
+ }
+
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + width - rx * (1 - 0.552);
+ vec[i].y1 = y + height;
+ vec[i].x2 = x + width;
+ vec[i].y2 = y + height - ry * (1 - 0.552);
+ vec[i].x3 = x + width;
+
+ vec[i].y3 = y + height - ry;
+
+ i++;
+
+ if(ry < height / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + width;
+ vec[i].y3 = y + ry;
+
+ i++;
+ }
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + width;
+ vec[i].y1 = y + ry * (1 - 0.552);
+ vec[i].x2 = x + width - rx * (1 - 0.552);
+ vec[i].y2 = y;
+ vec[i].x3 = x + width - rx;
+ vec[i].y3 = y;
+
+ i++;
+
+ if(rx < width / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y;
+
+ i++;
+ }
+
+ vec[i].code = ART_END;
+
+ res = ksvg_art_bez_path_to_vec(vec, 0.25);
+ if(m_context == NORMAL)
+ calcSVPs(res, m_rect, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(res, m_rect, screenCTM, &m_fillSVP);
+ art_free(vec);
+ }
+}
+
+// #####
+
+LibartEllipse::LibartEllipse(LibartCanvas *c, SVGEllipseElementImpl *ellipse)
+: LibartShape(c, ellipse), m_ellipse(ellipse)
+{
+ init();
+}
+
+void LibartEllipse::draw()
+{
+ if(isVisible())
+ LibartShape::draw(m_ellipse);
+}
+
+bool LibartEllipse::isVisible()
+{
+ // Spec: dont render when rx and/or ry is zero
+ return LibartShape::isVisible(m_ellipse) && m_ellipse->rx()->baseVal()->value() > 0 && m_ellipse->ry()->baseVal()->value() > 0;
+}
+
+void LibartEllipse::init()
+{
+ init(m_ellipse->screenCTM());
+}
+
+void LibartEllipse::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ ArtBpath *temp = allocBPath(6);
+
+ double x1, y1, x2, y2, x3, y3;
+ double len = 0.55228474983079356;
+ double rx = m_ellipse->rx()->baseVal()->value();
+ double ry = m_ellipse->ry()->baseVal()->value();
+ double cx = m_ellipse->cx()->baseVal()->value();
+ double cy = m_ellipse->cy()->baseVal()->value();
+ double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0};
+ double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0};
+ int i = 0;
+
+ temp[i].code = ART_MOVETO;
+ temp[i].x3 = cx + rx;
+ temp[i].y3 = cy;
+
+ i++;
+
+ while(i < 5)
+ {
+ x1 = cos4[i-1] + len * cos4[i];
+ y1 = sin4[i-1] + len * sin4[i];
+ x2 = cos4[i] + len * cos4[i-1];
+ y2 = sin4[i] + len * sin4[i-1];
+ x3 = cos4[i];
+ y3 = sin4[i];
+
+ temp[i].code = ART_CURVETO;
+ temp[i].x1 = cx + x1 * rx;
+ temp[i].y1 = cy + y1 * ry;
+ temp[i].x2 = cx + x2 * rx;
+ temp[i].y2 = cy + y2 * ry;
+ temp[i].x3 = cx + x3 * rx;
+ temp[i].y3 = cy + y3 * ry;
+
+ i++;
+ }
+
+ temp[i].code = ART_END;
+
+ if(m_context == NORMAL)
+ calcSVPs(temp, m_ellipse, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(ksvg_art_bez_path_to_vec(temp, 0.25), m_ellipse, screenCTM, &m_fillSVP);
+ art_free(temp);
+}
+
+// #####
+
+LibartCircle::LibartCircle(LibartCanvas *c, SVGCircleElementImpl *circle)
+: LibartShape(c, circle), m_circle(circle)
+{
+ init();
+}
+
+void LibartCircle::draw()
+{
+ // Spec: a value of zero disables rendering
+ if(isVisible())
+ LibartShape::draw(m_circle);
+}
+
+bool LibartCircle::isVisible()
+{
+ // Spec: dont render when rx and/or ry is zero
+ return LibartShape::isVisible(m_circle) && m_circle->r()->baseVal()->value() > 0;
+}
+
+void LibartCircle::init()
+{
+ init(m_circle->screenCTM());
+}
+
+void LibartCircle::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ ArtBpath *temp = allocBPath(6);
+
+ double x1, y1, x2, y2, x3, y3;
+ double len = 0.55228474983079356;
+ double r = m_circle->r()->baseVal()->value();
+ double cx = m_circle->cx()->baseVal()->value();
+ double cy = m_circle->cy()->baseVal()->value();
+ double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0};
+ double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0};
+ int i = 0;
+
+ temp[i].code = ART_MOVETO;
+ temp[i].x3 = cx + r;
+ temp[i].y3 = cy;
+
+ i++;
+
+ while(i < 5)
+ {
+ x1 = cos4[i-1] + len * cos4[i];
+ y1 = sin4[i-1] + len * sin4[i];
+ x2 = cos4[i] + len * cos4[i-1];
+ y2 = sin4[i] + len * sin4[i-1];
+ x3 = cos4[i];
+ y3 = sin4[i];
+
+ temp[i].code = ART_CURVETO;
+ temp[i].x1 = cx + x1 * r;
+ temp[i].y1 = cy + y1 * r;
+ temp[i].x2 = cx + x2 * r;
+ temp[i].y2 = cy + y2 * r;
+ temp[i].x3 = cx + x3 * r;
+ temp[i].y3 = cy + y3 * r;
+
+ i++;
+ }
+
+ temp[i].code = ART_END;
+
+ if(m_context == NORMAL)
+ calcSVPs(temp, m_circle, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(ksvg_art_bez_path_to_vec(temp, 0.25), m_circle, screenCTM, &m_fillSVP);
+ art_free(temp);
+}
+
+// #####
+
+LibartLine::LibartLine(LibartCanvas *c, SVGLineElementImpl *line)
+: LibartShape(c, line), MarkerHelper(), m_line(line)
+{
+ init();
+}
+
+LibartLine::~LibartLine()
+{
+}
+
+void LibartLine::draw()
+{
+ LibartShape::draw(m_line);
+
+ if(m_line->hasMarkers())
+ {
+ double x1 = m_line->x1()->baseVal()->value();
+ double y1 = m_line->y1()->baseVal()->value();
+ double x2 = m_line->x2()->baseVal()->value();
+ double y2 = m_line->y2()->baseVal()->value();
+ double slope = SVGAngleImpl::todeg(atan2(y2 - y1, x2 - x1));
+
+ if(m_line->hasStartMarker())
+ doStartMarker(m_line, m_line, x1, y1, slope);
+ if(m_line->hasEndMarker())
+ doEndMarker(m_line, m_line, x2, y2, slope);
+ }
+}
+
+bool LibartLine::isVisible()
+{
+ return LibartShape::isVisible(m_line);
+}
+
+void LibartLine::init()
+{
+ init(m_line->screenCTM());
+}
+
+void LibartLine::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ ArtVpath *vec;
+
+ vec = allocVPath(3);
+
+ vec[0].code = ART_MOVETO_OPEN;
+ vec[0].x = m_line->x1()->baseVal()->value();
+ vec[0].y = m_line->y1()->baseVal()->value();
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = m_line->x2()->baseVal()->value();
+ vec[1].y = m_line->y2()->baseVal()->value();
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(vec[1].x == vec[0].x && vec[1].y == vec[0].y && m_line->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ vec[1].x += .5;
+
+ vec[2].code = ART_END;
+
+ if(m_context == NORMAL)
+ {
+ calcSVPs(vec, m_line, screenCTM, &m_strokeSVP, &m_fillSVP);
+ art_svp_free(m_fillSVP);
+ m_fillSVP = 0;
+ }
+ else
+ calcClipSVP(vec, m_line, screenCTM, &m_fillSVP);
+}
+
+// #####
+LibartPoly::LibartPoly(LibartCanvas *c, SVGPolyElementImpl *poly)
+: LibartShape(c, poly), MarkerHelper(), m_poly(poly)
+{
+}
+
+LibartPoly::~LibartPoly()
+{
+}
+
+void LibartPoly::init()
+{
+ init(m_poly->screenCTM());
+}
+
+void LibartPoly::draw()
+{
+ LibartShape::draw(m_poly);
+
+ if(m_poly->hasMarkers())
+ m_poly->drawMarkers();
+}
+
+bool LibartPoly::isVisible()
+{
+ return LibartShape::isVisible(m_poly);
+}
+
+// #####
+LibartPolyline::LibartPolyline(LibartCanvas *c, SVGPolylineElementImpl *poly)
+: LibartPoly(c, poly)
+{
+ LibartPoly::init();
+}
+
+LibartPolyline::~LibartPolyline()
+{
+}
+
+void LibartPolyline::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ unsigned int numberOfPoints = m_poly->points()->numberOfItems();
+
+ if(numberOfPoints < 1)
+ return;
+
+ ArtVpath *polyline = allocVPath(2 + numberOfPoints);
+
+ polyline[0].code = ART_MOVETO_OPEN;
+ polyline[0].x = m_poly->points()->getItem(0)->x();
+ polyline[0].y = m_poly->points()->getItem(0)->y();
+
+ unsigned int index;
+ for(index = 1; index < numberOfPoints; index++)
+ {
+ polyline[index].code = ART_LINETO;
+ polyline[index].x = m_poly->points()->getItem(index)->x();
+ polyline[index].y = m_poly->points()->getItem(index)->y();
+ }
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(numberOfPoints == 2 && polyline[1].x == polyline[0].x && polyline[1].y == polyline[0].y && m_poly->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ polyline[1].x += .5;
+
+
+ if(m_poly->isFilled()) // if the polyline must be filled, inform libart that it should not be closed.
+ {
+ polyline[index].code = (ArtPathcode) ART_END2;
+ polyline[index].x = m_poly->points()->getItem(0)->x();
+ polyline[index++].y = m_poly->points()->getItem(0)->y();
+ }
+
+ polyline[index].code = ART_END;
+ if(m_context == NORMAL)
+ calcSVPs(polyline, m_poly, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+LibartPolygon::LibartPolygon(LibartCanvas *c, SVGPolygonElementImpl *poly)
+: LibartPoly(c, poly)
+{
+ LibartPoly::init();
+}
+
+LibartPolygon::~LibartPolygon()
+{
+}
+
+void LibartPolygon::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ unsigned int numberOfPoints = m_poly->points()->numberOfItems();
+
+ if(numberOfPoints < 1)
+ return;
+
+ ArtVpath *polygon = allocVPath(2 + numberOfPoints);
+
+ polygon[0].code = ART_MOVETO;
+ polygon[0].x = m_poly->points()->getItem(0)->x();
+ polygon[0].y = m_poly->points()->getItem(0)->y();
+
+ unsigned int index;
+ for(index = 1; index < numberOfPoints; index++)
+ {
+ polygon[index].code = ART_LINETO;
+ polygon[index].x = m_poly->points()->getItem(index)->x();
+ polygon[index].y = m_poly->points()->getItem(index)->y();
+ }
+
+ polygon[index].code = ART_LINETO;
+ polygon[index].x = m_poly->points()->getItem(0)->x();
+ polygon[index].y = m_poly->points()->getItem(0)->y();
+
+ index++;
+ polygon[index].code = ART_END;
+
+ if(m_context == NORMAL)
+ calcSVPs(polygon, m_poly, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(polygon, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+LibartPath::LibartPath(LibartCanvas *c, SVGPathElementImpl *path)
+: LibartShape(c, path), MarkerHelper(), T2P::BezierPathLibart(), ::SVGPathParser(), m_path(path)
+{
+ reset();
+}
+
+LibartPath::~LibartPath()
+{
+}
+
+void LibartPath::reset()
+{
+ m_array.resize(0);
+ LibartShape::reset();
+}
+
+void LibartPath::draw()
+{
+ LibartShape::draw(m_path);
+
+ if(m_path->hasMarkers())
+ {
+ SVGPathElementImpl::MarkerData markers = m_path->markerData();
+ int numMarkers = markers.numMarkers();
+
+ if(m_path->hasStartMarker())
+ doStartMarker(m_path, m_path, markers.marker(0).x, markers.marker(0).y, markers.marker(0).angle);
+
+ for(int i = 1; i < numMarkers - 1; i++)
+ {
+ if(m_path->hasMidMarker())
+ doMidMarker(m_path, m_path, markers.marker(i).x, markers.marker(i).y, markers.marker(i).angle);
+ }
+
+ if(m_path->hasEndMarker())
+ doEndMarker(m_path, m_path, markers.marker(numMarkers - 1).x, markers.marker(numMarkers - 1).y, markers.marker(numMarkers - 1).angle);
+ }
+}
+
+bool LibartPath::isVisible()
+{
+ return LibartShape::isVisible(m_path);
+}
+
+void LibartPath::init()
+{
+ init(m_path->screenCTM());
+}
+
+void LibartPath::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ if(m_array.count() > 0)
+ {
+ if(m_context == NORMAL)
+ calcSVPs(m_array.data(), m_path, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP);
+ }
+ else if(!m_path->getAttribute("d").string().isEmpty())
+ {
+ parseSVG(m_path->getAttribute("d").string(), true);
+
+ int index = m_array.count();
+ double curx = m_array[index - 1].x3;
+ double cury = m_array[index - 1].y3;
+
+ // Find last subpath
+ int find = -1;
+ for(int i = index - 1; i >= 0; i--)
+ {
+ if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ // Fix a problem where the .svg file used floats as values... (sofico.svg)
+ if(curx != m_array[find].x3 && cury != m_array[find].y3)
+ {
+ if((int) curx == (int) m_array[find].x3 && (int) cury == (int) m_array[find].y3)
+ {
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_LINETO;
+ m_array[index].x3 = m_array[find].x3;
+ m_array[index].y3 = m_array[find].y3;
+
+ curx = m_array[find].x3;
+ cury = m_array[find].y3;
+
+ index++;
+ }
+ }
+
+ // handle filled paths that are not closed explicitly
+ if(m_path->getFillColor()->paintType() != SVG_PAINTTYPE_NONE)
+ {
+ if((int) curx != (int) m_array[find].x3 || (int) cury != (int) m_array[find].y3)
+ {
+ ensureSpace(m_array, index)
+
+ m_array[index].code = (ArtPathcode)ART_END2;
+ m_array[index].x3 = m_array[find].x3;
+ m_array[index].y3 = m_array[find].y3;
+
+ curx = m_array[find].x3;
+ cury = m_array[find].y3;
+
+ index++;
+ }
+ }
+
+ // close
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_END;
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(index == 2 && m_array[1].code == ART_LINETO && m_array[1].x3 == m_array[0].x3 && m_array[1].y3 == m_array[0].y3 && m_path->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ m_array[1].x3 += .5;
+
+ // There are pure-moveto paths which reference paint servers *bah*
+ // Do NOT render them
+ bool render = false;
+ for(int i = index; i >= 0; i--)
+ {
+ if(m_array[i].code != ART_MOVETO_OPEN && m_array[i].code != ART_MOVETO && !(m_array[i].code >= ART_END))
+ {
+ render = true;
+ break;
+ }
+ }
+
+ if(render && m_context == NORMAL)
+ calcSVPs(m_array.data(), m_path, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP);
+ }
+}
+
+void LibartPath::svgMoveTo(double x1, double y1, bool closed, bool)
+{
+ int index = m_array.count();
+
+ if(index > 0 && !closed)
+ {
+ // Find last subpath
+ int find = -1;
+ for(int i = index - 1; i >= 0; i--)
+ {
+ if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ ensureSpace(m_array, index)
+
+ m_array[index].code = (ArtPathcode) ART_END2;
+ m_array[index].x3 = m_array[find].x3;
+ m_array[index].y3 = m_array[find].y3;
+
+ index++;
+ }
+
+ ensureSpace(m_array, index)
+
+ m_array[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN;
+ m_array[index].x3 = x1;
+ m_array[index].y3 = y1;
+}
+
+void LibartPath::svgLineTo(double x1, double y1, bool)
+{
+ int index = m_array.count();
+
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_LINETO;
+ m_array[index].x3 = x1;
+ m_array[index].y3 = y1;
+}
+
+void LibartPath::svgCurveToCubic(double x1, double y1, double x2, double y2, double x3, double y3, bool)
+{
+ int index = m_array.count();
+
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_CURVETO;
+ m_array[index].x1 = x1;
+ m_array[index].y1 = y1;
+ m_array[index].x2 = x2;
+ m_array[index].y2 = y2;
+ m_array[index].x3 = x3;
+ m_array[index].y3 = y3;
+}
+
+void LibartPath::svgClosePath()
+{
+ int index = m_array.count();
+ double curx = m_array[index - 1].x3;
+ double cury = m_array[index - 1].y3;
+
+ int find = -1;
+ for(int i = index - 1; i >= 0; i--)
+ {
+ if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ if(find != -1)
+ {
+ if(m_array[find].x3 != curx || m_array[find].y3 != cury)
+ {
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_LINETO;
+ m_array[index].x3 = m_array[find].x3;
+ m_array[index].y3 = m_array[find].y3;
+ }
+ }
+}
+
+// #####
+
+LibartClipPath::LibartClipPath(LibartCanvas *c, SVGClipPathElementImpl *clipPath)
+: CanvasClipPath(clipPath), m_canvas(c)
+{
+ m_clipSVP = 0;
+ m_clipItems.setAutoDelete(true);
+}
+
+LibartClipPath::~LibartClipPath()
+{
+ if(m_clipSVP)
+ art_svp_free(m_clipSVP);
+}
+
+void LibartClipPath::update(CanvasItemUpdate, int, int)
+{
+ if(m_clipSVP)
+ art_svp_free(m_clipSVP);
+ m_clipSVP = 0;
+}
+
+void LibartClipPath::init()
+{
+ SVGMatrixImpl *clipMatrix = 0;
+
+ // Start with referencing element's coordinate system
+ SVGLocatableImpl *locatableReferrer = dynamic_cast<SVGLocatableImpl *>(m_clipPath->getBBoxTarget());
+ if(locatableReferrer)
+ clipMatrix = locatableReferrer->getScreenCTM();
+ else
+ clipMatrix = SVGSVGElementImpl::createSVGMatrix();
+
+ if(m_clipPath->clipPathUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && m_clipPath->getBBoxTarget())
+ {
+ SVGRectImpl *rect = m_clipPath->getBBoxTarget()->getBBox();
+
+ clipMatrix->translate(rect->qrect().x(), rect->qrect().y());
+ clipMatrix->scaleNonUniform(rect->qrect().width(), rect->qrect().height());
+
+ rect->deref();
+ }
+
+ // Add transformations on the clipPath element itself
+ if(m_clipPath->localMatrix())
+ clipMatrix->multiply(m_clipPath->localMatrix());
+
+ if(m_clipSVP)
+ {
+ art_svp_free(m_clipSVP);
+ m_clipSVP = 0;
+ }
+
+ DOM::Node node = m_clipPath->firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = m_clipPath->ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+
+ bool ok = tests ? tests->ok() : true;
+
+ if(element && shape && ok && !shape->isContainer())
+ {
+ LibartClipItem *clipElement = dynamic_cast<LibartClipItem *>(shape->item());
+
+ if(dynamic_cast<LibartText *>(shape->item()))
+ {
+ // The cast to a clipElement above is failing when it is valid. But only
+ // in the plugin - svgdisplay works fine. What's going on? (Adrian)
+ clipElement = dynamic_cast<LibartText *>(shape->item());
+ }
+
+ if(clipElement)
+ {
+ clipElement->setRenderContext(CLIPPING);
+
+ // Push coordinate system down to children.
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(shape);
+ if(locatable)
+ locatable->updateCachedScreenCTM(clipMatrix);
+
+ clipElement->initClipItem();
+
+ ArtSVP *one = clipElement->clipSVP();
+ if(!one)
+ break;
+
+ if(m_clipSVP == 0)
+ m_clipSVP = LibartCanvas::copy_svp(one);
+ else
+ {
+ ArtSVP *svp_union = art_svp_union(m_clipSVP, one);
+ art_svp_free(m_clipSVP);
+ m_clipSVP = svp_union;
+ }
+ }
+ }
+ }
+
+ clipMatrix->deref();
+}
+
+void LibartClipPath::draw()
+{
+}
+
+ArtSVP *LibartClipPath::clipSVP()
+{
+ return m_clipSVP;
+}
+
+// #####
+
+LibartImage::LibartImage(LibartCanvas *c, SVGImageElementImpl *image)
+: m_canvas(c), m_image(image)
+{
+}
+
+LibartImage::~LibartImage()
+{
+}
+
+void LibartImage::draw()
+{
+ if(isVisible())
+ {
+ SVGMatrixImpl *ctm = m_image->scaledImageMatrix();
+ QImage image = m_image->scaledImage();
+ KSVGPolygon clippingPolygon = m_image->clippingShape();
+
+ m_canvas->drawImage(image, m_image, ctm, clippingPolygon);
+
+ ctm->deref();
+ }
+}
+
+bool LibartImage::isVisible()
+{
+ return (m_referenced || (m_image->getVisible() && m_image->getDisplay() && m_image->directRender())) && m_image->image();
+}
+
+void LibartImage::init()
+{
+}
+
+QRect LibartImage::bbox() const
+{
+ QRect bbox(static_cast<int>(m_image->x()->baseVal()->value()),
+ static_cast<int>(m_image->y()->baseVal()->value()),
+ static_cast<int>(m_image->width()->baseVal()->value()),
+ static_cast<int>(m_image->height()->baseVal()->value()));
+
+
+ return SVGHelperImpl::fromUserspace(m_image, bbox);
+}
+
+// #####
+
+LibartMarker::LibartMarker(LibartCanvas *c, SVGMarkerElementImpl *marker)
+: CanvasMarker(marker), m_canvas(c)
+{
+}
+
+LibartMarker::~LibartMarker()
+{
+}
+
+void LibartMarker::init()
+{
+}
+
+void LibartMarker::draw()
+{
+}
+
+// #####
+
+LibartText::LibartText(LibartCanvas *c, SVGTextElementImpl *text)
+: CanvasText(text), m_canvas(c)
+{
+ m_drawFillItems.setAutoDelete(true);
+ m_drawStrokeItems.setAutoDelete(true);
+ m_fillPainters.setAutoDelete(true);
+ m_strokePainters.setAutoDelete(true);
+
+ init();
+}
+
+LibartText::~LibartText()
+{
+ clearSVPs();
+}
+
+LibartText::SVPElement::~SVPElement()
+{
+ if(svp)
+ art_svp_free(svp);
+}
+
+QRect LibartText::bbox() const
+{
+ QRect result, rect;
+
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ ArtIRect *irect = new ArtIRect();
+ ArtVpath *vpath = art_vpath_from_svp((stroke && stroke->svp) ? stroke->svp : fill->svp);
+ art_vpath_bbox_irect(vpath, irect);
+ art_free(vpath);
+
+ rect.setX(irect->x0);
+ rect.setY(irect->y0);
+ rect.setWidth(irect->x1 - irect->x0);
+ rect.setHeight(irect->y1 - irect->y0);
+
+ delete irect;
+
+ result = result.unite(rect);
+
+ fill = ++it1;
+ stroke = ++it2;
+ }
+ return result;
+}
+
+bool LibartText::fillContains(const QPoint &p)
+{
+ QPtrListIterator<SVPElement> it(m_drawFillItems);
+
+ SVPElement *fill = it.current();
+ while(fill && fill->svp)
+ {
+ if(fill->svp && art_svp_point_wind(fill->svp, p.x(), p.y()) != 0)
+ return true;
+
+ fill = ++it;
+ }
+
+ return false;
+}
+
+bool LibartText::strokeContains(const QPoint &p)
+{
+ QPtrListIterator<SVPElement> it(m_drawStrokeItems);
+
+ SVPElement *stroke = it.current();
+ while(stroke && stroke->svp)
+ {
+ if(stroke->svp && art_svp_point_wind(stroke->svp, p.x(), p.y()) != 0)
+ return true;
+
+ stroke = ++it;
+ }
+
+ return false;
+}
+
+void LibartText::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(reason == UPDATE_STYLE)
+ {
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ SVGTextContentElementImpl *text = fill ? fill->element : stroke->element;
+
+ bool fillOk = fill && fill->svp && text->isFilled();
+ bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted.
+ if(fillOk || strokeOk)
+ {
+ if(m_fillPainters.find(text))
+ m_fillPainters[text]->update(text);
+
+ if(m_strokePainters.find(text))
+ m_strokePainters[text]->update(text);
+ }
+ fill = ++it1;
+ stroke = ++it2;
+ }
+ m_canvas->invalidate(this, false);
+ }
+ else if(reason == UPDATE_TRANSFORM)
+ {
+ clearSVPs();
+ init();
+ m_canvas->invalidate(this, true);
+ }
+ else if(reason == UPDATE_ZOOM)
+ {
+ clearSVPs();
+ init();
+ }
+ else if(reason == UPDATE_PAN)
+ {
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+
+ double affine[6];
+ KSVGHelper::matrixToAffine(m_text->screenCTM(), affine);
+
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ SVGTextContentElementImpl *text = fill ? fill->element : stroke->element;
+
+ bool fillOk = fill && fill->svp && text->isFilled();
+ bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted.
+
+ if(fillOk)
+ ksvg_art_svp_move(fill->svp, param1, param2);
+ if(strokeOk)
+ ksvg_art_svp_move(stroke->svp, param1, param2);
+ fill = ++it1;
+ stroke = ++it2;
+ }
+ }
+ /*
+ else if(reason == UPDATE_LINEWIDTH)
+ {
+ }*/
+}
+
+void LibartText::draw()
+{
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ SVGTextContentElementImpl *text = fill ? fill->element : stroke->element;
+ if(!text || !text->getVisible() || !text->getDisplay() || !text->directRender())
+ return;
+
+ bool fillOk = fill && fill->svp && text->isFilled();
+ bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted.
+
+ if(fillOk || strokeOk)
+ {
+ if(fillOk && m_fillPainters.find(text))
+ m_fillPainters[text]->draw(m_canvas, fill->svp, text, text);
+
+ if(strokeOk && m_strokePainters.find(text))
+ m_strokePainters[text]->draw(m_canvas, stroke->svp, text, text);
+ }
+ fill = ++it1;
+ stroke = ++it2;
+ }
+}
+
+bool LibartText::isVisible()
+{
+ bool foundVisible = false;
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ SVGTextContentElementImpl *text = fill ? fill->element : stroke->element;
+ if(text && text->getVisible() && text->getDisplay() && text->directRender())
+ {
+ foundVisible = true;
+ break;
+ }
+
+ fill = ++it1;
+ stroke = ++it2;
+ }
+
+ return foundVisible;
+}
+
+void LibartText::init()
+{
+ init(m_text->screenCTM());
+}
+
+void LibartText::renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const
+{
+ unsigned int glyphCount = glyph->glyphCount(); // Don't call it n times in the for loop
+ for(unsigned int i = 0; i < glyphCount; i++)
+ {
+ T2P::GlyphAffinePair *glyphAffine = glyph->set()[i];
+ ArtBpath *bezier = static_cast<const T2P::BezierPathLibart *>(glyphAffine->transformatedPath())->m_array.data();
+ ArtBpath *result = bezier;
+
+ // text-anchor support
+ if(anchor != 0)
+ {
+ double correct[6];
+
+ if(!params->tb())
+ art_affine_translate(correct, -anchor, 0);
+ else
+ art_affine_translate(correct, 0, -anchor);
+
+ ArtBpath *temp = art_bpath_affine_transform(result, correct);
+ //art_free(result);
+ result = temp;
+ }
+
+ ArtSVP *fillSVP = 0, *strokeSVP = 0;
+
+ if(m_context == NORMAL)
+ LibartShape::calcSVPs(result, m_text, screenCTM, &strokeSVP, &fillSVP);
+ else
+ LibartShape::calcClipSVP(ksvg_art_bez_path_to_vec(result, 0.25), m_text, screenCTM, &fillSVP);
+
+ SVPElement *fillElement = new SVPElement();
+ fillElement->svp = fillSVP;
+ fillElement->element = element;
+
+ SVPElement *strokeElement = new SVPElement();
+ strokeElement->svp = strokeSVP;
+ strokeElement->element = element;
+
+ m_drawFillItems.append(fillElement);
+ m_drawStrokeItems.append(strokeElement);
+
+ if(!m_fillPainters.find(element) && element->isFilled())
+ m_fillPainters.insert(element, new LibartFillPainter(element));
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(!m_strokePainters.find(element) && element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0)
+ m_strokePainters.insert(element, new LibartStrokePainter(element));
+ }
+}
+
+void LibartText::init(const SVGMatrixImpl *screenCTM)
+{
+ int curx = 0, cury = 0, endx = 0, endy = 0;
+ KSVGTextChunk *textChunk = CanvasText::createTextChunk(m_canvas, screenCTM, curx, cury, endx, endy);
+
+ if(textChunk->count() > 0)
+ CanvasText::createGlyphs(textChunk, m_canvas, screenCTM, curx, cury, endx, endy);
+
+ delete textChunk;
+}
+
+void LibartText::clearSVPs()
+{
+ m_drawFillItems.clear();
+ m_drawStrokeItems.clear();
+ m_fillPainters.clear();
+ m_strokePainters.clear();
+}
+
+void LibartText::addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double width, double height) const
+{
+ if(m_text->isFilled() || m_text->isStroked())
+ {
+ // compute rect svp
+ ArtVpath *vec = allocVPath(6);
+
+ vec[0].code = ART_MOVETO;
+ vec[0].x = x;
+ vec[0].y = y;
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = x;
+ vec[1].y = y + height;
+
+ vec[2].code = ART_LINETO;
+ vec[2].x = x + width;
+ vec[2].y = y + height;
+
+ vec[3].code = ART_LINETO;
+ vec[3].x = x + width;
+ vec[3].y = y;
+
+ vec[4].code = ART_LINETO;
+ vec[4].x = x;
+ vec[4].y = y;
+
+ vec[5].code = ART_END;
+ double affine[6];
+ KSVGHelper::matrixToAffine(m_text->screenCTM(), affine);
+
+ ArtVpath *temp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+ vec = temp;
+
+ if(m_text->isFilled())
+ {
+ ArtSvpWriter *swr;
+ ArtSVP *temp = art_svp_from_vpath(vec);
+
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN);
+
+ art_svp_intersector(temp, swr);
+ ArtSVP *fillSVP = art_svp_writer_rewind_reap(swr);
+
+ SVPElement *fillElement = new SVPElement();
+ fillElement->svp = fillSVP;
+ fillElement->element = element;
+
+ m_drawFillItems.append(fillElement);
+
+ if(!m_fillPainters.find(element) && element->isFilled())
+ m_fillPainters.insert(element, new LibartFillPainter(element));
+
+ art_svp_free(temp);
+ }
+ // Stroking
+ if(m_text->isStroked() || m_text->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI)
+ {
+ double ratio = art_affine_expansion(affine);
+ ArtSVP *strokeSVP = art_svp_vpath_stroke(vec, (ArtPathStrokeJoinType)m_text->getJoinStyle(), (ArtPathStrokeCapType)m_text->getCapStyle(), m_text->getStrokeWidth()->baseVal()->value() * ratio, m_text->getStrokeMiterlimit(), 0.25);
+
+ SVPElement *strokeElement = new SVPElement();
+ strokeElement->svp = strokeSVP;
+ strokeElement->element = element;
+
+ m_drawStrokeItems.append(strokeElement);
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(!m_strokePainters.find(element) && element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0)
+ m_strokePainters.insert(element, new LibartStrokePainter(element));
+ }
+ art_free(vec);
+ }
+}
+
+void LibartText::initClipItem()
+{
+ init();
+}
+
+ArtSVP *LibartText::clipSVP()
+{
+ ArtSVP *svp = 0;
+ QPtrListIterator<SVPElement> it(m_drawFillItems);
+
+ SVPElement *fill = it.current();
+ while(fill && fill->svp)
+ {
+ if(svp == 0)
+ svp = LibartCanvas::copy_svp(fill->svp);
+ else
+ {
+ ArtSVP *svp_union = art_svp_union(svp, fill->svp);
+ art_svp_free(svp);
+ svp = svp_union;
+ }
+
+ fill = ++it;
+ }
+
+ return svp;
+}
+
+ArtRender *LibartPaintServer::createRenderer(QRect bbox, KSVGCanvas *c)
+{
+ int x0 = bbox.x();
+ int y0 = bbox.y();
+ int x1 = bbox.right();
+ int y1 = bbox.bottom();
+
+ c->clipToBuffer(x0, y0, x1, y1);
+
+ // Note: We always pass 3 for the number of channels since the ART_ALPHA parameter
+ // adds the alpha channel when present.
+ ArtRender *render = 0;
+ render = art_render_new(QMIN(x0, x1),
+ QMIN(y0, y1),
+ QMAX(x0, x1) + 1,
+ QMAX(y0, y1) + 1,
+ c->renderingBuffer() + x0 * c->nrChannels() + y0 * c->rowStride(),
+ c->rowStride(), 3, 8,
+ c->nrChannels() == 3 ? ART_ALPHA_NONE : ART_ALPHA_PREMUL, 0);
+
+ return render;
+}
+
+void LibartGradient::parseGradientStops(SVGGradientElementImpl *gradient)
+{
+ const double epsilon = DBL_EPSILON;
+
+ for(DOM::Node node = gradient->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGStopElementImpl *elem = dynamic_cast<SVGStopElementImpl *>(m_gradient->ownerDoc()->getElementFromHandle(node.handle()));
+ if(elem)
+ {
+ m_stops.resize(m_stops.size() + 1);
+
+ ArtGradientStop *stop = &(m_stops[m_stops.size() - 1]);
+
+ stop->offset = elem->offset()->baseVal();
+
+ // Spec: clamp range to 0 to 1
+ if(stop->offset < epsilon)
+ stop->offset = 0;
+ else if(stop->offset > 1 - epsilon)
+ stop->offset = 1;
+
+ // Spec: if offset is less than previous offset, set it to the previous offset
+ if(m_stops.size() > 1 && stop->offset < (stop - 1)->offset + epsilon)
+ stop->offset = (stop - 1)->offset;
+
+ // Get color
+ QColor qStopColor;
+
+ if(elem->getStopColor()->colorType() == SVG_COLORTYPE_CURRENTCOLOR)
+ qStopColor = elem->getColor()->rgbColor().color();
+ else
+ qStopColor = elem->getStopColor()->rgbColor().color();
+
+ // Convert in a libart suitable form
+ QString tempName = qStopColor.name();
+ const char *str = tempName.latin1();
+
+ int stopColor = 0;
+
+ for(int i = 1; str[i]; i++)
+ {
+ int hexval;
+ if(str[i] >= '0' && str[i] <= '9')
+ hexval = str[i] - '0';
+ else if (str[i] >= 'A' && str[i] <= 'F')
+ hexval = str[i] - 'A' + 10;
+ else if (str[i] >= 'a' && str[i] <= 'f')
+ hexval = str[i] - 'a' + 10;
+ else
+ break;
+
+ stopColor = (stopColor << 4) + hexval;
+ }
+
+ // Apply stop-opacity
+ float opacity = elem->stopOpacity();
+
+ // Get rgba color including stop-opacity
+ Q_UINT32 rgba = (stopColor << 8) | int(opacity * 255.0 + 0.5);
+ Q_UINT32 r, g, b, a;
+
+ a = rgba & 0xff;
+ r = (rgba >> 24) & 0xff;
+ g = (rgba >> 16) & 0xff;
+ b = (rgba >> 8) & 0xff;
+
+ stop->color[0] = ART_PIX_MAX_FROM_8(r);
+ stop->color[1] = ART_PIX_MAX_FROM_8(g);
+ stop->color[2] = ART_PIX_MAX_FROM_8(b);
+ stop->color[3] = ART_PIX_MAX_FROM_8(a);
+ }
+ }
+}
+
+void LibartGradient::finalizePaintServer()
+{
+ parseGradientStops(m_gradient->stopsSource());
+
+ QString _href = SVGURIReferenceImpl::getTarget(m_gradient->href()->baseVal().string());
+ if(!_href.isEmpty())
+ reference(_href);
+
+ setFinalized();
+}
+
+void LibartGradient::reference(const QString &)
+{
+}
+
+void LibartLinearGradient::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox)
+{
+ if(!m_stops.isEmpty())
+ {
+ m_linear->converter()->finalize(getBBoxTarget(), m_linear->ownerSVGElement(), m_linear->gradientUnits()->baseVal());
+
+ ArtKSVGGradientLinear *linear = art_new(ArtKSVGGradientLinear, 1);
+
+ if(m_linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT)
+ linear->spread = ART_GRADIENT_REPEAT;
+ else if(m_linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT)
+ linear->spread = ART_GRADIENT_REFLECT;
+ else
+ linear->spread = ART_GRADIENT_PAD;
+
+ linear->interpolation = m_linear->getColorInterpolation() == CI_SRGB ? ART_KSVG_SRGB_INTERPOLATION : ART_KSVG_LINEARRGB_INTERPOLATION;
+
+ ArtRender *render = createRenderer(screenBBox, c);
+
+ double _x1 = m_linear->x1()->baseVal()->value();
+ double _y1 = m_linear->y1()->baseVal()->value();
+ double _x2 = m_linear->x2()->baseVal()->value();
+ double _y2 = m_linear->y2()->baseVal()->value();
+
+ // Respect current transformation matrix (so gradients zoom with...)
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(getBBoxTarget());
+ SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->getScreenCTM();
+ else
+ matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ const double epsilon = DBL_EPSILON;
+
+ if(m_linear->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ {
+ // Here we're undoing the unit-converter's work because putting the
+ // bounding box transform into the matrix here lets the gradient transform
+ // sit at the right point in the chain to work with bounding box coordinates. It
+ // also removes the need for code to generate the 'not perpendicular to gradient vector' effect.
+ SVGRectImpl *userBbox = getBBoxTarget()->getBBox();
+
+ double width = userBbox->width();
+ double height = userBbox->height();
+
+ // Catch case of width or height of zero, which can be the case for lines.
+ if(width < epsilon)
+ width = 1;
+ if(height < epsilon)
+ height = 1;
+
+ _x1 /= width;
+ _y1 /= height;
+ _x2 /= width;
+ _y2 /= height;
+
+ matrix->translate(userBbox->x(), userBbox->y());
+ matrix->scaleNonUniform(width, height);
+
+ userBbox->deref();
+ }
+
+ // Adjust to gradient transform
+ SVGMatrixImpl *gradTrans = m_linear->gradientTransform()->baseVal()->concatenate();
+ if(gradTrans)
+ {
+ matrix->multiply(gradTrans);
+ gradTrans->deref();
+ }
+
+ double dx = _x2 - _x1;
+ double dy = _y2 - _y1;
+
+ if(fabs(dx) < epsilon && fabs(dy) < epsilon)
+ {
+ // Lines can generate (0, 0) with bbox coords.
+ dx = 1;
+ dy = 0;
+ }
+
+ double angle = atan2(dy, dx);
+ double length = sqrt(dx * dx + dy * dy);
+
+ const double pi = 3.14159265358979323846;
+
+ matrix->translate(_x1, _y1);
+ matrix->scale(length);
+ matrix->rotate(angle * 180.0 / pi);
+
+ double affine[6];
+
+ KSVGHelper::matrixToAffine(matrix, affine);
+ art_affine_invert(linear->affine, affine);
+
+ matrix->deref();
+
+ QMemArray<ArtGradientStop> stops = m_stops;
+ stops.detach();
+
+ for(unsigned int i = 0; i < stops.size(); i++)
+ stops[i].color[3] = ArtPixMaxDepth(stops[i].color[3] * opacity + 0.5);
+
+ if(m_linear->x1()->baseVal()->valueInSpecifiedUnits() == m_linear->x2()->baseVal()->valueInSpecifiedUnits()
+ && m_linear->y1()->baseVal()->valueInSpecifiedUnits() == m_linear->y2()->baseVal()->valueInSpecifiedUnits())
+ {
+ // Spec: If x1 == x2 and y1 == y2, paint the area in a single colour, using the colour
+ // of the last stop.
+ //
+ // Using valueInSpecifiedUnits() so that we are comparing the values before possible
+ // conversion to bounding box units by the converter.
+ if(stops.size() > 1)
+ {
+ stops[0] = stops[stops.size() - 1];
+ stops.resize(1);
+ }
+ }
+
+ linear->stops = &(stops[0]);
+ linear->n_stops = stops.size();
+
+ art_render_svp(render, svp);
+ art_ksvg_render_gradient_linear(render, linear, ART_FILTER_HYPER);
+
+ if(mask.data())
+ art_render_mask(render, screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1,
+ (const art_u8 *)mask.data(), screenBBox.width());
+
+ art_render_invoke(render);
+
+ art_free(linear);
+ }
+}
+
+void LibartRadialGradient::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox)
+{
+ if(!m_stops.isEmpty())
+ {
+ m_radial->converter()->finalize(getBBoxTarget(), m_radial->ownerSVGElement(), m_radial->gradientUnits()->baseVal());
+
+ ArtKSVGGradientRadial *radial = art_new(ArtKSVGGradientRadial, 1);
+
+ if(m_radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT)
+ radial->spread = ART_GRADIENT_REPEAT;
+ else if(m_radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT)
+ radial->spread = ART_GRADIENT_REFLECT;
+ else
+ radial->spread = ART_GRADIENT_PAD;
+
+ radial->interpolation = m_radial->getColorInterpolation() == CI_SRGB ? ART_KSVG_SRGB_INTERPOLATION : ART_KSVG_LINEARRGB_INTERPOLATION;
+
+ ArtRender *render = createRenderer(screenBBox, c);
+
+ // Respect current transformation matrix (so gradients zoom with...)
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(getBBoxTarget());
+ SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->getScreenCTM();
+ else
+ matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ double _cx = m_radial->cx()->baseVal()->value();
+ double _cy = m_radial->cy()->baseVal()->value();
+ double _r = m_radial->r()->baseVal()->value();
+
+ double _fx;
+ double _fy;
+
+ // Spec: If attribute fx is not specified, fx will coincide with cx.
+ if(m_radial->getAttribute("fx").isEmpty())
+ _fx = _cx;
+ else
+ _fx = m_radial->fx()->baseVal()->value();
+
+ // Spec: If attribute fy is not specified, fy will coincide with cy.
+ if(m_radial->getAttribute("fy").isEmpty())
+ _fy = _cy;
+ else
+ _fy = m_radial->fy()->baseVal()->value();
+
+ const double epsilon = DBL_EPSILON;
+
+ if(m_radial->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ {
+ // Here we're undoing the unit-converter's work because putting the
+ // bounding box transform into the matrix here lets the gradient transform
+ // sit at the right point in the chain to work with bounding box coordinates.
+ // It also produces the elliptical shape due to the non-uniform scaling.
+ SVGRectImpl *userBBox = getBBoxTarget()->getBBox();
+
+ double width = userBBox->width();
+ double height = userBBox->height();
+
+ // Catch case of width or height of zero, which can be the case for lines.
+ if(width < epsilon)
+ width = 1;
+ if(height < epsilon)
+ height = 1;
+
+ _cx /= width;
+ _cy /= height;
+ _fx /= width;
+ _fy /= height;
+ _r /= (sqrt(width * width + height * height) / 1.4142135623731);
+
+ matrix->translate(userBBox->x(), userBBox->y());
+ matrix->scaleNonUniform(width, height);
+
+ userBBox->deref();
+ }
+
+ // Adjust to gradient transforms
+ SVGMatrixImpl *transform = m_radial->gradientTransform()->baseVal()->concatenate();
+
+ if(transform)
+ {
+ matrix->multiply(transform);
+ transform->deref();
+ }
+
+ double fx = (_fx - _cx) / _r;
+ double fy = (_fy - _cy) / _r;
+
+ if(fx * fx + fy * fy > 0.99)
+ {
+ // Spec: If (fx, fy) lies outside the circle defined by (cx, cy) and r, set (fx, fy)
+ // to the point of intersection of the line through (fx, fy) and the circle.
+ //
+ // Note: We need to keep (fx, fy) inside the unit circle in order for
+ // libart to render the gradient correctly.
+ double angle = atan2(fy, fx);
+ fx = cos(angle) * 0.99;
+ fy = sin(angle) * 0.99;
+ }
+
+ radial->fx = fx;
+ radial->fy = fy;
+
+ matrix->translate(_cx, _cy);
+ matrix->scale(_r);
+
+ double affine[6];
+
+ KSVGHelper::matrixToAffine(matrix, affine);
+ art_affine_invert(radial->affine, affine);
+
+ matrix->deref();
+
+ QMemArray<ArtGradientStop> stops = m_stops;
+ stops.detach();
+
+ for(unsigned int i = 0; i < stops.size(); i++)
+ stops[i].color[3] = ArtPixMaxDepth(stops[i].color[3] * opacity + 0.5);
+
+ radial->stops = &(stops[0]);
+ radial->n_stops = stops.size();
+
+ art_render_svp(render, svp);
+ art_ksvg_render_gradient_radial(render, radial, ART_FILTER_HYPER);
+
+ if(mask.data())
+ art_render_mask(render, screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1,
+ (const art_u8 *)mask.data(), screenBBox.width());
+
+ art_render_invoke(render);
+
+ art_free(radial);
+ }
+}
+
+LibartPattern::LibartPattern(SVGPatternElementImpl *pattern)
+ : m_pattern(pattern)
+{
+}
+
+void LibartPattern::finalizePaintServer()
+{
+ m_pattern->finalizePaintServer();
+ setFinalized();
+}
+
+void LibartPattern::reference(const QString &href)
+{
+ m_pattern->reference(href);
+}
+
+void LibartPattern::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox)
+{
+ SVGPatternElementImpl::Tile tile = m_pattern->createTile(getBBoxTarget());
+
+ if(!tile.image().isNull())
+ {
+ QWMatrix m = tile.screenToTile();
+ double affine[6];
+
+ affine[0] = m.m11();
+ affine[1] = m.m12();
+ affine[2] = m.m21();
+ affine[3] = m.m22();
+ affine[4] = m.dx();
+ affine[5] = m.dy();
+
+ int alpha = int(opacity * 255 + 0.5);
+
+ ksvg_art_rgb_texture(svp, c->renderingBuffer() + screenBBox.x() * c->nrChannels() + screenBBox.y() * c->rowStride(), screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1, c->rowStride(), c->nrChannels(), tile.image().bits(), tile.image().width(), tile.image().height(), tile.image().width() * 4, affine, ART_FILTER_NEAREST, 0L, alpha, (art_u8 *)mask.data());
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvasItems.h b/ksvg/plugin/backends/libart/LibartCanvasItems.h
new file mode 100644
index 00000000..c62224e5
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvasItems.h
@@ -0,0 +1,414 @@
+/*
+ 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 LIBARTCANVASITEMS_H
+#define LIBARTCANVASITEMS_H
+
+#include <qptrlist.h>
+
+#include "CanvasItems.h"
+#include "LibartCanvas.h"
+#include "BezierPathLibart.h"
+
+#include "SVGPathElementImpl.h"
+#include "SVGPolyElementImpl.h"
+#include "SVGLineElementImpl.h"
+#include "SVGRectElementImpl.h"
+#include "SVGTextElementImpl.h"
+#include "SVGCircleElementImpl.h"
+#include "SVGEllipseElementImpl.h"
+
+// Helpers
+#define allocVPath(n) art_new(ArtVpath, n)
+#define allocBPath(n) art_new(ArtBpath, n)
+
+#define LIBART_CLASS(Class, Type, Member) \
+class Libart##Class : public LibartShape \
+{ \
+public: \
+ Libart##Class(LibartCanvas *c, Type *Member); \
+ virtual ~Libart##Class() { } \
+ virtual void draw(); \
+ virtual bool isVisible(); \
+ virtual void init(); \
+ virtual void init(const SVGMatrixImpl *screenCTM); \
+ virtual SVGElementImpl *element() const { return m_##Member; } \
+protected: \
+ Type *m_##Member; \
+};
+
+struct _ArtSVP;
+struct _ArtBpath;
+struct _ArtRender;
+struct _ArtGradientStop;
+
+namespace KSVG
+{
+ class SVGImageElementImpl;
+ class SVGGradientElementImpl;
+ class SVGRadialGradientElementImpl;
+ class SVGLinearGradientElementImpl;
+ class SVGPatternElementImpl;
+
+ class LibartPaintServer : public CanvasPaintServer
+ {
+ public:
+ LibartPaintServer() : CanvasPaintServer() {}
+ virtual ~LibartPaintServer() {}
+
+ virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox) = 0;
+
+ _ArtRender *createRenderer(QRect rect, KSVGCanvas *c);
+ };
+
+ class LibartGradient : public LibartPaintServer
+ {
+ public:
+ LibartGradient(SVGGradientElementImpl *gradient) : m_gradient(gradient) {}
+ virtual ~LibartGradient() {}
+
+ void parseGradientStops(SVGGradientElementImpl *gradient);
+
+ virtual void finalizePaintServer();
+ virtual void reference(const QString &href);
+
+ protected:
+ SVGGradientElementImpl *m_gradient;
+ QMemArray<_ArtGradientStop> m_stops;
+ };
+
+ class LibartLinearGradient : public LibartGradient
+ {
+ public:
+ LibartLinearGradient(SVGLinearGradientElementImpl *linear) : LibartGradient(linear), m_linear(linear) {}
+
+ virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox);
+
+ protected:
+ SVGLinearGradientElementImpl *m_linear;
+ };
+
+ class LibartRadialGradient : public LibartGradient
+ {
+ public:
+ LibartRadialGradient(SVGRadialGradientElementImpl *radial) : LibartGradient(radial), m_radial(radial) {}
+
+ virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox);
+
+ protected:
+ SVGRadialGradientElementImpl *m_radial;
+ };
+
+ class LibartPattern : public LibartPaintServer
+ {
+ public:
+ LibartPattern(SVGPatternElementImpl *pattern);
+ virtual ~LibartPattern() {}
+
+ virtual void finalizePaintServer();
+ virtual void reference(const QString &href);
+
+ virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox);
+
+ protected:
+ SVGPatternElementImpl *m_pattern;
+ };
+
+ class LibartPainter
+ {
+ public:
+ LibartPainter() { m_color = 0; }
+ virtual ~LibartPainter() {}
+
+ void update(SVGStylableImpl *style);
+ void draw(LibartCanvas *canvas, _ArtSVP *svp, SVGStylableImpl *style, SVGShapeImpl *shape);
+
+ virtual float opacity(SVGStylableImpl *style) const = 0;
+ virtual unsigned short paintType(SVGStylableImpl *style) const = 0;
+ virtual QString paintUri(SVGStylableImpl *style) const = 0;
+ virtual QRgb color(SVGStylableImpl *style) const = 0;
+
+ protected:
+ art_u32 m_color;
+ };
+
+ class LibartFillPainter : public LibartPainter
+ {
+ public:
+ LibartFillPainter(SVGStylableImpl *style);
+
+ float opacity(SVGStylableImpl *style) const { return style->getFillOpacity() * style->getOpacity(); }
+ unsigned short paintType(SVGStylableImpl *style) const { return style->getFillColor()->paintType(); }
+ QString paintUri(SVGStylableImpl *style) const { return style->getFillColor()->uri().string(); }
+ QRgb color(SVGStylableImpl *style) const { return style->getFillColor()->rgbColor().color(); }
+ };
+
+ class LibartStrokePainter : public LibartPainter
+ {
+ public:
+ LibartStrokePainter(SVGStylableImpl *style);
+
+ float opacity(SVGStylableImpl *style) const { return style->getStrokeOpacity() * style->getOpacity(); }
+ unsigned short paintType(SVGStylableImpl *style) const { return style->getStrokeColor()->paintType(); }
+ QString paintUri(SVGStylableImpl *style) const { return style->getStrokeColor()->uri().string(); }
+ QRgb color(SVGStylableImpl *style) const { return style->getStrokeColor()->rgbColor().color(); }
+ };
+
+ class LibartClipItem
+ {
+ public:
+ LibartClipItem() { m_context = NORMAL; }
+ virtual ~LibartClipItem() {}
+
+ virtual void initClipItem() = 0;
+ void setRenderContext(RenderContext context) { m_context = context; }
+ virtual ArtSVP *clipSVP() = 0;
+
+ protected:
+ RenderContext m_context;
+ };
+
+ class LibartShape : public CanvasItem, public LibartClipItem
+ {
+ public:
+ LibartShape(LibartCanvas *c, SVGStylableImpl *style);
+ virtual ~LibartShape();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &p);
+ virtual bool strokeContains(const QPoint &p);
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0);
+ void draw(SVGShapeImpl *shape);
+ bool isVisible(SVGShapeImpl *shape);
+
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *);
+ virtual void reset() { freeSVPs(); init(); }
+
+ void initClipItem();
+ ArtSVP *clipSVP();
+
+ static void calcClipSVP(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **clipSVP);
+ static void calcSVPs(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **strokeSVP, _ArtSVP **fillSVP);
+ static void calcSVPs(_ArtBpath *bpath, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **strokeSVP, _ArtSVP **fillSVP);
+
+ protected:
+ void freeSVPs();
+ static void calcSVPInternal(ArtVpath *vec, SVGStylableImpl *style, double *affine, ArtSVP **strokeSVP, ArtSVP **fillSVP);
+
+ _ArtSVP *m_fillSVP;
+ _ArtSVP *m_strokeSVP;
+ LibartFillPainter *m_fillPainter;
+ LibartStrokePainter *m_strokePainter;
+ LibartCanvas *m_canvas;
+ SVGStylableImpl *m_style;
+ };
+
+ LIBART_CLASS(Rectangle, SVGRectElementImpl, rect)
+ LIBART_CLASS(Ellipse, SVGEllipseElementImpl, ellipse)
+ LIBART_CLASS(Circle, SVGCircleElementImpl, circle)
+
+ class LibartLine : public LibartShape, public MarkerHelper
+ {
+ public:
+ LibartLine(LibartCanvas *c, SVGLineElementImpl *line);
+ virtual ~LibartLine();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual SVGElementImpl *element() const { return m_line; }
+
+ protected:
+ SVGLineElementImpl *m_line;
+ };
+
+ class LibartPoly : public LibartShape, public MarkerHelper
+ {
+ public:
+ LibartPoly(LibartCanvas *c, SVGPolyElementImpl *poly);
+ virtual ~LibartPoly();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM) = 0;
+
+ virtual SVGElementImpl *element() const { return m_poly; }
+
+ protected:
+ SVGPolyElementImpl *m_poly;
+
+ };
+ class LibartPolyline : public LibartPoly
+ {
+ public:
+ LibartPolyline(LibartCanvas *c, SVGPolylineElementImpl *poly);
+ virtual ~LibartPolyline();
+
+ virtual void init(const SVGMatrixImpl *screenCTM);
+ };
+
+ class LibartPolygon : public LibartPoly
+ {
+ public:
+ LibartPolygon(LibartCanvas *c, SVGPolygonElementImpl *poly);
+ virtual ~LibartPolygon();
+
+ virtual void init(const SVGMatrixImpl *screenCTM);
+ };
+
+ class LibartPath : public LibartShape, public MarkerHelper, public T2P::BezierPathLibart, public ::SVGPathParser
+ {
+ public:
+ LibartPath(LibartCanvas *c, SVGPathElementImpl *path);
+ virtual ~LibartPath();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void reset();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual SVGElementImpl *element() const { return m_path; }
+
+ protected:
+ friend class LibartCanvas;
+ SVGPathElementImpl *m_path;
+
+ virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true);
+ virtual void svgLineTo(double x1, double y1, bool abs = true);
+ virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true);
+ virtual void svgClosePath();
+ };
+
+ class LibartClipPath : public CanvasClipPath
+ {
+ public:
+ LibartClipPath(LibartCanvas *c, SVGClipPathElementImpl *clipPath);
+ virtual ~LibartClipPath();
+
+ virtual QRect bbox() const { return QRect(); }
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int param1 = 0, int param2 = 0);
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible() { return false; }
+
+ _ArtSVP *clipSVP();
+
+ protected:
+ LibartCanvas *m_canvas;
+ _ArtSVP *m_clipSVP;
+
+ QPtrList<CanvasItem> m_clipItems;
+ };
+
+ class LibartImage : public CanvasItem
+ {
+ public:
+ LibartImage(LibartCanvas *c, SVGImageElementImpl *image);
+ virtual ~LibartImage();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int = 0, int = 0) { }
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible();
+
+ // We can't include SVGImageElementImpl.h here
+ // because of compiliation errors (X11 headers!)
+ virtual SVGElementImpl *element() const { return reinterpret_cast<SVGElementImpl *>(m_image); }
+
+ protected:
+ LibartCanvas *m_canvas;
+ SVGImageElementImpl *m_image;
+ };
+
+ class LibartMarker : public CanvasMarker
+ {
+ public:
+ LibartMarker(LibartCanvas *c, SVGMarkerElementImpl *marker);
+ virtual ~LibartMarker();
+
+ virtual QRect bbox() const { return QRect(); }
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int = 0, int = 0) { }
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible() { return false; }
+
+ protected:
+ LibartCanvas *m_canvas;
+ };
+
+ class LibartText : public CanvasText, public LibartClipItem
+ {
+ public:
+ LibartText(LibartCanvas *c, SVGTextElementImpl *text);
+ virtual ~LibartText();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &p);
+ virtual bool strokeContains(const QPoint &p);
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0);
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const;
+ virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const;
+
+ void initClipItem();
+ ArtSVP *clipSVP();
+
+ protected:
+ LibartCanvas *m_canvas;
+
+ private:
+ void clearSVPs();
+
+ class SVPElement
+ {
+ public:
+ SVPElement() { svp = 0; element = 0; }
+ ~SVPElement();
+
+ _ArtSVP *svp;
+ SVGTextContentElementImpl *element;
+ };
+
+ // renderCallback() is const.
+ mutable QPtrList<SVPElement> m_drawFillItems;
+ mutable QPtrList<SVPElement> m_drawStrokeItems;
+ mutable QPtrDict<LibartFillPainter> m_fillPainters;
+ mutable QPtrDict<LibartStrokePainter> m_strokePainters;
+ };
+}
+
+#endif
+
diff --git a/ksvg/plugin/backends/libart/Makefile.am b/ksvg/plugin/backends/libart/Makefile.am
new file mode 100644
index 00000000..b3f4ea5b
--- /dev/null
+++ b/ksvg/plugin/backends/libart/Makefile.am
@@ -0,0 +1,11 @@
+kde_module_LTLIBRARIES = libksvgrendererlibart.la
+
+libksvgrendererlibart_la_SOURCES = BezierPathLibart.cpp GlyphTracerLibart.cpp LibartCanvas.cpp LibartCanvasItems.cpp LibartCanvasFactory.cpp
+libksvgrendererlibart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libksvgrendererlibart_la_LIBADD = ../../../libksvg.la
+libksvgrendererlibart_la_METASOURCES = AUTO
+
+kde_services_DATA = ksvglibartcanvas.desktop
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+INCLUDES = $(LIBART_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(KDE_INCLUDES) $(all_includes)
diff --git a/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop b/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop
new file mode 100644
index 00000000..af6f3a6c
--- /dev/null
+++ b/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop
@@ -0,0 +1,101 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KSVG/Renderer
+X-KDE-Library=libksvgrendererlibart
+X-KSVG-InternalName=libart
+Name=KSVG Rendering Backend - Libart
+Name[ar]=خلفية الرسم ل KSVG - Libart
+Name[bs]=KSVG renderiranje - Libart
+Name[ca]=Representació en segon pla de KSVG - Biblioteca d'imatges
+Name[cs]=Vykreslovací nástroj KSVG - Libart
+Name[cy]=Ôl-wyneb Llunio KSVG - Libart
+Name[da]=Underliggende program til KSVG-visning - Libart
+Name[de]=KSVG-Darstellungsmodul - Libart
+Name[el]=Σύστημα υποστήριξης αποτύπωσης του KSVG - Libart
+Name[es]=Motor de procesado de KSVG - Libart
+Name[et]=KSVG renderdamise taustarakendus - Libart
+Name[eu]=KSVG errendatze programa - Libart
+Name[fa]=پایانۀ پشتیبانی پرداخت KSVG - Libart
+Name[fi]=KSVG-piirtäjän taustaohjelma - Libart
+Name[fr]=Moteur de rendu KSVG - Libart
+Name[ga]=Inneall Rindreála KSVG - Libart
+Name[gl]=Mecanismo de Interpretación KSVG - Libart
+Name[hi]=के-एसवीजी रेंडरिंग बैकएण्ड- लिबआर्ट
+Name[hu]=KSVG megjelenítőmotor - Libart
+Name[is]=KSVG teiknari - Libart
+Name[it]=Backend di KSVG per il rendering - Libart
+Name[ja]=KSVG レンダリングバックエンド - Libart
+Name[kk]=KSVG кескіндеу бағдарламасы - Libart
+Name[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG - Libart
+Name[lt]=KSVG atkūrimo programinė sąsaja - Libart
+Name[ms]=Tepi Belakang Menrealisasi KSVG - Libart
+Name[nb]=Modul for KSVG-tegning – Libart
+Name[nds]=KSVG-Dorstellhölper - Libart
+Name[ne]=KSVG रेन्डरिङ ब्याकइन्ड - लिबर्ट
+Name[nl]=KSVG weergavecomponent - Libart
+Name[nn]=Modul for KSVG-teikning – Libart
+Name[pl]=Narzędzie do renderowania KSVG - Libart
+Name[pt]=Infra-Estrutura de Desenho do KSVG - Libart
+Name[pt_BR]=Estrutura de KSVG Rendering Backend - Libart
+Name[ro]=Motor de randare KSVG - Libart
+Name[ru]=Движок отрисовки KSVG - Libart
+Name[sk]=Nástroj pre zobrazovanie KSVG - libart
+Name[sl]=Izrisovalnik KSVG - Libart
+Name[sr]=KSVG-ов позадински систем за рендеровање — Libart
+Name[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje — Libart
+Name[sv]=KSVG-uppritningsmodul - konstbibliotek
+Name[ta]=KSVG வழங்கும் பின் அமைப்பு - லிபார்ட்
+Name[tg]=Лағжандаи тасовироти KSVG - Libart
+Name[tr]=KSVG Derleme Aracı - Libart
+Name[uk]=Інтерфейс відтворення KSVG - Libart
+Name[zh_CN]=KSVG 渲染后端 - Libart
+Name[zh_HK]=KSVG 合成後端 - Libart
+Name[zh_TW]=KSVG 上色後端介面 - Libart
+Comment=Mature ksvg rendering backend
+Comment[ar]=خلفية الرسم لksvg البالغة
+Comment[bs]=Zreli ksvg rendering backend
+Comment[ca]=Representador madur en segon pla de ksvg
+Comment[cs]=Vyspělý vykreslovací nástroj KSVG
+Comment[cy]=Ôl-wyneb llunio ksvg aeddfed
+Comment[da]=Modent underliggende program til ksvg-visning
+Comment[de]=Ausgereiftes KSVG-Darstellungsmodul
+Comment[el]=Ώριμο σύστημα υποστήριξης αποτύπωσης του KSVG
+Comment[es]=Motor de procesado de ksvg tradicional
+Comment[et]=Kasutamisküps ksvg renderdamise taustarakendus
+Comment[eu]=ksvg errendatze programa egonkorra
+Comment[fa]=پایانۀ پشتیبانی کامل پرداخت ksvg
+Comment[fi]=Kypsä ksvg-piirtäjän taustaohjelma
+Comment[fr]=Moteur de rendu KSVG mature
+Comment[gl]=Mecanismo de interpretación maduro ksvg
+Comment[hi]=परिपक्व के-एसवीजी रेंडरिंग बैकएण्ड
+Comment[hu]=Egy kiforrott megjelenítőmotor a KSVG-hez
+Comment[is]=Reyndur ksvg teiknari
+Comment[it]=Maturo backend di KSVG per il rendering
+Comment[ja]=成熟した ksvg レンダリングバックエンド
+Comment[kk]=Баяғы, жетілірдірген, KSVG кескіндеу бағдарламасы
+Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ ksvg ចាស់ៗ
+Comment[lt]=Išvystyta ksvg atkūrimo programinė sąsaja
+Comment[ms]=Tepi belakang menrealisasi ksvg matang
+Comment[nb]=Velutviklet modul for ksvg-tegning
+Comment[nds]=Reep KSVG-Dorstellhölper
+Comment[ne]=पूर्ण विकसित ksvg रेन्डरिङ ब्याकइन्ड
+Comment[nl]=Volgroeide KSVG weergavecomponent
+Comment[nn]=Velutvikla modul for ksvg-teikning
+Comment[pl]=Dopracowane narzędzie do renderowania KSVG
+Comment[pt]=Uma infra-estrutura de desenho do ksvg mais madura
+Comment[pt_BR]=Estrutura de renderização madura do ksvg
+Comment[ro]=Motor de randare KSVG matur
+Comment[ru]=Старый движок отрисовки ksvg
+Comment[sk]=Stabilný nástroj pre zobrazovanie ksvg
+Comment[sl]=Zrel izrisovalnik KSVG
+Comment[sr]=Стари KSVG-ов позадински систем за рендеровање
+Comment[sr@Latn]=Stari KSVG-ov pozadinski sistem za renderovanje
+Comment[sv]=Mogen KSVG-uppritningsmodul
+Comment[ta]=முழுமையான ksvg வழங்கும் பின் அமைப்பு
+Comment[tg]=Лағжандаи тасовироти кӯҳнаи ksvg
+Comment[tr]=Tamamlanmış ksvg derleme aracı
+Comment[uk]=Стабільний інтерфейс відтворення KSVG
+Comment[zh_CN]=稳定的 ksvg 渲染后端
+Comment[zh_HK]=成熟的 ksvg 合成後端
+Comment[zh_TW]=成熟的 ksvg 上色後端介面
+author=Nikolas Zimmermann <wildfox@kde.org>