+2006-08-14 Eric Seidel <eric@eseidel.com>
+
+ Reviewed by darin and mjs.
+
+ Add better SVGLoad event support.
+ http://bugzilla.opendarwin.org/show_bug.cgi?id=6010
+ Updated test results.
+
+ * svg/W3C-SVG-1.1/extend-namespace-01-f-expected.checksum:
+ * svg/W3C-SVG-1.1/extend-namespace-01-f-expected.png:
+ * svg/W3C-SVG-1.1/extend-namespace-01-f-expected.txt:
+ * svg/W3C-SVG-1.1/struct-dom-01-b-expected.checksum:
+ * svg/W3C-SVG-1.1/struct-dom-01-b-expected.png:
+ * svg/W3C-SVG-1.1/struct-dom-01-b-expected.txt:
+ * svg/W3C-SVG-1.1/struct-dom-02-b-expected.checksum:
+ * svg/W3C-SVG-1.1/struct-dom-02-b-expected.png:
+ * svg/W3C-SVG-1.1/struct-dom-02-b-expected.txt:
+ * svg/W3C-SVG-1.1/struct-dom-03-b-expected.checksum:
+ * svg/W3C-SVG-1.1/struct-dom-03-b-expected.png:
+ * svg/W3C-SVG-1.1/struct-dom-03-b-expected.txt:
+ * svg/W3C-SVG-1.1/struct-dom-04-b-expected.checksum:
+ * svg/W3C-SVG-1.1/struct-dom-04-b-expected.png:
+ * svg/W3C-SVG-1.1/struct-dom-04-b-expected.txt:
+ * svg/W3C-SVG-1.1/struct-dom-05-b-expected.checksum:
+ * svg/W3C-SVG-1.1/struct-dom-05-b-expected.png:
+ * svg/W3C-SVG-1.1/struct-dom-05-b-expected.txt:
+ * svg/W3C-SVG-1.1/struct-dom-06-b-expected.checksum:
+ * svg/W3C-SVG-1.1/struct-dom-06-b-expected.png:
+ * svg/W3C-SVG-1.1/struct-dom-06-b-expected.txt:
+
2006-08-14 Maciej Stachowiak <mjs@apple.com>
Missing expected results for last test.
-bf2a1657c3305f4818f274ffb5fad223
\ No newline at end of file
+40e2571f917ea604155cc19efaa67b48
\ No newline at end of file
layer at (0,0) size 480x360
RenderView at (0,0) size 480x360
KCanvasContainer {svg} at (0.50,0.50) size 479x359
- KCanvasContainer {g} at (0,0) size 0x0
+ KCanvasContainer {g} at (126.05,61.42) size 242.55x213.97
KCanvasContainer {g} at (0,0) size 0x0
RenderSVGText {text} at (0,0) size 465x18
RenderText {#text} at (0,0) size 349x17
text run at (0,0) width 349: "Pie chart built from data in a different namespace."
- KCanvasContainer {g} at (0,0) size 0x0
+ KCanvasContainer {g} at (126.05,61.42) size 242.55x213.97
+ KCanvasItem {path} at (263.86,76.89) size 104.74x81.61 [transform={m=((1.00,0.00)(0.00,1.00)) t=(27.00,-13.00)}] [stroke={[type=SOLID] [color=#0000FF] [stroke width=3.00]}] [fill={[type=SOLID] [color=#FF8888]}] [data="M240.00,170.00L340.00,170.00C340.10,139.74,326.50,111.06,303.00,92.00"]
+ RenderSVGText {text} at (0,0) size 465x16
+ RenderText {#text} at (0,0) size 28x16
+ text run at (0,0) width 28: "East"
+ KCanvasItem {path} at (190.64,61.42) size 113.76x110.37 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#6D6D6D]}] [data="M240.00,170.00L303.00,92.00C271.46,66.45,227.60,62.50,192.00,82.00"]
+ RenderSVGText {text} at (0,0) size 465x16
+ RenderText {#text} at (0,0) size 35x16
+ text run at (0,0) width 35: "North"
+ KCanvasItem {path} at (126.05,80.65) size 115.35x130.67 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#929292]}] [data="M240.00,170.00L192.00,82.00C146.30,106.75,127.18,162.38,148.00,210.00"]
+ RenderSVGText {text} at (0,0) size 465x16
+ RenderText {#text} at (0,0) size 32x16
+ text run at (0,0) width 32: "West"
+ KCanvasItem {path} at (146.68,168.31) size 94.70x100.88 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#B6B6B6]}] [data="M240.00,170.00L148.00,210.00C160.89,239.68,187.34,261.29,219.00,268.00"]
+ RenderSVGText {text} at (0,0) size 465x16
+ RenderText {#text} at (0,0) size 46x16
+ text run at (0,0) width 46: "Central"
+ KCanvasItem {path} at (217.81,169) size 123.26x106.39 [stroke={[type=SOLID] [color=#000000] [stroke width=2.00]}] [fill={[type=SOLID] [color=#DBDBDB]}] [data="M240.00,170.00L219.00,268.00C248.57,274.35,279.43,266.98,302.94,247.94C326.44,228.90,340.07,200.25,340.00,170.00"]
+ RenderSVGText {text} at (0,0) size 465x16
+ RenderText {#text} at (0,0) size 37x16
+ text run at (0,0) width 37: "South"
RenderSVGText {text} at (0,0) size 465x46
RenderText {#text} at (0,0) size 264x46
text run at (0,0) width 264: "$Revision: 1.1 $"
-0763e33b8aad0b768fa66561d59cf282
\ No newline at end of file
+40a6bbba9a7b85b0d4c525998e31763a
\ No newline at end of file
KCanvasContainer {svg} at (0.50,0.50) size 479x359
KCanvasContainer {g} at (40,150) size 50x50
KCanvasItem {rect} at (40,150) size 50x50 [fill={[type=SOLID] [color=#FF0000]}] [data="M40.00,150.00L90.00,150.00L90.00,200.00L40.00,200.00"]
+ RenderSVGText {text} at (0,0) size 465x18
+ RenderText {#text} at (0,0) size 266x18
+ text run at (0,0) width 266: "This document's root identifier is: svg-root"
RenderSVGText {text} at (0,0) size 465x36
RenderText {#text} at (0,0) size 198x36
text run at (0,0) width 198: "$Revision: 1.1 $"
-990fae4e2eca24cf2f3fe0438a6eb8ca
\ No newline at end of file
+eb57fcf5ec1c29efaf461f26d34bd57f
\ No newline at end of file
RenderText {#text} at (0,0) size 198x36
text run at (0,0) width 198: "$Revision: 1.1 $"
KCanvasItem {rect} at (0.50,0.50) size 479x359 [stroke={[type=SOLID] [color=#000000]}] [data="M1.00,1.00L479.00,1.00L479.00,359.00L1.00,359.00"]
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "xml"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "true"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 129x36
+ text run at (0,0) width 129: "stylesheets"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "true"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 70x36
+ text run at (0,0) width 70: "views"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "true"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 52x36
+ text run at (0,0) width 52: "css2"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "true"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 76x36
+ text run at (0,0) width 76: "events"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "true"
-990fae4e2eca24cf2f3fe0438a6eb8ca
\ No newline at end of file
+ebd638b5c2115f2143e86868c6c44d56
\ No newline at end of file
RenderText {#text} at (0,0) size 198x36
text run at (0,0) width 198: "$Revision: 1.1 $"
KCanvasItem {rect} at (0.50,0.50) size 479x359 [stroke={[type=SOLID] [color=#000000]}] [data="M1.00,1.00L479.00,1.00L479.00,359.00L1.00,359.00"]
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 99x36
+ text run at (0,0) width 99: "uievents"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 154x36
+ text run at (0,0) width 154: "mouseevents"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "true"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 181x36
+ text run at (0,0) width 181: "mutationevents"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "true"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 102x36
+ text run at (0,0) width 102: "traversal"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 46x36
+ text run at (0,0) width 46: "true"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 148x36
+ text run at (0,0) width 148: "org.w3c.svg"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
-990fae4e2eca24cf2f3fe0438a6eb8ca
\ No newline at end of file
+aaf1fe3f6c5db04e7fd07b4830be3e5e
\ No newline at end of file
RenderText {#text} at (0,0) size 198x36
text run at (0,0) width 198: "$Revision: 1.1 $"
KCanvasItem {rect} at (0.50,0.50) size 479x359 [stroke={[type=SOLID] [color=#000000]}] [data="M1.00,1.00L479.00,1.00L479.00,359.00L1.00,359.00"]
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 207x36
+ text run at (0,0) width 207: "org.w3c.svg.lang"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 258x36
+ text run at (0,0) width 258: "org.w3c.svg.dynamic"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 218x36
+ text run at (0,0) width 218: "org.w3c.svg.static"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 209x36
+ text run at (0,0) width 209: "org.w3c.dom.svg"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 148x36
+ text run at (0,0) width 148: "org.w3c.svg"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
-990fae4e2eca24cf2f3fe0438a6eb8ca
\ No newline at end of file
+9058873570c32158449fa57b60caaa3b
\ No newline at end of file
RenderText {#text} at (0,0) size 198x36
text run at (0,0) width 198: "$Revision: 1.1 $"
KCanvasItem {rect} at (0.50,0.50) size 479x359 [stroke={[type=SOLID] [color=#000000]}] [data="M1.00,1.00L479.00,1.00L479.00,359.00L1.00,359.00"]
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 279x36
+ text run at (0,0) width 279: "org.w3c.dom.svg.static"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 335x36
+ text run at (0,0) width 335: "org.w3c.dom.svg.animation"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 319x36
+ text run at (0,0) width 319: "org.w3c.dom.svg.dynamic"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 246x36
+ text run at (0,0) width 246: "org.w3c.dom.svg.all"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 185x36
+ text run at (0,0) width 185: "org.w3c.svg.all"
+ RenderSVGText {text} at (0,0) size 465x36
+ RenderText {#text} at (0,0) size 56x36
+ text run at (0,0) width 56: "false"
-b50397794a544a22aaf283804f83b426
\ No newline at end of file
+667ede172909f628f8032933dde32df6
\ No newline at end of file
layer at (0,0) size 480x360
RenderView at (0,0) size 480x360
- KCanvasContainer {svg} at (0,0) size 479.50x450
- KCanvasContainer {g} at (0,0) size 450x450
- KCanvasItem {rect} at (0,0) size 450x450 [fill={[type=SOLID] [color=#FF0000]}] [data="M0.00,0.00L450.00,0.00L450.00,450.00L0.00,450.00"]
- RenderSVGText {text} at (0,0) size 465x72
- RenderText {#text} at (0,0) size 418x72
- text run at (0,0) width 418: "Removing DOM Elements is"
- text run at (0,36) width 213: "not supported"
+ KCanvasContainer {svg} at (0.50,0.50) size 479x359
+ KCanvasContainer {g} at (0,0) size 0x0
+ KCanvasItem {rect} at (inf,inf) size 0x0 [fill={[type=SOLID] [color=#FF0000]}] [data=""]
+ RenderSVGText {text} at (0,0) size 465x18
+ RenderText {#text} at (0,0) size 148x18
+ text run at (0,0) width 148: "DOM API is supported"
RenderSVGText {text} at (0,0) size 465x36
RenderText {#text} at (0,0) size 198x36
text run at (0,0) width 198: "$Revision: 1.1 $"
+2006-08-14 Eric Seidel <eric@eseidel.com>
+
+ Reviewed by darin and mjs.
+
+ Add better SVGLoad event support.
+ http://bugzilla.opendarwin.org/show_bug.cgi?id=6010
+ There will still need to be additional support added for <link> and <script> elements.
+ Not all of the error -> loaded -> error transition cases work yet.
+
+ * dom/EventTargetNode.cpp:
+ (WebCore::EventTargetNode::dispatchGenericEvent):
+ * html/HTMLImageLoader.cpp:
+ (WebCore::HTMLImageLoader::dispatchLoadEvent):
+ * html/HTMLImageLoader.h:
+ (WebCore::HTMLImageLoader::haveFiredLoadEvent):
+ (WebCore::HTMLImageLoader::setHaveFiredLoadEvent):
+ * ksvg2/misc/SVGImageLoader.cpp:
+ (WebCore::SVGImageLoader::SVGImageLoader):
+ (WebCore::SVGImageLoader::dispatchLoadEvent):
+ * ksvg2/misc/SVGImageLoader.h:
+ * ksvg2/svg/SVGAElement.cpp:
+ (WebCore::SVGAElement::parseMappedAttribute):
+ * ksvg2/svg/SVGAnimatedBoolean.h:
+ * ksvg2/svg/SVGElement.cpp:
+ (WebCore::SVGElement::SVGElement):
+ (WebCore::SVGElement::parseMappedAttribute):
+ (WebCore::SVGElement::haveLoadedRequiredResources):
+ (WebCore::SVGElement::sendSVGLoadEventIfPossible):
+ (WebCore::SVGElement::closeRenderer):
+ * ksvg2/svg/SVGElement.h:
+ (WebCore::SVGElement::rendererIsNeeded):
+ (WebCore::svg_dynamic_cast):
+ * ksvg2/svg/SVGExternalResourcesRequired.h:
+ * ksvg2/svg/SVGImageElement.cpp:
+ (SVGImageElement::SVGImageElement):
+ (SVGImageElement::haveLoadedRequiredResources):
+ * ksvg2/svg/SVGImageElement.h:
+ * ksvg2/svg/SVGSVGElement.cpp:
+ (WebCore::SVGSVGElement::parseMappedAttribute):
+ * ksvg2/svg/SVGScriptElement.cpp:
+ (WebCore::SVGScriptElement::SVGScriptElement):
+ (WebCore::SVGScriptElement::parseMappedAttribute):
+ (WebCore::SVGScriptElement::executeScript):
+ * xml/xmlhttprequest.cpp:
+ (WebCore::XMLHttpRequest::callReadyStateChangeListener): use new Event() instead of createEvent
+
2006-08-14 Anders Carlsson <acarlsson@apple.com>
Reviewed by Maciej.
RefPtr<Event> evt(e);
assert(!eventDispatchForbidden());
assert(evt->target());
-
- // ### check that type specified
+ assert(!evt->type().isNull()); // JavaScript code could create an event with an empty name
// work out what nodes to send event to
DeprecatedPtrList<Node> nodeChain;
void HTMLImageLoader::dispatchLoadEvent()
{
- if (!m_firedLoad && m_image) {
- m_firedLoad = true;
- element()->dispatchHTMLEvent(m_image->isErrorImage() ? errorEvent : loadEvent, false, false);
+ if (!haveFiredLoadEvent() && image()) {
+ setHaveFiredLoadEvent(true);
+ element()->dispatchHTMLEvent(image()->isErrorImage() ? errorEvent : loadEvent, false, false);
}
}
virtual void updateFromElement();
- void dispatchLoadEvent();
+ virtual void dispatchLoadEvent();
Element* element() const { return m_element; }
bool imageComplete() const { return m_imageComplete; }
protected:
void setLoadingImage(CachedImage*);
+
+ bool haveFiredLoadEvent() { return m_firedLoad; }
+ void setHaveFiredLoadEvent(bool firedLoad) { m_firedLoad = firedLoad; }
private:
Element* m_element;
namespace WebCore {
-SVGImageLoader::SVGImageLoader(SVGImageElement *node) : HTMLImageLoader(node)
+SVGImageLoader::SVGImageLoader(SVGImageElement* node)
+ : HTMLImageLoader(node)
{
}
renderer->resetAnimation();
}
+void SVGImageLoader::dispatchLoadEvent()
+{
+ if (!haveFiredLoadEvent() && image()) {
+ setHaveFiredLoadEvent(true);
+ if (image()->isErrorImage()) {
+ // FIXME: We're supposed to put the document in an "error state" per the spec.
+ } else
+ static_cast<SVGElement*>(element())->sendSVGLoadEventIfPossible(true);
+ }
+}
+
}
#endif // SVG_SUPPORT
virtual ~SVGImageLoader();
virtual void updateFromElement();
+ virtual void dispatchLoadEvent();
};
} // namespace WebCore
if (attr->name() == SVGNames::targetAttr) {
target()->setBaseVal(value.impl());
} else {
- if(SVGURIReference::parseMappedAttribute(attr))
- {
+ if (SVGURIReference::parseMappedAttribute(attr)) {
m_isLink = attr->value() != 0;
return;
}
- if(SVGTests::parseMappedAttribute(attr)) return;
- if(SVGLangSpace::parseMappedAttribute(attr)) return;
- if(SVGExternalResourcesRequired::parseMappedAttribute(attr)) return;
+ if (SVGTests::parseMappedAttribute(attr))
+ return;
+ if (SVGLangSpace::parseMappedAttribute(attr))
+ return;
+ if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
+ return;
SVGStyledTransformableElement::parseMappedAttribute(attr);
}
}
#include "Attr.h"
#include "Document.h"
#include "DOMImplementation.h"
+#include "Event.h"
#include "EventListener.h"
#include "EventNames.h"
#include "HTMLNames.h"
SVGElement::SVGElement(const QualifiedName& tagName, Document* doc)
: StyledElement(tagName, doc)
- , m_closed(false)
{
}
void SVGElement::parseMappedAttribute(MappedAttribute *attr)
{
// standard events
- if (attr->name() == onclickAttr)
+ if (attr->name() == onloadAttr)
+ addSVGEventListener(loadEvent, attr);
+ else if (attr->name() == onclickAttr)
addSVGEventListener(clickEvent, attr);
else if (attr->name() == onmousedownAttr)
addSVGEventListener(mousedownEvent, attr);
StyledElement::parseMappedAttribute(attr);
}
+bool SVGElement::haveLoadedRequiredResources()
+{
+ Node* child = fastFirstChild();
+ while (child) {
+ if (child->isSVGElement() && !static_cast<SVGElement*>(child)->haveLoadedRequiredResources())
+ return false;
+ child = child->nextSibling();
+ }
+ return true;
+}
+
+void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
+{
+ RefPtr<SVGElement> currentTarget = this;
+ while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
+ RefPtr<Node> parent;
+ if (sendParentLoadEvents)
+ parent = currentTarget->parentNode(); // save the next parent to dispatch too incase dispatching the event changes the tree
+
+ // FIXME: This malloc could be avoided by walking the tree first to check if any listeners are present: http://bugzilla.opendarwin.org/show_bug.cgi?id=10264
+ RefPtr<Event> event = new Event(loadEvent, false, false);
+ event->setTarget(currentTarget.get());
+ ExceptionCode ignored = 0;
+ dispatchGenericEvent(event.release(), ignored, false);
+ currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : 0;
+ }
+}
+
+void SVGElement::closeRenderer()
+{
+ // closeRenderer() is called when the close tag is reached for an element (e.g. </svg>)
+ // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
+ sendSVGLoadEventIfPossible();
+}
+
bool SVGElement::childShouldCreateRenderer(Node *child) const
{
if (child->isSVGElement())
// Internal
virtual void parseMappedAttribute(MappedAttribute*);
-
- // To be implemented by any element which can establish new viewports...
- virtual DeprecatedString adjustViewportClipping() const { return DeprecatedString::null; }
virtual bool isStyled() const { return false; }
virtual bool isStyledTransformable() const { return false; }
// For SVGTests
virtual bool isValid() const { return true; }
- virtual void closeRenderer() { m_closed = true; }
+ virtual void closeRenderer();
virtual bool rendererIsNeeded(RenderStyle*) { return false; }
virtual bool childShouldCreateRenderer(Node*) const;
- // helper:
- bool isClosed() const { return m_closed; }
+ void sendSVGLoadEventIfPossible(bool sendParentLoadEvents = false);
private:
- bool m_closed;
void addSVGEventListener(const AtomicString& eventType, const Attribute*);
+ virtual bool haveLoadedRequiredResources();
};
class MappedAttribute;
class SVGAnimatedBoolean;
+ // FIXME: This is wrong for several reasons:
+ // 1. externalResourcesRequired is not animateable according to SVG 1.1 section 5.9
+ // 2. externalResourcesRequired should just be part of SVGElement, and default to "false" for all elements
+ /*
+ SPEC: Note that the SVG DOM
+ defines the attribute externalResourcesRequired as being of type SVGAnimatedBoolean, whereas the
+ SVG language definition says that externalResourcesRequired is not animated. Because the SVG
+ language definition states that externalResourcesRequired cannot be animated, the animVal will
+ always be the same as the baseVal.
+ */
class SVGExternalResourcesRequired {
public:
SVGExternalResourcesRequired();
#include "config.h"
#ifdef SVG_SUPPORT
-#include "DeprecatedStringList.h"
#include "Attr.h"
-#include "StringImpl.h"
-
-#include "SVGNames.h"
-#include "svgpathparser.h"
-#include "SVGRect.h"
-#include "SVGSVGElement.h"
+#include "SVGAnimatedPreserveAspectRatio.h"
#include "SVGAnimatedRect.h"
#include "SVGFitToViewBox.h"
+#include "SVGNames.h"
#include "SVGPreserveAspectRatio.h"
-#include "SVGAnimatedPreserveAspectRatio.h"
+#include "SVGRect.h"
+#include "SVGSVGElement.h"
+#include "StringImpl.h"
+#include "svgpathparser.h"
-using namespace WebCore;
+namespace WebCore {
SVGFitToViewBox::SVGFitToViewBox()
{
{
}
-SVGAnimatedRect *SVGFitToViewBox::viewBox() const
+SVGAnimatedRect* SVGFitToViewBox::viewBox() const
{
- if(!m_viewBox)
- {
+ if (!m_viewBox) {
//const SVGStyledElement *context = dynamic_cast<const SVGStyledElement *>(this);
m_viewBox = new SVGAnimatedRect(0); // FIXME: 0 is a hack
}
return m_viewBox.get();
}
-SVGAnimatedPreserveAspectRatio *SVGFitToViewBox::preserveAspectRatio() const
+SVGAnimatedPreserveAspectRatio* SVGFitToViewBox::preserveAspectRatio() const
{
- if(!m_preserveAspectRatio)
- {
+ if (!m_preserveAspectRatio) {
//const SVGStyledElement *context = dynamic_cast<const SVGStyledElement *>(this);
m_preserveAspectRatio = new SVGAnimatedPreserveAspectRatio(0); // FIXME: 0 is a hack
}
return m_preserveAspectRatio.get();
}
-void SVGFitToViewBox::parseViewBox(StringImpl *str)
+void SVGFitToViewBox::parseViewBox(StringImpl* str)
{
double x = 0, y = 0, w = 0, h = 0;
DeprecatedString viewbox = String(str).deprecatedString();
viewBox()->baseVal()->setHeight(h);
return;
-bail_out:
- fprintf(stderr, "WARNING: Malformed viewbox string: %s (l: %i)", viewbox.ascii(), viewbox.length());
+bail_out:;
+ // FIXME: Per the spec we are supposed to set the document into an "error state" here.
}
-SVGMatrix *SVGFitToViewBox::viewBoxToViewTransform(float viewWidth, float viewHeight) const
+SVGMatrix* SVGFitToViewBox::viewBoxToViewTransform(float viewWidth, float viewHeight) const
{
- SVGRect *viewBoxRect = viewBox()->baseVal();
+ SVGRect* viewBoxRect = viewBox()->baseVal();
if(viewBoxRect->width() == 0 || viewBoxRect->height() == 0)
return SVGSVGElement::createSVGMatrix();
0, 0, viewWidth, viewHeight);
}
-bool SVGFitToViewBox::parseMappedAttribute(MappedAttribute *attr)
+bool SVGFitToViewBox::parseMappedAttribute(MappedAttribute* attr)
{
- if (attr->name() == SVGNames::viewBoxAttr)
- {
+ if (attr->name() == SVGNames::viewBoxAttr) {
parseViewBox(attr->value().impl());
return true;
- }
- else if (attr->name() == SVGNames::preserveAspectRatioAttr)
- {
+ } else if (attr->name() == SVGNames::preserveAspectRatioAttr) {
preserveAspectRatio()->baseVal()->parsePreserveAspectRatio(attr->value().impl());
return true;
}
return false;
}
+}
+
// vim:ts=4:noet
#endif // SVG_SUPPORT
#include "CSSPropertyNames.h"
#include "KCanvasRenderingStyle.h"
#include "RenderSVGImage.h"
+#include "SVGAnimatedBoolean.h"
#include "SVGAnimatedLength.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "SVGAnimatedString.h"
using namespace WebCore;
SVGImageElement::SVGImageElement(const QualifiedName& tagName, Document *doc)
-: SVGStyledTransformableElement(tagName, doc), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGURIReference(), m_imageLoader(this)
+ : SVGStyledTransformableElement(tagName, doc)
+ , SVGTests()
+ , SVGLangSpace()
+ , SVGExternalResourcesRequired()
+ , SVGURIReference()
+ , m_imageLoader(this)
{
}
return new (arena) RenderSVGImage(this);
}
+bool SVGImageElement::haveLoadedRequiredResources()
+{
+ return (!externalResourcesRequired()->baseVal() || m_imageLoader.imageComplete());
+}
+
void SVGImageElement::attach()
{
SVGStyledTransformableElement::attach();
virtual bool rendererIsNeeded(RenderStyle *style) { return StyledElement::rendererIsNeeded(style); }
virtual RenderObject *createRenderer(RenderArena *arena, RenderStyle *style);
+
+ protected:
+ virtual bool haveLoadedRequiredResources();
private:
mutable RefPtr<SVGAnimatedLength> m_x;
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)
+ if (attr->name() == onunloadAttr)
addSVGWindowEventListner(unloadEvent, attr);
else if (attr->name() == onabortAttr)
addSVGWindowEventListner(abortEvent, attr);
#include "config.h"
#ifdef SVG_SUPPORT
#include "PlatformString.h"
-//#include <kdom/ecma/Ecma.h>
#include "Attr.h"
#include "StringImpl.h"
#include "SVGNames.h"
#include "SVGScriptElement.h"
-using namespace WebCore;
+namespace WebCore {
-SVGScriptElement::SVGScriptElement(const QualifiedName& tagName, Document *doc) : SVGElement(tagName, doc), SVGURIReference(), SVGExternalResourcesRequired()
+SVGScriptElement::SVGScriptElement(const QualifiedName& tagName, Document* doc)
+ : SVGElement(tagName, doc)
+ , SVGURIReference()
+ , SVGExternalResourcesRequired()
{
}
{
if (attr->name() == SVGNames::typeAttr)
setType(attr->value().impl());
- else
- {
- if(SVGURIReference::parseMappedAttribute(attr)) return;
- if(SVGExternalResourcesRequired::parseMappedAttribute(attr)) return;
+ else {
+ if(SVGURIReference::parseMappedAttribute(attr))
+ return;
+ if(SVGExternalResourcesRequired::parseMappedAttribute(attr))
+ return;
SVGElement::parseMappedAttribute(attr);
}
// Run script
KJS::Completion comp = ecmaEngine->evaluate(jsCode.deprecatedString(), ecmaEngine->globalObject());
- if(comp.complType() == KJS::Throw)
- {
+ if (comp.complType() == KJS::Throw) {
KJS::ExecState *exec = ecmaEngine->globalExec();
KJS::JSValue *exVal = comp.value();
int lineno = -1;
- if(exVal->isObject())
- {
+ if (exVal->isObject()) {
KJS::JSValue *lineVal = static_cast<KJS::JSObject *>(exVal)->get(exec, "line");
if(lineVal->type() == KJS::NumberType)
lineno = int(lineVal->toNumber(exec));
// Fire ERROR_EVENT upon errors...
SVGDocument *svgDocument = static_cast<SVGDocument *>(document);
- if(svgDocument && document->hasListenerType(ERROR_EVENT))
- {
+ if (svgDocument && document->hasListenerType(ERROR_EVENT)) {
RefPtr<Event> event = svgDocument->createEvent("SVGEvents");
event->initEvent(EventNames::errorEvent, false, false);
svgDocument->dispatchRecursiveEvent(event.get(), svgDocument->lastChild());
#endif
}
+}
+
// vim:ts=4:noet
#endif // SVG_SUPPORT
return;
ExceptionCode ec = 0;
- RefPtr<Event> evt = new Event(khtmlEditableContentChangedEvent, false, false);
- EventTargetNodeCast(root)->dispatchEvent(evt, ec, true);
+ EventTargetNodeCast(root)->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
}
void Frame::appliedEditing(EditCommandPtr& cmd)
--- /dev/null
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "FloatRect.h"
+#include "Image.h"
+#include "ImageAnimationObserver.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+#include "Timer.h"
+#include <wtf/Vector.h>
+
+#if __APPLE__
+// FIXME: Will go away when we make PDF a subclass.
+#include "PDFDocumentImage.h"
+#endif
+
+namespace WebCore {
+
+// ================================================
+// Image Class
+// ================================================
+
+Image::Image()
+: m_currentFrame(0), m_frames(0), m_animationObserver(0),
+ m_frameTimer(0), m_repetitionCount(0), m_repetitionsComplete(0),
+ m_isSolidColor(false), m_animatingImageType(true), m_animationFinished(false),
+ m_haveSize(false), m_sizeAvailable(false)
+{
+ initNativeData();
+}
+
+Image::Image(ImageAnimationObserver* observer, bool isPDF)
+ : m_currentFrame(0), m_frames(0), m_animationObserver(0),
+ m_frameTimer(0), m_repetitionCount(0), m_repetitionsComplete(0),
+ m_isSolidColor(false), m_animatingImageType(true), m_animationFinished(false),
+ m_haveSize(false), m_sizeAvailable(false)
+{
+ initNativeData();
+#if __APPLE__
+ if (isPDF)
+ setIsPDF(); // FIXME: Will go away when we make PDF a subclass.
+#endif
+ m_animationObserver = observer;
+}
+
+Image::~Image()
+{
+ invalidateData();
+ stopAnimation();
+ destroyNativeData();
+}
+
+void Image::invalidateData()
+{
+ // Destroy the cached images and release them.
+ if (m_frames.size()) {
+ m_frames.last().clear();
+ m_isSolidColor = false;
+ invalidateNativeData();
+ }
+}
+
+void Image::cacheFrame(size_t index)
+{
+ size_t numFrames = frameCount();
+ if (!m_frames.size() && shouldAnimate()) {
+ // Snag the repetition count.
+ m_repetitionCount = m_source.repetitionCount();
+ if (m_repetitionCount == cAnimationNone)
+ m_animatingImageType = false;
+ }
+
+ if (m_frames.size() < numFrames)
+ m_frames.resize(numFrames);
+
+ m_frames[index].m_frame = m_source.createFrameAtIndex(index);
+ if (m_frames[index].m_frame)
+ checkForSolidColor();
+
+ if (shouldAnimate())
+ m_frames[index].m_duration = m_source.frameDurationAtIndex(index);
+ m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index);
+}
+
+bool Image::isNull() const
+{
+ return size().isEmpty();
+}
+
+IntSize Image::size() const
+{
+#if __APPLE__
+ // FIXME: Will go away when we make PDF a subclass.
+ if (m_isPDF) {
+ if (m_PDFDoc) {
+ FloatSize size = m_PDFDoc->size();
+ return IntSize((int)size.width(), (int)size.height());
+ }
+ } else
+#endif
+
+ if (m_sizeAvailable && !m_haveSize) {
+ m_size = m_source.size();
+ m_haveSize = true;
+ }
+ return m_size;
+}
+
+bool Image::setData(bool allDataReceived)
+{
+ int length = m_data.size();
+ if (!length)
+ return true;
+
+#ifdef kImageBytesCutoff
+ // This is a hack to help with testing display of partially-loaded images.
+ // To enable it, define kImageBytesCutoff to be a size smaller than that of the image files
+ // being loaded. They'll never finish loading.
+ if (length > kImageBytesCutoff) {
+ length = kImageBytesCutoff;
+ allDataReceived = false;
+ }
+#endif
+
+#if __APPLE__
+ // Avoid the extra copy of bytes by just handing the byte array directly to a CFDataRef.
+ CFDataRef data = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(m_data.data()), length, kCFAllocatorNull);
+ bool result = setNativeData(data, allDataReceived);
+ CFRelease(data);
+#else
+ bool result = setNativeData(&m_data, allDataReceived);
+#endif
+
+ return result;
+}
+
+bool Image::setNativeData(NativeBytePtr data, bool allDataReceived)
+{
+#if __APPLE__
+ // FIXME: Will go away when we make PDF a subclass.
+ if (m_isPDF) {
+ if (allDataReceived && !m_PDFDoc)
+ m_PDFDoc = new PDFDocumentImage(data);
+ return m_PDFDoc;
+ }
+#endif
+
+ invalidateData();
+
+ // Feed all the data we've seen so far to the image decoder.
+ m_source.setData(data, allDataReceived);
+
+ // Image properties will not be available until the first frame of the file
+ // reaches kCGImageStatusIncomplete.
+ return isSizeAvailable();
+}
+
+size_t Image::frameCount()
+{
+ return m_source.frameCount();
+}
+
+bool Image::isSizeAvailable()
+{
+ if (m_sizeAvailable)
+ return true;
+
+ m_sizeAvailable = m_source.isSizeAvailable();
+
+ return m_sizeAvailable;
+
+}
+
+NativeImagePtr Image::frameAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ if (index >= m_frames.size() || !m_frames[index].m_frame)
+ cacheFrame(index);
+
+ return m_frames[index].m_frame;
+}
+
+float Image::frameDurationAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ if (index >= m_frames.size() || !m_frames[index].m_frame)
+ cacheFrame(index);
+
+ return m_frames[index].m_duration;
+}
+
+bool Image::frameHasAlphaAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ if (index >= m_frames.size() || !m_frames[index].m_frame)
+ cacheFrame(index);
+
+ return m_frames[index].m_hasAlpha;
+}
+
+bool Image::shouldAnimate()
+{
+ return (m_animatingImageType && frameCount() > 1 && !m_animationFinished && m_animationObserver);
+}
+
+void Image::startAnimation()
+{
+ if (m_frameTimer || !shouldAnimate())
+ return;
+
+ m_frameTimer = new Timer<Image>(this, &Image::advanceAnimation);
+ m_frameTimer->startOneShot(frameDurationAtIndex(m_currentFrame));
+}
+
+void Image::stopAnimation()
+{
+ // This timer is used to animate all occurrences of this image. Don't invalidate
+ // the timer unless all renderers have stopped drawing.
+ delete m_frameTimer;
+ m_frameTimer = 0;
+}
+
+void Image::resetAnimation()
+{
+ stopAnimation();
+ m_currentFrame = 0;
+ m_repetitionsComplete = 0;
+ m_animationFinished = false;
+}
+
+
+void Image::advanceAnimation(Timer<Image>* timer)
+{
+ // Stop the animation.
+ stopAnimation();
+
+ // See if anyone is still paying attention to this animation. If not, we don't
+ // advance and will simply pause the animation.
+ if (animationObserver()->shouldStopAnimation(this))
+ return;
+
+ m_currentFrame++;
+ if (m_currentFrame >= frameCount()) {
+ m_repetitionsComplete += 1;
+ if (m_repetitionCount && m_repetitionsComplete >= m_repetitionCount) {
+ m_animationFinished = false;
+ m_currentFrame--;
+ return;
+ }
+ m_currentFrame = 0;
+ }
+
+ // Notify our observer that the animation has advanced.
+ animationObserver()->animationAdvanced(this);
+
+ // Kick off a timer to move to the next frame.
+ m_frameTimer = new Timer<Image>(this, &Image::advanceAnimation);
+ m_frameTimer->startOneShot(frameDurationAtIndex(m_currentFrame));
+}
+
+IntRect Image::rect() const
+{
+ return IntRect(IntPoint(), size());
+}
+
+int Image::width() const
+{
+ return size().width();
+}
+
+int Image::height() const
+{
+ return size().height();
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IMAGE_H_
+#define IMAGE_H_
+
+#include "Color.h"
+#include "GraphicsTypes.h"
+#include "ImageSource.h"
+#include "IntSize.h"
+#include "FloatSize.h"
+
+#if __APPLE__
+#ifdef __OBJC__
+@class NSImage;
+#else
+class NSImage;
+#endif
+#endif
+
+namespace WebCore {
+ struct FrameData;
+}
+
+// This complicated-looking declaration tells the framedata Vector that it can copy without
+// having to invoke our copy constructor. This allows us to not have to worry about ref counting
+// the native frames.
+namespace WTF {
+ template<> class VectorTraits<WebCore::FrameData> : public SimpleClassVectorTraits {};
+}
+
+namespace WebCore {
+
+class FloatPoint;
+class FloatRect;
+class GraphicsContext;
+class IntRect;
+class IntSize;
+class PDFDocumentImage;
+class String;
+
+template <typename T> class Timer;
+
+// This class gets notified when an image advances animation frames.
+class ImageAnimationObserver;
+
+// ================================================
+// FrameData Class
+// ================================================
+
+struct FrameData {
+ FrameData()
+ :m_frame(0), m_duration(0), m_hasAlpha(true)
+ {}
+
+ ~FrameData()
+ {
+ clear();
+ }
+
+ void clear();
+
+ NativeImagePtr m_frame;
+ float m_duration;
+ bool m_hasAlpha;
+};
+
+// =================================================
+// Image Class
+// =================================================
+
+class Image : Noncopyable {
+ friend class GraphicsContext;
+public:
+ Image();
+ Image(ImageAnimationObserver* observer, bool isPDF = false);
+ ~Image();
+
+ static Image* loadResource(const char *name);
+ static bool supportsType(const String& type);
+
+ bool isNull() const;
+
+ IntSize size() const;
+ IntRect rect() const;
+ int width() const;
+ int height() const;
+
+ bool setData(bool allDataReceived);
+ bool setNativeData(NativeBytePtr, bool allDataReceived);
+
+ Vector<char>& dataBuffer() { return m_data; }
+
+ // It may look unusual that there is no start animation call as public API. This is because
+ // we start and stop animating lazily. Animation begins whenever someone draws the image. It will
+ // automatically pause once all observers no longer want to render the image anywhere.
+ void stopAnimation();
+ void resetAnimation();
+
+ // Frame accessors.
+ size_t currentFrame() const { return m_currentFrame; }
+ size_t frameCount();
+ NativeImagePtr frameAtIndex(size_t index);
+ float frameDurationAtIndex(size_t index);
+ bool frameHasAlphaAtIndex(size_t index);
+
+ // Typically the CachedImage that owns us.
+ ImageAnimationObserver* animationObserver() const { return m_animationObserver; }
+
+ enum TileRule { StretchTile, RoundTile, RepeatTile };
+
+#if __APPLE__
+ // Accessors for native image formats.
+ CGImageRef getCGImageRef();
+ NSImage* getNSImage();
+ CFDataRef getTIFFRepresentation();
+
+ // PDF
+ void setIsPDF() { m_isPDF = true; }
+#endif
+
+private:
+ void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator);
+ void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize,
+ CompositeOperator);
+ void drawTiled(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule, TileRule vRule,
+ CompositeOperator);
+
+ // Decodes and caches a frame. Never accessed except internally.
+ void cacheFrame(size_t index);
+
+ // Called to invalidate all our cached data when more bytes are available.
+ void invalidateData();
+
+ // Whether or not size is available yet.
+ bool isSizeAvailable();
+
+ // Animation.
+ bool shouldAnimate();
+ void startAnimation();
+ void advanceAnimation(Timer<Image>* timer);
+
+ // Constructor for native data.
+ void initNativeData();
+
+ // Destructor for native data.
+ void destroyNativeData();
+
+ // Invalidation of native data.
+ void invalidateNativeData();
+
+ // Checks to see if the image is a 1x1 solid color. We optimize these images and just do a fill rect instead.
+ void checkForSolidColor();
+
+ // Members
+ Vector<char> m_data; // The encoded raw data for the image.
+ ImageSource m_source;
+ mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image).
+
+ size_t m_currentFrame; // The index of the current frame of animation.
+ Vector<FrameData> m_frames; // An array of the cached frames of the animation. We have to ref frames to pin them in the cache.
+
+ // Our animation observer.
+ ImageAnimationObserver* m_animationObserver;
+ Timer<Image>* m_frameTimer;
+ int m_repetitionCount; // How many total animation loops we should do.
+ int m_repetitionsComplete; // How many repetitions we've finished.
+
+#if __APPLE__
+ mutable NSImage* m_nsImage; // A cached NSImage of frame 0. Only built lazily if someone actually queries for one.
+ mutable CFDataRef m_tiffRep; // Cached TIFF rep for frame 0. Only built lazily if someone queries for one.
+ PDFDocumentImage* m_PDFDoc;
+ bool m_isPDF;
+#endif
+
+ Color m_solidColor; // If we're a 1x1 solid color, this is the color to use to fill.
+ bool m_isSolidColor; // Whether or not we are a 1x1 solid image.
+
+ bool m_animatingImageType; // Whether or not we're an image type that is capable of animating (GIF).
+ bool m_animationFinished; // Whether or not we've completed the entire animation.
+
+ mutable bool m_haveSize; // Whether or not our |m_size| member variable has the final overall image size yet.
+ bool m_sizeAvailable; // Whether or not we can obtain the size of the first image frame yet from ImageIO.
+};
+
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "Image.h"
+
+#import "FloatRect.h"
+#import "FoundationExtras.h"
+#import "GraphicsContext.h"
+#import "PDFDocumentImage.h"
+#import "PlatformString.h"
+#import "WebCoreFrameBridge.h"
+#import "WebCoreSystemInterface.h"
+
+namespace WebCore {
+
+void FrameData::clear()
+{
+ if (m_frame) {
+ CFRelease(m_frame);
+ m_frame = 0;
+ m_duration = 0.;
+ m_hasAlpha = true;
+ }
+}
+
+// ================================================
+// Image Class
+// ================================================
+
+void Image::initNativeData()
+{
+ m_nsImage = 0;
+ m_tiffRep = 0;
+ m_isPDF = false;
+ m_PDFDoc = 0;
+}
+
+void Image::destroyNativeData()
+{
+ delete m_PDFDoc;
+}
+
+void Image::invalidateNativeData()
+{
+ if (m_frames.size() != 1)
+ return;
+
+ if (m_nsImage) {
+ CFRelease(m_nsImage);
+ m_nsImage = 0;
+ }
+
+ if (m_tiffRep) {
+ CFRelease(m_tiffRep);
+ m_tiffRep = 0;
+ }
+}
+
+Image* Image::loadResource(const char *name)
+{
+ NSBundle *bundle = [NSBundle bundleForClass:[WebCoreFrameBridge class]];
+ NSString *imagePath = [bundle pathForResource:[NSString stringWithUTF8String:name] ofType:@"tiff"];
+ NSData *namedImageData = [NSData dataWithContentsOfFile:imagePath];
+ if (namedImageData) {
+ Image* image = new Image;
+ image->setNativeData((CFDataRef)namedImageData, true);
+ return image;
+ }
+ return 0;
+}
+
+bool Image::supportsType(const String& type)
+{
+ // FIXME: Would be better if this was looking in a set rather than an NSArray.
+ // FIXME: Would be better not to convert to an NSString just to check if a type is supported.
+ return [[WebCoreFrameBridge supportedImageResourceMIMETypes] containsObject:type];
+}
+
+// Drawing Routines
+
+void Image::checkForSolidColor()
+{
+ if (frameCount() > 1)
+ m_isSolidColor = false;
+ else {
+ CGImageRef image = frameAtIndex(0);
+
+ // Currently we only check for solid color in the important special case of a 1x1 image.
+ if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) {
+ CGFloat pixel[4]; // RGBA
+ CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
+ CGContextRef bmap = CGBitmapContextCreate(&pixel, 1, 1, 8*sizeof(float), sizeof(pixel), space,
+ kCGImageAlphaPremultipliedLast | kCGBitmapFloatComponents | kCGBitmapByteOrder32Host);
+ if (bmap) {
+ GraphicsContext(bmap).setCompositeOperation(CompositeCopy);
+ CGRect dst = { {0, 0}, {1, 1} };
+ CGContextDrawImage(bmap, dst, image);
+ if (pixel[3] == 0)
+ m_solidColor = Color(0, 0, 0, 0);
+ else
+ m_solidColor = Color(int(pixel[0] / pixel[3] * 255), int(pixel[1] / pixel[3] * 255), int(pixel[2] / pixel[3] * 255), int(pixel[3] * 255));
+ m_isSolidColor = true;
+ CFRelease(bmap);
+ }
+ CFRelease(space);
+ }
+ }
+}
+
+CFDataRef Image::getTIFFRepresentation()
+{
+ if (m_tiffRep)
+ return m_tiffRep;
+
+ unsigned numFrames = frameCount();
+ CFMutableDataRef data = CFDataCreateMutable(0, 0);
+ // FIXME: Use type kCGImageTypeIdentifierTIFF constant once is becomes available in the API
+ CGImageDestinationRef destination = CGImageDestinationCreateWithData(data, CFSTR("public.tiff"), numFrames, 0);
+ if (!destination)
+ return 0;
+
+ for (unsigned i = 0; i < numFrames; ++i ) {
+ CGImageRef cgImage = frameAtIndex(i);
+ if (!cgImage) {
+ CFRelease(destination);
+ return 0;
+ }
+ CGImageDestinationAddImage(destination, cgImage, 0);
+ }
+ CGImageDestinationFinalize(destination);
+ CFRelease(destination);
+
+ m_tiffRep = data;
+ return m_tiffRep;
+}
+
+NSImage* Image::getNSImage()
+{
+ if (m_nsImage)
+ return m_nsImage;
+
+ CFDataRef data = getTIFFRepresentation();
+ if (!data)
+ return 0;
+
+ m_nsImage = HardRetainWithNSRelease([[NSImage alloc] initWithData:(NSData*)data]);
+ return m_nsImage;
+}
+
+CGImageRef Image::getCGImageRef()
+{
+ return frameAtIndex(0);
+}
+
+void Image::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp)
+{
+ if (m_isPDF) {
+ if (m_PDFDoc)
+ m_PDFDoc->draw(ctxt, srcRect, dstRect, compositeOp);
+ return;
+ }
+
+ if (!m_source.initialized())
+ return;
+
+ CGRect fr = ctxt->roundToDevicePixels(srcRect);
+ CGRect ir = ctxt->roundToDevicePixels(dstRect);
+
+ CGImageRef image = frameAtIndex(m_currentFrame);
+ if (!image) // If it's too early we won't have an image yet.
+ return;
+
+ if (m_isSolidColor && m_currentFrame == 0) {
+ if (m_solidColor.alpha() > 0) {
+ ctxt->save();
+ ctxt->setCompositeOperation(!m_solidColor.hasAlpha() && compositeOp == CompositeSourceOver ? CompositeCopy : compositeOp);
+ ctxt->fillRect(ir, m_solidColor);
+ ctxt->restore();
+ }
+ return;
+ }
+
+ CGContextRef context = ctxt->platformContext();
+ ctxt->save();
+
+ // Get the height (in adjusted, i.e. scaled, coords) of the portion of the image
+ // that is currently decoded. This could be less that the actual height.
+ CGSize selfSize = size(); // full image size, in pixels
+ float curHeight = CGImageGetHeight(image); // height of loaded portion, in pixels
+
+ CGSize adjustedSize = selfSize;
+ if (curHeight < selfSize.height) {
+ adjustedSize.height *= curHeight / selfSize.height;
+
+ // Is the amount of available bands less than what we need to draw? If so,
+ // we may have to clip 'fr' if it goes outside the available bounds.
+ if (CGRectGetMaxY(fr) > adjustedSize.height) {
+ float frHeight = adjustedSize.height - fr.origin.y; // clip fr to available bounds
+ if (frHeight <= 0)
+ return; // clipped out entirely
+ ir.size.height *= (frHeight / fr.size.height); // scale ir proportionally to fr
+ fr.size.height = frHeight;
+ }
+ }
+
+ // Flip the coords.
+ ctxt->setCompositeOperation(compositeOp);
+ CGContextTranslateCTM(context, ir.origin.x, ir.origin.y);
+ CGContextScaleCTM(context, 1, -1);
+ CGContextTranslateCTM(context, 0, -ir.size.height);
+
+ // Translated to origin, now draw at 0,0.
+ ir.origin.x = ir.origin.y = 0;
+
+ // If we're drawing a sub portion of the image then create
+ // a image for the sub portion and draw that.
+ // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ if (fr.size.width != adjustedSize.width || fr.size.height != adjustedSize.height) {
+ // Convert ft to image pixel coords:
+ float xscale = adjustedSize.width / selfSize.width;
+ float yscale = adjustedSize.height / curHeight; // yes, curHeight, not selfSize.height!
+ fr.origin.x /= xscale;
+ fr.origin.y /= yscale;
+ fr.size.width /= xscale;
+ fr.size.height /= yscale;
+
+ image = CGImageCreateWithImageInRect(image, fr);
+ if (image) {
+ CGContextDrawImage(context, ir, image);
+ CFRelease(image);
+ }
+ } else // Draw the whole image.
+ CGContextDrawImage(context, ir, image);
+
+ ctxt->restore();
+
+ startAnimation();
+
+}
+
+static void drawPattern(void* info, CGContextRef context)
+{
+ Image* data = (Image*)info;
+ CGImageRef image = data->frameAtIndex(data->currentFrame());
+ float w = CGImageGetWidth(image);
+ float h = CGImageGetHeight(image);
+ CGContextDrawImage(context, GraphicsContext(context).roundToDevicePixels(FloatRect
+ (0, data->size().height() - h, w, h)), image);
+}
+
+static const CGPatternCallbacks patternCallbacks = { 0, drawPattern, NULL };
+
+void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const FloatPoint& srcPoint,
+ const FloatSize& tileSize, CompositeOperator op)
+{
+ CGImageRef image = frameAtIndex(m_currentFrame);
+ if (!image)
+ return;
+
+ if (m_isSolidColor && m_currentFrame == 0) {
+ if (m_solidColor.alpha() > 0) {
+ ctxt->save();
+ ctxt->setCompositeOperation(!m_solidColor.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op);
+ ctxt->fillRect(destRect, m_solidColor);
+ ctxt->restore();
+ }
+ return;
+ }
+
+ CGPoint scaledPoint = srcPoint;
+ CGSize intrinsicTileSize = size();
+ CGSize scaledTileSize = intrinsicTileSize;
+
+ // If tileSize is not equal to the intrinsic size of the image, set patternTransform
+ // to the appropriate scalar matrix, scale the source point, and set the size of the
+ // scaled tile.
+ float scaleX = 1.0;
+ float scaleY = 1.0;
+ CGAffineTransform patternTransform = CGAffineTransformIdentity;
+ if (tileSize.width() != intrinsicTileSize.width || tileSize.height() != intrinsicTileSize.height) {
+ scaleX = tileSize.width() / intrinsicTileSize.width;
+ scaleY = tileSize.height() / intrinsicTileSize.height;
+ patternTransform = CGAffineTransformMakeScale(scaleX, scaleY);
+ scaledTileSize = tileSize;
+ }
+
+ // Check and see if a single draw of the image can cover the entire area we are supposed to tile.
+ NSRect oneTileRect;
+ oneTileRect.origin.x = destRect.x() + fmodf(fmodf(-scaledPoint.x, scaledTileSize.width) -
+ scaledTileSize.width, scaledTileSize.width);
+ oneTileRect.origin.y = destRect.y() + fmodf(fmodf(-scaledPoint.y, scaledTileSize.height) -
+ scaledTileSize.height, scaledTileSize.height);
+ oneTileRect.size.width = scaledTileSize.width;
+ oneTileRect.size.height = scaledTileSize.height;
+
+ // If the single image draw covers the whole area, then just draw once.
+ if (NSContainsRect(oneTileRect, destRect)) {
+ CGRect fromRect;
+ fromRect.origin.x = (destRect.x() - oneTileRect.origin.x) / scaleX;
+ fromRect.origin.y = (destRect.y() - oneTileRect.origin.y) / scaleY;
+ fromRect.size.width = destRect.width() / scaleX;
+ fromRect.size.height = destRect.height() / scaleY;
+
+ draw(ctxt, destRect, fromRect, op);
+ return;
+ }
+
+ CGPatternRef pattern = CGPatternCreate(this, CGRectMake(0, 0, intrinsicTileSize.width, intrinsicTileSize.height),
+ patternTransform, intrinsicTileSize.width, intrinsicTileSize.height,
+ kCGPatternTilingConstantSpacing, true, &patternCallbacks);
+
+ if (pattern) {
+ CGContextRef context = ctxt->platformContext();
+
+ ctxt->save();
+
+ wkSetPatternPhaseInUserSpace(context, CGPointMake(oneTileRect.origin.x, oneTileRect.origin.y));
+
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
+ CGContextSetFillColorSpace(context, patternSpace);
+ CGColorSpaceRelease(patternSpace);
+
+ CGFloat patternAlpha = 1;
+ CGContextSetFillPattern(context, pattern, &patternAlpha);
+
+ ctxt->setCompositeOperation(op);
+
+ CGContextFillRect(context, destRect);
+
+ ctxt->restore();
+
+ CGPatternRelease(pattern);
+ }
+
+ startAnimation();
+}
+
+// FIXME: Merge with the other drawTiled eventually, since we need a combination of both for some things.
+void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, TileRule hRule,
+ TileRule vRule, CompositeOperator op)
+{
+ CGImageRef image = frameAtIndex(m_currentFrame);
+ if (!image)
+ return;
+
+ if (m_isSolidColor && m_currentFrame == 0) {
+ if (m_solidColor.alpha() > 0) {
+ ctxt->save();
+ ctxt->setCompositeOperation(!m_solidColor.hasAlpha() && op == CompositeSourceOver ? CompositeCopy : op);
+ ctxt->fillRect(dstRect, m_solidColor);
+ ctxt->restore();
+ }
+ return;
+ }
+
+ ctxt->save();
+
+ CGSize tileSize = srcRect.size();
+ CGRect ir = dstRect;
+ CGRect fr = srcRect;
+
+ // Now scale the slice in the appropriate direction using an affine transform that we will pass into
+ // the pattern.
+ float scaleX = 1.0f, scaleY = 1.0f;
+
+ if (hRule == Image::StretchTile)
+ scaleX = ir.size.width / fr.size.width;
+ if (vRule == Image::StretchTile)
+ scaleY = ir.size.height / fr.size.height;
+
+ if (hRule == Image::RepeatTile)
+ scaleX = scaleY;
+ if (vRule == Image::RepeatTile)
+ scaleY = scaleX;
+
+ if (hRule == Image::RoundTile) {
+ // Complicated math ensues.
+ float imageWidth = fr.size.width * scaleY;
+ float newWidth = ir.size.width / ceilf(ir.size.width / imageWidth);
+ scaleX = newWidth / fr.size.width;
+ }
+
+ if (vRule == Image::RoundTile) {
+ // More complicated math ensues.
+ float imageHeight = fr.size.height * scaleX;
+ float newHeight = ir.size.height / ceilf(ir.size.height / imageHeight);
+ scaleY = newHeight / fr.size.height;
+ }
+
+ CGAffineTransform patternTransform = CGAffineTransformMakeScale(scaleX, scaleY);
+
+ // Possible optimization: We may want to cache the CGPatternRef
+ CGPatternRef pattern = CGPatternCreate(this, CGRectMake(fr.origin.x, fr.origin.y, tileSize.width, tileSize.height),
+ patternTransform, tileSize.width, tileSize.height,
+ kCGPatternTilingConstantSpacing, true, &patternCallbacks);
+ if (pattern) {
+ CGContextRef context = ctxt->platformContext();
+
+ // We want to construct the phase such that the pattern is centered (when stretch is not
+ // set for a particular rule).
+ float hPhase = scaleX * fr.origin.x;
+ float vPhase = scaleY * (tileSize.height - fr.origin.y);
+ if (hRule == Image::RepeatTile)
+ hPhase -= fmodf(ir.size.width, scaleX * tileSize.width) / 2.0f;
+ if (vRule == Image::RepeatTile)
+ vPhase -= fmodf(ir.size.height, scaleY * tileSize.height) / 2.0f;
+
+ wkSetPatternPhaseInUserSpace(context, CGPointMake(ir.origin.x - hPhase, ir.origin.y - vPhase));
+
+ CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
+ CGContextSetFillColorSpace(context, patternSpace);
+ CGColorSpaceRelease(patternSpace);
+
+ CGFloat patternAlpha = 1;
+ CGContextSetFillPattern(context, pattern, &patternAlpha);
+
+ ctxt->setCompositeOperation(op);
+
+ CGContextFillRect(context, ir);
+
+ CGPatternRelease(pattern);
+ }
+
+ ctxt->restore();
+
+ startAnimation();
+}
+
+}
void XMLHttpRequest::callReadyStateChangeListener()
{
- if (m_doc && m_doc->frame() && m_onReadyStateChangeListener) {
- ExceptionCode ec;
- RefPtr<Event> ev = m_doc->createEvent("HTMLEvents", ec);
- ev->initEvent(readystatechangeEvent, true, true);
- m_onReadyStateChangeListener->handleEvent(ev.get(), true);
- }
+ if (m_doc && m_doc->frame() && m_onReadyStateChangeListener)
+ m_onReadyStateChangeListener->handleEvent(new Event(readystatechangeEvent, true, true), true);
- if (m_doc && m_doc->frame() && m_state == Completed && m_onLoadListener) {
- ExceptionCode ec;
- RefPtr<Event> ev = m_doc->createEvent("HTMLEvents", ec);
- ev->initEvent(loadEvent, true, true);
- m_onLoadListener->handleEvent(ev.get(), true);
- }
+ if (m_doc && m_doc->frame() && m_state == Completed && m_onLoadListener)
+ m_onLoadListener->handleEvent(new Event(loadEvent, true, true), true);
}
bool XMLHttpRequest::urlMatchesDocumentDomain(const KURL& url) const