blob: eaf8edee8f452e9421457691062b6cc1ad502d49 [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 <assert.h>
#include <kurl.h>
#include <klocale.h>
#include <kdom/Helper.h>
#include "Shared.h"
#include <kdom/Namespace.h>
#include <kdom/core/domattrs.h>
#include <kdom/cache/KDOMLoader.h>
#include "DocLoader.h"
#include <kdom/cache/KDOMCachedObject.h>
#include "cssstyleselector.h"
#include "css_stylesheetimpl.h"
#include <kdom/events/MouseEventImpl.h>
#include <kdom/events/KeyboardEventImpl.h>
#include <kdom/core/ProcessingInstructionImpl.h>
#include <kcanvas/KCanvas.h>
#include <kcanvas/RenderPath.h>
#include "ksvg.h"
//#include "Ecma.h"
#include <ksvg2/KSVGView.h>
#include "SVGElementImpl.h"
#include "SVGRenderStyle.h"
#include "SVGZoomEventImpl.h"
#include "KSVGTimeScheduler.h"
#include "SVGSVGElementImpl.h"
#include "SVGAnimatedStringImpl.h"
#include "SVGDOMImplementationImpl.h"
#include "SVGScriptElementImpl.h"
#include "SVGElementFactory.h"
#include "SVGStyleElementImpl.h"
#include "SVGTitleElementImpl.h"
#include "SVGDocumentImpl.h"
#include "EventNames.h"
namespace WebCore {
SVGDocumentImpl::SVGDocumentImpl(SVGDOMImplementationImpl *i, KDOMView *view) : DocumentImpl(i, view), CachedObjectClient()
{
m_scriptsIt = 0;
m_cachedScript = 0;
}
SVGDocumentImpl::~SVGDocumentImpl()
{
// Fire UNLOAD_EVENT upon destruction...
//if(DocumentImpl::hasListenerType(UNLOAD_EVENT))
{
int exceptioncode;
RefPtr<EventImpl> event = createEvent("SVGEvents", exceptioncode);
event->initEvent(EventNames::unloadEvent, false, false);
dispatchRecursiveEvent(event.get(), lastChild());
}
delete m_scriptsIt;
delete m_cachedScript;
}
DOMString SVGDocumentImpl::title() const
{
if(rootElement())
{
for(NodeImpl *child = rootElement()->firstChild(); child != 0; child = child->nextSibling())
if(child->hasTagName(SVGNames::titleTag))
return static_cast<SVGTitleElementImpl *>(child)->title();
}
return DOMString();
}
ElementImpl *SVGDocumentImpl::createElement(const DOMString& tagName, int& exceptionCode)
{
QualifiedName qname(nullAtom, tagName.impl(), SVGNames::svgNamespaceURI);
SVGElementImpl *elem = SVGElementFactory::createSVGElement(qname, this, false);
if(!elem)
return DocumentImpl::createElement(tagName, exceptionCode);
return elem;
}
SVGSVGElementImpl *SVGDocumentImpl::rootElement() const
{
ElementImpl *elem = documentElement();
if(elem && elem->hasTagName(SVGNames::svgTag))
return static_cast<SVGSVGElementImpl *>(elem);
return 0;
}
void SVGDocumentImpl::notifyFinished(CachedObject *finishedObj)
{
// This is called when a script has finished loading that was requested from
// executeScripts(). We execute the script, and then call executeScripts()
// again to continue iterating through the list of scripts in the document
if(finishedObj == m_cachedScript)
{
DOMString scriptSource = m_cachedScript->script();
m_cachedScript->deref(this);
m_cachedScript = 0;
SVGScriptElementImpl::executeScript(this, DOMString(scriptSource.qstring()).impl());
executeScripts(true);
}
}
FrameView *SVGDocumentImpl::svgView() const
{
return m_view;
}
void SVGDocumentImpl::finishedParsing()
{
addScripts(rootElement());
m_scriptsIt = new Q3PtrListIterator<SVGScriptElementImpl>(m_scripts);
executeScripts(false);
}
void SVGDocumentImpl::dispatchRecursiveEvent(EventImpl *event, NodeImpl *obj)
{
// Iterate the tree, backwards, and dispatch the event to every child
for(NodeImpl *n = obj; n != 0; n = n->previousSibling())
{
int exceptioncode;
if(n->hasChildNodes())
{
// Dispatch to all children
dispatchRecursiveEvent(event, n->lastChild());
// Dispatch, locally
n->dispatchEvent(event, exceptioncode);
}
else
n->dispatchEvent(event, exceptioncode);
}
}
void SVGDocumentImpl::dispatchZoomEvent(float prevScale, float newScale)
{
// dispatch zoom event
int exceptioncode;
RefPtr<SVGZoomEventImpl> event = static_cast<SVGZoomEventImpl *>(createEvent("SVGZoomEvents", exceptioncode));
event->initEvent(EventNames::zoomEvent, true, false);
event->setPreviousScale(prevScale);
event->setNewScale(newScale);
rootElement()->dispatchEvent(event.get(), exceptioncode);
}
void SVGDocumentImpl::dispatchScrollEvent()
{
// dispatch zoom event
int exceptioncode;
RefPtr<EventImpl> event = createEvent("SVGEvents", exceptioncode);
event->initEvent(EventNames::scrollEvent, true, false);
rootElement()->dispatchEvent(event.get(), exceptioncode);
}
bool SVGDocumentImpl::dispatchKeyEvent(EventTargetImpl *target, QKeyEvent *key, bool keypress)
{
// dispatch key event
int exceptioncode;
RefPtr<KeyboardEventImpl> keyEventImpl = static_cast<KeyboardEventImpl *>(createEvent("KeyboardEvents", exceptioncode));
//keyEventImpl->initKeyboardEvent(key);
target->dispatchEvent(keyEventImpl.get(), exceptioncode);
return /*keyEventImpl->defaultHandled() ||*/ keyEventImpl->defaultPrevented();
}
CSSStyleSelector *SVGDocumentImpl::createStyleSelector(const QString &usersheet)
{
return new CSSStyleSelector(this, usersheet, m_styleSheets.get(), false);
}
void SVGDocumentImpl::addScripts(NodeImpl *n)
{
if(!n)
return;
// Recursively go through the entire document tree, looking for svg <script> tags.
// For each of these that is found, add it to the m_scripts list from which they will be executed
if (n->hasTagName(SVGNames::scriptTag))
m_scripts.append(static_cast<SVGScriptElementImpl *>(n));
NodeImpl *child;
for(child = n->firstChild(); child != 0; child = child->nextSibling())
addScripts(child);
}
void SVGDocumentImpl::executeScripts(bool needsStyleSelectorUpdate)
{
// Iterate through all of the svg <script> tags in the document. For those that have a src attribute,
// start loading the script and return (executeScripts() will be called again once the script is loaded
// and continue where it left off). For scripts that don't have a src attribute, execute the code inside the tag
SVGScriptElementImpl *script = 0;
while((script = m_scriptsIt->current()))
{
DOMString hrefAttr(script->href()->baseVal());
QString charset; // TODO m_scriptsIt->current()->getAttribute(SVGNames::charsetAttr).qstring();
if(!hrefAttr.isEmpty())
{
// we have a src attribute
m_cachedScript = docLoader()->requestScript(hrefAttr, charset);
++(*m_scriptsIt);
m_cachedScript->ref(this); // will call executeScripts() again if already cached
return;
}
else
{
// no src attribute - execute from contents of tag
SVGScriptElementImpl::executeScript(this, script->textContent().impl());
++(*m_scriptsIt);
needsStyleSelectorUpdate = true;
}
}
// Fire LOAD_EVENT after all scripts are evaluated
if(!m_scriptsIt->current())
{
int exceptioncode;
RefPtr<EventImpl> event = createEvent("SVGEvents", exceptioncode);
event->initEvent(EventNames::loadEvent, false, false);
dispatchRecursiveEvent(event.get(), lastChild());
}
// All scripts have finished executing, so calculate the
// style for the document and close the last element
if(renderer() && needsStyleSelectorUpdate)
updateStyleSelector();
// close any unclosed nodes
Q3PtrListIterator<SVGElementImpl> it(m_forwardReferences);
for(;it.current(); ++it)
{
if(!it.current()->isClosed())
it.current()->closeRenderer();
}
m_forwardReferences.clear();
}
void SVGDocumentImpl::recalcStyle(StyleChange change)
{
for(NodeImpl *n = firstChild(); n; n = n->nextSibling())
{
if(change >= Inherit || n->hasChangedChild() || n->changed())
n->recalcStyle(change);
}
}
void SVGDocumentImpl::dispatchUIEvent(EventTargetImpl *target, const AtomicString &type)
{
// Setup kdom 'UIEvent'...
int exceptioncode;
RefPtr<UIEventImpl> event = static_cast<UIEventImpl *>(createEvent("UIEvents", exceptioncode));
event->initUIEvent(type, true, true, 0, 0);
target->dispatchEvent(event.get(), exceptioncode);
}
void SVGDocumentImpl::dispatchMouseEvent(EventTargetImpl *target, const AtomicString &type)
{
// Setup kdom 'MouseEvent'...
int exceptioncode;
RefPtr<MouseEventImpl> event = static_cast<MouseEventImpl *>(createEvent("MouseEvents", exceptioncode));
event->initEvent(type, true, true);
target->dispatchEvent(event.get(), exceptioncode);
}
void SVGDocumentImpl::addForwardReference(const SVGElementImpl *element)
{
m_forwardReferences.append(element);
}
}
// vim:ts=4:noet
#endif // SVG_SUPPORT