blob: a90617a15f3c08ba8993d09fcf5b100938869653 [file] [log] [blame]
/*
Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
2004, 2005 Rob Buis <buis@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., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "config.h"
#if SVG_SUPPORT
#include "SVGSVGElementImpl.h"
#include "DocumentImpl.h"
#include "EventListener.h"
#include "EventNames.h"
#include "KCanvasRenderingStyle.h"
#include "KSVGTimeScheduler.h"
#include "SVGAngleImpl.h"
#include "SVGAnimatedLengthImpl.h"
#include "SVGAnimatedPreserveAspectRatioImpl.h"
#include "SVGAnimatedRectImpl.h"
#include "SVGDocumentExtensions.h"
#include "SVGFitToViewBoxImpl.h"
#include "SVGHelper.h"
#include "SVGLengthImpl.h"
#include "SVGMatrixImpl.h"
#include "SVGNames.h"
#include "SVGNumberImpl.h"
#include "SVGPointImpl.h"
#include "SVGPreserveAspectRatioImpl.h"
#include "SVGRectImpl.h"
#include "SVGRenderStyle.h"
#include "SVGTransformImpl.h"
#include "SVGZoomAndPanImpl.h"
#include "SVGZoomEventImpl.h"
#include "StringImpl.h"
#include "cssproperties.h"
#include "htmlnames.h"
#include "ksvg.h"
#include <kcanvas/KCanvas.h>
#include <kcanvas/KCanvasContainer.h>
#include <kcanvas/KCanvasCreator.h>
#include <kcanvas/KCanvasMatrix.h>
#include <kcanvas/RenderPath.h>
#include <kcanvas/device/KRenderingDevice.h>
#include <kdom/core/AttrImpl.h>
#include <kdom/core/NamedAttrMapImpl.h>
#include <qtextstream.h>
namespace WebCore {
using namespace HTMLNames;
using namespace EventNames;
SVGSVGElementImpl::SVGSVGElementImpl(const QualifiedName& tagName, DocumentImpl *doc)
: SVGStyledLocatableElementImpl(tagName, doc), SVGTestsImpl(), SVGLangSpaceImpl(),
SVGExternalResourcesRequiredImpl(), SVGFitToViewBoxImpl(),
SVGZoomAndPanImpl()
{
m_useCurrentView = false;
}
SVGSVGElementImpl::~SVGSVGElementImpl()
{
}
SVGAnimatedLengthImpl *SVGSVGElementImpl::x() const
{
const SVGElementImpl *viewport = ownerDocument()->documentElement() == this ? this : viewportElement();
return lazy_create<SVGAnimatedLengthImpl>(m_x, (SVGStyledElementImpl *)0, LM_WIDTH, viewport);
}
SVGAnimatedLengthImpl *SVGSVGElementImpl::y() const
{
const SVGElementImpl *viewport = ownerDocument()->documentElement() == this ? this : viewportElement();
return lazy_create<SVGAnimatedLengthImpl>(m_y, (SVGStyledElementImpl *)0, LM_HEIGHT, viewport);
}
SVGAnimatedLengthImpl *SVGSVGElementImpl::width() const
{
if (!m_width) {
DOMString temp("100%");
const SVGElementImpl *viewport = ownerDocument()->documentElement() == this ? this : viewportElement();
lazy_create<SVGAnimatedLengthImpl>(m_width, (SVGStyledElementImpl *)0, LM_WIDTH, viewport);
m_width->baseVal()->setValueAsString(temp.impl());
}
return m_width.get();
}
SVGAnimatedLengthImpl *SVGSVGElementImpl::height() const
{
if (!m_height) {
DOMString temp("100%");
const SVGElementImpl *viewport = ownerDocument()->documentElement() == this ? this : viewportElement();
lazy_create<SVGAnimatedLengthImpl>(m_height, (SVGStyledElementImpl *)0, LM_HEIGHT, viewport);
m_height->baseVal()->setValueAsString(temp.impl());
}
return m_height.get();
}
AtomicString SVGSVGElementImpl::contentScriptType() const
{
return tryGetAttribute("contentScriptType", "text/ecmascript");
}
void SVGSVGElementImpl::setContentScriptType(const AtomicString& type)
{
setAttribute(SVGNames::contentScriptTypeAttr, type);
}
AtomicString SVGSVGElementImpl::contentStyleType() const
{
return tryGetAttribute("contentStyleType", "text/css");
}
void SVGSVGElementImpl::setContentStyleType(const AtomicString& type)
{
setAttribute(SVGNames::contentStyleTypeAttr, type);
}
SVGRectImpl *SVGSVGElementImpl::viewport() const
{
SVGRectImpl *ret = createSVGRect();
double _x = x()->baseVal()->value();
double _y = y()->baseVal()->value();
double w = width()->baseVal()->value();
double h = height()->baseVal()->value();
RefPtr<SVGMatrixImpl> viewBox = viewBoxToViewTransform(w, h);
viewBox->qmatrix().map(_x, _y, &_x, &_y);
viewBox->qmatrix().map(w, h, &w, &h);
ret->setX(_x);
ret->setY(_y);
ret->setWidth(w);
ret->setHeight(h);
return ret;
}
float SVGSVGElementImpl::pixelUnitToMillimeterX() const
{
#if 0
if(ownerDocument() && ownerDocument()->paintDeviceMetrics())
{
Q3PaintDeviceMetrics *metrics = ownerDocument()->paintDeviceMetrics();
return float(metrics->widthMM()) / float(metrics->width());
}
#endif
return .28;
}
float SVGSVGElementImpl::pixelUnitToMillimeterY() const
{
#if 0
if(ownerDocument() && ownerDocument()->paintDeviceMetrics())
{
Q3PaintDeviceMetrics *metrics = ownerDocument()->paintDeviceMetrics();
return float(metrics->heightMM()) / float(metrics->height());
}
#endif
return .28;
}
float SVGSVGElementImpl::screenPixelToMillimeterX() const
{
return pixelUnitToMillimeterX();
}
float SVGSVGElementImpl::screenPixelToMillimeterY() const
{
return pixelUnitToMillimeterY();
}
bool SVGSVGElementImpl::useCurrentView() const
{
return m_useCurrentView;
}
void SVGSVGElementImpl::setUseCurrentView(bool currentView)
{
m_useCurrentView = currentView;
}
float SVGSVGElementImpl::currentScale() const
{
//if(!canvasView())
return 1.;
//return canvasView()->zoom();
}
void SVGSVGElementImpl::setCurrentScale(float scale)
{
// if(canvasView())
// {
// float oldzoom = canvasView()->zoom();
// canvasView()->setZoom(scale);
// getDocument()->dispatchZoomEvent(oldzoom, scale);
// }
}
SVGPointImpl *SVGSVGElementImpl::currentTranslate() const
{
//if(!canvas())
return 0;
//return createSVGPoint(canvasView()->pan());
}
void SVGSVGElementImpl::addSVGWindowEventListner(const AtomicString& eventType, const AttributeImpl* attr)
{
// FIXME: None of these should be window events long term.
// Once we propertly support SVGLoad, etc.
RefPtr<EventListener> listener = getDocument()->accessSVGExtensions()->createSVGEventListener(attr->value(), this);
getDocument()->setHTMLWindowEventListener(eventType, listener.release());
}
void SVGSVGElementImpl::parseMappedAttribute(MappedAttributeImpl *attr)
{
const AtomicString& value = attr->value();
if (!nearestViewportElement()) {
// Only handle events if we're the outermost <svg> element
if (attr->name() == onloadAttr)
addSVGWindowEventListner(loadEvent, attr);
else if (attr->name() == onunloadAttr)
addSVGWindowEventListner(unloadEvent, attr);
else if (attr->name() == onabortAttr)
addSVGWindowEventListner(abortEvent, attr);
else if (attr->name() == onerrorAttr)
addSVGWindowEventListner(errorEvent, attr);
else if (attr->name() == onresizeAttr)
addSVGWindowEventListner(resizeEvent, attr);
else if (attr->name() == onscrollAttr)
addSVGWindowEventListner(scrollEvent, attr);
else if (attr->name() == SVGNames::onzoomAttr)
addSVGWindowEventListner(zoomEvent, attr);
}
if (attr->name() == SVGNames::xAttr) {
x()->baseVal()->setValueAsString(value.impl());
} else if (attr->name() == SVGNames::yAttr) {
y()->baseVal()->setValueAsString(value.impl());
} else if (attr->name() == SVGNames::widthAttr) {
width()->baseVal()->setValueAsString(value.impl());
addCSSProperty(attr, CSS_PROP_WIDTH, value);
} else if (attr->name() == SVGNames::heightAttr) {
height()->baseVal()->setValueAsString(value.impl());
addCSSProperty(attr, CSS_PROP_HEIGHT, value);
} else
{
if(SVGTestsImpl::parseMappedAttribute(attr)) return;
if(SVGLangSpaceImpl::parseMappedAttribute(attr)) return;
if(SVGExternalResourcesRequiredImpl::parseMappedAttribute(attr)) return;
if (SVGFitToViewBoxImpl::parseMappedAttribute(attr)) {
if (renderer())
static_cast<KCanvasContainer*>(renderer())->setViewBox(FloatRect(viewBox()->baseVal()->x(), viewBox()->baseVal()->y(), viewBox()->baseVal()->width(), viewBox()->baseVal()->height()));
}
if(SVGZoomAndPanImpl::parseMappedAttribute(attr)) return;
SVGStyledLocatableElementImpl::parseMappedAttribute(attr);
}
}
unsigned long SVGSVGElementImpl::suspendRedraw(unsigned long /* max_wait_milliseconds */)
{
// TODO
return 0;
}
void SVGSVGElementImpl::unsuspendRedraw(unsigned long /* suspend_handle_id */)
{
// TODO
}
void SVGSVGElementImpl::unsuspendRedrawAll()
{
// TODO
}
void SVGSVGElementImpl::forceRedraw()
{
// TODO
}
NodeListImpl *SVGSVGElementImpl::getIntersectionList(SVGRectImpl *rect, SVGElementImpl *)
{
//NodeListImpl *list;
// TODO
return 0;
}
NodeListImpl *SVGSVGElementImpl::getEnclosureList(SVGRectImpl *rect, SVGElementImpl *)
{
// TODO
return 0;
}
bool SVGSVGElementImpl::checkIntersection(SVGElementImpl *element, SVGRectImpl *rect)
{
// TODO : take into account pointer-events?
RefPtr<SVGRectImpl> bbox = getBBox();
FloatRect r(rect->x(), rect->y(), rect->width(), rect->height());
FloatRect r2(bbox->x(), bbox->y(), bbox->width(), bbox->height());
return r.intersects(r2);
}
bool SVGSVGElementImpl::checkEnclosure(SVGElementImpl *element, SVGRectImpl *rect)
{
// TODO : take into account pointer-events?
RefPtr<SVGRectImpl> bbox = getBBox();
FloatRect r(rect->x(), rect->y(), rect->width(), rect->height());
FloatRect r2(bbox->x(), bbox->y(), bbox->width(), bbox->height());
return r.contains(r2);
}
void SVGSVGElementImpl::deselectAll()
{
// TODO
}
SVGNumberImpl *SVGSVGElementImpl::createSVGNumber()
{
return new SVGNumberImpl(0);
}
SVGLengthImpl *SVGSVGElementImpl::createSVGLength()
{
return new SVGLengthImpl(0);
}
SVGAngleImpl *SVGSVGElementImpl::createSVGAngle()
{
return new SVGAngleImpl(0);
}
SVGPointImpl *SVGSVGElementImpl::createSVGPoint(const IntPoint &p)
{
return new SVGPointImpl(p);
}
SVGMatrixImpl *SVGSVGElementImpl::createSVGMatrix()
{
return new SVGMatrixImpl();
}
SVGRectImpl *SVGSVGElementImpl::createSVGRect()
{
return new SVGRectImpl(0);
}
SVGTransformImpl *SVGSVGElementImpl::createSVGTransform()
{
return new SVGTransformImpl();
}
SVGTransformImpl *SVGSVGElementImpl::createSVGTransformFromMatrix(SVGMatrixImpl *matrix)
{
SVGTransformImpl *obj = SVGSVGElementImpl::createSVGTransform();
obj->setMatrix(matrix);
return obj;
}
SVGMatrixImpl *SVGSVGElementImpl::getCTM() const
{
SVGMatrixImpl *mat = createSVGMatrix();
if(mat)
{
mat->translate(x()->baseVal()->value(), y()->baseVal()->value());
if(attributes()->getNamedItem(SVGNames::viewBoxAttr))
{
RefPtr<SVGMatrixImpl> viewBox = viewBoxToViewTransform(width()->baseVal()->value(), height()->baseVal()->value());
mat->multiply(viewBox.get());
}
}
return mat;
}
SVGMatrixImpl *SVGSVGElementImpl::getScreenCTM() const
{
SVGMatrixImpl *mat = SVGStyledLocatableElementImpl::getScreenCTM();
if(mat)
{
mat->translate(x()->baseVal()->value(), y()->baseVal()->value());
if(attributes()->getNamedItem(SVGNames::viewBoxAttr))
{
RefPtr<SVGMatrixImpl> viewBox = viewBoxToViewTransform(width()->baseVal()->value(), height()->baseVal()->value());
mat->multiply(viewBox.get());
}
}
return mat;
}
RenderObject *SVGSVGElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
{
KCanvasContainer *rootContainer = renderingDevice()->createContainer(arena, style, this);
// FIXME: all this setup should be done after attributesChanged, not here.
float _x = x()->baseVal()->value();
float _y = y()->baseVal()->value();
float _width = width()->baseVal()->value();
float _height = height()->baseVal()->value();
rootContainer->setViewport(FloatRect(_x, _y, _width, _height));
rootContainer->setViewBox(FloatRect(viewBox()->baseVal()->x(), viewBox()->baseVal()->y(), viewBox()->baseVal()->width(), viewBox()->baseVal()->height()));
rootContainer->setAlign(KCAlign(preserveAspectRatio()->baseVal()->align() - 1));
rootContainer->setSlice(preserveAspectRatio()->baseVal()->meetOrSlice() == SVG_MEETORSLICE_SLICE);
return rootContainer;
}
void SVGSVGElementImpl::setZoomAndPan(unsigned short zoomAndPan)
{
SVGZoomAndPanImpl::setZoomAndPan(zoomAndPan);
//canvasView()->enableZoomAndPan(zoomAndPan == SVG_ZOOMANDPAN_MAGNIFY);
}
}
// vim:ts=4:noet
#endif // SVG_SUPPORT