Bug #: 4155
authoreseidel <eseidel@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 29 Jul 2005 20:22:51 +0000 (20:22 +0000)
committereseidel <eseidel@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 29 Jul 2005 20:22:51 +0000 (20:22 +0000)
Submitted by: eseidel
Reviewed by: sullivan
        * WebCore+SVG/DrawCanvasItem.h: Added.
        * WebCore+SVG/DrawCanvasItem.mm: Added.
        * WebCore+SVG/DrawCanvasItemPrivate.h: Added.
        * WebCore+SVG/DrawDocument.h: Added.
        * WebCore+SVG/DrawDocument.mm: Added.
        * WebCore+SVG/DrawDocumentPrivate.h: Added.
        * WebCore+SVG/DrawView.h: Added.
        * WebCore+SVG/DrawView.mm: Added.
        * WebCore+SVG/DrawViewPrivate.h: Added.
        * WebCore+SVG/NSSVGImageRep.h: Added.
        * WebCore+SVG/NSSVGImageRep.m: Added.
        Temporary SPI to make it possible to write Obj-C test applications.
        http://bugzilla.opendarwin.org/show_bug.cgi?id=4155

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@9948 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
WebCore/ChangeLog-2005-08-23
WebCore/WebCore+SVG/DrawCanvasItem.h [new file with mode: 0644]
WebCore/WebCore+SVG/DrawCanvasItem.mm [new file with mode: 0644]
WebCore/WebCore+SVG/DrawCanvasItemPrivate.h [new file with mode: 0644]
WebCore/WebCore+SVG/DrawDocument.h [new file with mode: 0644]
WebCore/WebCore+SVG/DrawDocument.mm [new file with mode: 0644]
WebCore/WebCore+SVG/DrawDocumentPrivate.h [new file with mode: 0644]
WebCore/WebCore+SVG/DrawView.h [new file with mode: 0644]
WebCore/WebCore+SVG/DrawView.mm [new file with mode: 0644]
WebCore/WebCore+SVG/DrawViewPrivate.h [new file with mode: 0644]
WebCore/WebCore+SVG/NSSVGImageRep.h [new file with mode: 0644]
WebCore/WebCore+SVG/NSSVGImageRep.m [new file with mode: 0644]

index d5530bb38d4ef6d74e877bcc152382836c057e8e..90e27349c489e094ad8a929c63a751c5cd93ca43 100644 (file)
@@ -1,3 +1,21 @@
+2005-07-29  Eric Seidel  <eseidel@apple.com>
+
+        Reviewed by sullivan.
+
+        * WebCore+SVG/DrawCanvasItem.h: Added.
+        * WebCore+SVG/DrawCanvasItem.mm: Added.
+        * WebCore+SVG/DrawCanvasItemPrivate.h: Added.
+        * WebCore+SVG/DrawDocument.h: Added.
+        * WebCore+SVG/DrawDocument.mm: Added.
+        * WebCore+SVG/DrawDocumentPrivate.h: Added.
+        * WebCore+SVG/DrawView.h: Added.
+        * WebCore+SVG/DrawView.mm: Added.
+        * WebCore+SVG/DrawViewPrivate.h: Added.
+        * WebCore+SVG/NSSVGImageRep.h: Added.
+        * WebCore+SVG/NSSVGImageRep.m: Added.
+        Temporary SPI to make it possible to write Obj-C test applications.
+        http://bugzilla.opendarwin.org/show_bug.cgi?id=4155
+
 2005-07-29  Justin Garcia  <justin.garcia@apple.com>
 
         Reviewed by harrison
diff --git a/WebCore/WebCore+SVG/DrawCanvasItem.h b/WebCore/WebCore+SVG/DrawCanvasItem.h
new file mode 100644 (file)
index 0000000..c8f4af8
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2005 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. 
+ */
+
+/*
+ WARNING: These files are temporary and exist solely for the purpose
+ of allowing greater testing of WebCore+SVG prior to full DOM integration.
+ Do NOT depend on these SPIs or files as they will soon be gone.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+/*
+ This is an Obj-C wrapper object for KCanvasItem
+ This exists mostly because we don't have Obj-C
+ bindings for the SVG DOM yet.
+
+ In a real editor, you would not want to make changes to only the render
+ tree, but rather to the DOM directly, and let the engine automatically
+ reflect those in the render tree.
+*/
+
+@class DrawCanvasItemPrivate;
+
+@interface DrawCanvasItem : NSObject {
+    DrawCanvasItemPrivate *_private;
+}
+
+// convenience
++ (NSArray *)controlPointsForRect:(NSRect)bbox;
++ (NSPoint)dragAnchorPointForControlPointIndex:(int)controlPointIndex fromRectControlPoints:(NSArray *)controlPoints;
+
+/*
+   These were all originally intended to allow more than just the four corner
+   knobs to be displayed for selection, editing, but are not finished, and
+   instead always return the 4 corner points for any shape, path, etc.
+   Why? A classic example is a curved path, where you don't just want 4 selection
+   nobs, but rather ones along the path, possibly for curve control points, etc.
+*/
+- (NSPoint)dragAnchorPointForControlPointIndex:(int)controlPointIndex;
+- (NSArray *)controlPoints;
+- (NSRect)boundingBox;
+
+// used for moving objects
+- (void)translateByOffset:(NSSize)offset;
+- (void)resizeWithPoint:(NSPoint)canvasPoint usingControlPoint:(int)controlPointIndex dragAnchorPoint:(NSPoint)canvasDragAnchorPoint;
+
+- (unsigned int)zIndex;
+- (void)raise;
+- (void)lower;
+
+@end
diff --git a/WebCore/WebCore+SVG/DrawCanvasItem.mm b/WebCore/WebCore+SVG/DrawCanvasItem.mm
new file mode 100644 (file)
index 0000000..4822810
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2005 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 "DrawCanvasItemPrivate.h"
+
+#import <kcanvas/KCanvas.h>
+#import <kcanvas/KCanvasItem.h>
+
+#import <kdom/Namespace.h>
+#import <kdom/Helper.h>
+
+#import <ksvg2/impl/SVGStyledElementImpl.h>
+#import <ksvg2/impl/SVGEllipseElementImpl.h>
+#import <ksvg2/impl/SVGRectElementImpl.h>
+#import <ksvg2/impl/SVGPathElementImpl.h>
+
+@interface DrawCanvasItemPrivate : NSObject {
+    @public
+    KCanvasItem *item; // this is likely dangerous...
+}
+@end 
+
+@implementation DrawCanvasItemPrivate
+@end
+
+@implementation DrawCanvasItem
+
++ (id)canvasItemForItem:(KCanvasItem *)canvasItem
+{
+    return [[[self alloc] initWithItem:canvasItem] autorelease];
+}
+
+- (id)initWithItem:(KCanvasItem *)canvasItem
+{
+    if ((self = [super init])) {
+        _private = [[DrawCanvasItemPrivate alloc] init];
+        _private->item = canvasItem;
+    }
+    return self;
+}
+
+- (KCanvasItem *)item
+{
+    return _private->item;
+}
+
+- (NSRect)boundingBox
+{
+    return NSRect(_private->item->bbox());
+}
+
+- (unsigned int)zIndex
+{
+    return _private->item->zIndex();
+}
+
+- (void)raise
+{
+    _private->item->raise();
+}
+
+- (void)lower
+{
+    _private->item->lower();
+}
+
+// see note in header.
++ (NSPoint)dragAnchorPointForControlPointIndex:(int)controlPointIndex fromRectControlPoints:(NSArray *)controlPoints{
+    int anchorPointIndex = (controlPointIndex + 2) % 4; // the anchor point is the opposite corner.
+    NSPoint anchorPoint = [[controlPoints objectAtIndex:anchorPointIndex] pointValue];
+    return anchorPoint;
+}
+
+// see note in header.
+- (NSPoint)dragAnchorPointForControlPointIndex:(int)controlPointIndex
+{
+    KDOM::NodeImpl *node = (KDOM::NodeImpl *)_private->item->userData();
+    int localId = node->localId();
+    NSPoint dragAnchorPoint;
+    
+    switch (localId) {
+       case ID_PATH:
+            //KSVG::SVGPathElementImpl *path = (KSVG::SVGPathElementImpl *)node;
+       default:
+            // if we have no special knob list, grab the default
+            dragAnchorPoint = [DrawCanvasItem dragAnchorPointForControlPointIndex:controlPointIndex
+                                                            fromRectControlPoints:[self controlPoints]];
+            
+    }
+    return dragAnchorPoint;
+}
+
+// see note in header.
++ (NSArray *)controlPointsForRect:(NSRect)bbox
+{
+    return [NSArray arrayWithObjects:
+        [NSValue valueWithPoint:NSMakePoint(NSMinX(bbox), NSMinY(bbox))],
+        [NSValue valueWithPoint:NSMakePoint(NSMinX(bbox), NSMaxY(bbox))],
+        [NSValue valueWithPoint:NSMakePoint(NSMaxX(bbox), NSMaxY(bbox))],
+        [NSValue valueWithPoint:NSMakePoint(NSMaxX(bbox), NSMinY(bbox))],
+        nil];
+}
+
+// see note in header.
+- (NSArray *)controlPoints
+{      
+    KDOM::NodeImpl *node = (KDOM::NodeImpl *)_private->item->userData();
+    int localId = node->localId();
+    NSArray *controlPoints = nil;
+    
+    switch (localId) {
+        case ID_PATH:
+            //KSVG::SVGPathElementImpl *path = (KSVG::SVGPathElementImpl *)node;
+        default:
+            // if we have no special knob list, grab the default
+            controlPoints = [DrawCanvasItem controlPointsForRect:[self boundingBox]];
+    }
+    return controlPoints;
+}
+
+- (void)fitToNewBBox:(NSRect)newRect
+{
+    [self willChangeValueForKey:@"boundingBox"];
+    [self willChangeValueForKey:@"attributedXMLString"];
+    //NSLog(@"Fitting canvasItem: %p from: %@ into new bbox: %@",
+    // self, NSStringFromRect([self boundingBox]), NSStringFromRect(newRect));
+    KDOM::NodeImpl *node = (KDOM::NodeImpl *)_private->item->userData();
+    int localId = node->localId();
+    switch (localId) {
+       case ID_ELLIPSE:
+       {
+            KSVG::SVGEllipseElementImpl *ellipse = (KSVG::SVGEllipseElementImpl *)node;
+            ellipse->setAttributeNS(KDOM::NS_SVG, "cx", QString::number(newRect.origin.x + newRect.size.width/2.f));
+            ellipse->setAttributeNS(KDOM::NS_SVG, "cy", QString::number(newRect.origin.y + newRect.size.height/2.f));
+            ellipse->setAttributeNS(KDOM::NS_SVG, "rx", QString::number(newRect.size.width/2.f));
+            ellipse->setAttributeNS(KDOM::NS_SVG, "ry", QString::number(newRect.size.height/2.f));
+            break;
+       }
+       case ID_RECT:
+       {
+            KSVG::SVGRectElementImpl *rect = (KSVG::SVGRectElementImpl *)node;
+            rect->setAttributeNS(KDOM::NS_SVG, "x", QString::number(newRect.origin.x));
+            rect->setAttributeNS(KDOM::NS_SVG, "y", QString::number(newRect.origin.y));
+            rect->setAttributeNS(KDOM::NS_SVG, "width", QString::number(newRect.size.width - 1));
+            rect->setAttributeNS(KDOM::NS_SVG, "height", QString::number(newRect.size.height - 1));
+            break;
+       }
+       default:
+            NSLog(@"Id not handled: %i", localId);
+    }
+    [self didChangeValueForKey:@"boundingBox"];
+    [self didChangeValueForKey:@"attributedXMLString"];
+}
+
+- (void)translateByOffset:(NSSize)offset
+{
+    NSRect newRect = [self boundingBox];
+    newRect.origin.x += offset.width + 1; // HACK
+    newRect.origin.y += offset.height + 1;
+    [self fitToNewBBox:newRect];
+}
+
+- (void)resizeWithPoint:(NSPoint)canvasPoint usingControlPoint:(int)controlPointIndex dragAnchorPoint:(NSPoint)canvasDragAnchorPoint{
+    // The controlPointIndex can be used for paths, etc.
+    NSRect newRect;
+    newRect.origin.x = MIN(canvasDragAnchorPoint.x, canvasPoint.x);
+    newRect.origin.y = MIN(canvasDragAnchorPoint.y, canvasPoint.y);
+    newRect.size.width = ABS(canvasDragAnchorPoint.x - canvasPoint.x + 1);
+    newRect.size.height = ABS(canvasDragAnchorPoint.y - canvasPoint.y + 1);
+    
+    [self fitToNewBBox:newRect];
+}
+
+- (id)valueForKey:(NSString *)key
+{
+    KSVG::SVGStyledElementImpl *element = (KSVG::SVGStyledElementImpl *)_private->item->userData();
+    id theValue = nil;
+    
+    if ([key isEqualToString:@"isFilled"]) {
+        KDOM::DOMString value = element->getAttributeNS(KDOM::NS_SVG, "fill");
+        theValue = [NSNumber numberWithBool:(value != "none")];
+    } else if ([key isEqualToString:@"isStroked"]) {
+        KDOM::DOMString value = element->getAttributeNS(KDOM::NS_SVG, "stroke");
+        theValue = [NSNumber numberWithBool:(value != "none")];
+    } else if ([key isEqualToString:@"fillColor"]) {
+        KDOM::DOMString value = element->getAttributeNS(KDOM::NS_SVG, "fill");
+        theValue = nsColor(QColor(value.string()));
+    } else if ([key isEqualToString:@"strokeColor"]) {
+        KDOM::DOMString value = element->getAttributeNS(KDOM::NS_SVG, "stroke");
+        theValue = nsColor(QColor(value.string()));
+    }
+    
+    if (theValue)
+        return theValue;
+    
+    return [super valueForKey:key];
+}
+
+- (NSAttributedString *)attribtuedXMLString
+{
+    QString *nodeText = new QString();
+    QTextStream nodeTextStream(nodeText, IO_WriteOnly);
+    KDOM::Helper::PrintNode(nodeTextStream, (KDOM::NodeImpl *)_private->item->userData());
+    NSString *nodeString = nodeText->getNSString();
+    delete nodeText;
+    
+    if (nodeString)
+        return [[NSAttributedString alloc] initWithString:nodeString];
+    return nil;
+}
+
+@end
diff --git a/WebCore/WebCore+SVG/DrawCanvasItemPrivate.h b/WebCore/WebCore+SVG/DrawCanvasItemPrivate.h
new file mode 100644 (file)
index 0000000..bdde519
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2005 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. 
+ */
+
+/*
+ WARNING: These files are temporary and exist solely for the purpose
+ of allowing greater testing of WebCore+SVG prior to full DOM integration.
+ Do NOT depend on these SPIs or files as they will soon be gone.
+*/
+
+#import <WebCore+SVG/DrawCanvasItem.h>
+
+class KCanvasItem;
+
+@interface DrawCanvasItem (PrivateMethods)
+
+// This does not retain canvasItem, dangerous.
++ (id)canvasItemForItem:(KCanvasItem *)canvasItem;
+- (id)initWithItem:(KCanvasItem *)canvasItem;
+
+- (KCanvasItem *)item;
+
+@end
\ No newline at end of file
diff --git a/WebCore/WebCore+SVG/DrawDocument.h b/WebCore/WebCore+SVG/DrawDocument.h
new file mode 100644 (file)
index 0000000..8ad63eb
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2005 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. 
+ */
+
+/*
+ WARNING: These files are temporary and exist solely for the purpose
+ of allowing greater testing of WebCore+SVG prior to full DOM integration.
+ Do NOT depend on these SPIs or files as they will soon be gone.
+*/
+
+
+#import <Cocoa/Cocoa.h>
+
+@class DrawDocumentPrivate;
+@class DrawView;
+
+@interface DrawDocument : NSObject {
+@private
+    DrawDocumentPrivate *_private;
+}
+
++ (id)documentWithSVGData:(NSData *)data;
+//+ (id)documentWithSVGData:(NSData *)data loadingIntoView:(DrawView *)view;
+
+- (id)initWithSVGData:(NSData *)data;
+//- (id)initWithSVGData:(NSData *)data loadingIntoView:(DrawView *)view;
+- (id)initWithContentsOfFile:(NSString *)path;
+
+//- (NSSize)documentSize;
+
+- (NSString *)svgText;
+
+@end
diff --git a/WebCore/WebCore+SVG/DrawDocument.mm b/WebCore/WebCore+SVG/DrawDocument.mm
new file mode 100644 (file)
index 0000000..487ac95
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2005 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 "DrawDocumentPrivate.h"
+#import "DrawCanvasItemPrivate.h"
+
+#import "DrawViewPrivate.h"
+#import "QuartzSupport.h" // for CGAffineTransformMakeMapBetweenRects()
+
+#import <kcursor.h>
+#import <qevent.h>
+
+#import <kcanvas/KCanvas.h>
+#import <kcanvas/KCanvasItem.h>
+#import <kcanvas/KCanvasContainer.h>
+#import <kcanvas/device/quartz/KCanvasViewQuartz.h>
+#import <kcanvas/device/quartz/KRenderingDeviceQuartz.h>
+
+#define id ID_HACK
+
+#import <kdom/Namespace.h>
+#import <kdom/Helper.h>
+#import <kdom/DOMConfiguration.h>
+#import <kdom/parser/KDOMParser.h>
+#import <kdom/backends/libxml/LibXMLParser.h>
+#import <kdom/impl/NodeImpl.h>
+#import <kdom/impl/NodeListImpl.h>
+#import <kdom/impl/DOMConfigurationImpl.h>
+#import <kdom/impl/DOMImplementationImpl.h>
+#import <kdom/impl/ElementImpl.h>
+#import <kdom/events/kdomevents.h>
+#import <kdom/events/impl/EventImpl.h>
+#import <kdom/events/impl/MouseEventImpl.h>
+
+#import <ksvg2/KSVGPart.h>
+#import <ksvg2/KSVGView.h>
+#import <ksvg2/core/KSVGDocumentBuilder.h>
+#import <ksvg2/impl/SVGDocumentImpl.h>
+#import <ksvg2/impl/SVGSVGElementImpl.h>
+#import <ksvg2/impl/SVGDescElementImpl.h>
+#import <ksvg2/impl/SVGStyledElementImpl.h>
+#import <ksvg2/impl/SVGEllipseElementImpl.h>
+#import <ksvg2/impl/SVGRectElementImpl.h>
+
+// these shouldn't be used!
+#import <ksvg2/dom/SVGEllipseElement.h>
+#import <ksvg2/dom/SVGRectElement.h>
+
+#undef id
+
+using namespace KDOM;
+using namespace KSVG;
+
+@interface DrawDocumentPrivate : NSObject {
+    @public
+    SVGDocumentImpl *svgDocument;
+    KCanvas *canvas;
+    KCanvasViewQuartz *primaryView;
+    
+    KCanvasViewQuartz *dummyView; // used to hold the canvas, until we get a real view.
+}
+
+@end
+
+@implementation DrawDocumentPrivate
+
++ (KRenderingDeviceQuartz *)sharedRenderingDevice
+{
+    static KRenderingDeviceQuartz *__quartzRenderingDevice = NULL;
+    if (!__quartzRenderingDevice)
+        __quartzRenderingDevice = new KRenderingDeviceQuartz();
+    
+    return __quartzRenderingDevice;
+}
+
+- (void)dealloc
+{
+    if (canvas)
+        delete canvas;
+    if (svgDocument)
+        svgDocument->deref();
+    [super dealloc];
+}
+
+- (void)setSVGDocument:(SVGDocumentImpl *)svgDocumentImpl
+{
+    KDOM_SAFE_SET(svgDocument, svgDocumentImpl);
+}
+
+- (void)setPrimaryView:(KCanvasViewQuartz *)view
+{
+    if (!primaryView || (primaryView == dummyView)) {
+        if (!canvas)
+            canvas = new KCanvas([DrawDocumentPrivate sharedRenderingDevice]);
+        
+        primaryView = view;
+        primaryView->init(canvas, NULL);
+        if (svgDocument) {
+            svgDocument->setCanvasView(primaryView);
+            canvas->addView(primaryView);
+            //svgDocument->attach();
+            
+//          // if the SVG doc doesn't contain any size information
+//          // size it appropriately...
+//          if (NSEqualSizes([self canvasSize], NSMakeSize(-1,-1))) {
+//              [self sizeCanvasToFitContent];
+//          }
+            delete dummyView;
+            dummyView = NULL;
+        }
+    }
+}
+
+@end
+
+
+@interface DrawView (InternalCanvasMethods)
+- (KCanvasViewQuartz *)canvasView;
+@end
+
+@implementation DrawDocument
+
++ (id)documentWithSVGData:(NSData *)data
+{
+    return [[[DrawDocument alloc] initWithSVGData:data] autorelease];
+}
+
+// makes new empty document
+//- (id)init
+//{
+//     if (self = [super init]) {
+//             // need an alternative call than "self"
+//             SVGDocumentImpl *svgDoc = new SVGDocumentImpl(SVGDOMImplementation::self());
+//             [_private setSVGDocument:svgDoc];
+//     }
+//     return self;
+//}
+
+
+- (id)initWithSVGData:(NSData *)data
+{
+    self = [super init];
+    if (!self)
+        return nil;
+    
+    _private = [[DrawDocumentPrivate alloc] init];
+    
+    // total hack!
+    // this is needed until post-parse attach works.
+    // these are leaking for now...
+    KSVGPart *dummyPart = new KSVGPart();
+    KSVGView *dummySVGView = static_cast<KSVGView *>(dummyPart->view());
+    _private->dummyView =  static_cast<KCanvasViewQuartz *>(dummySVGView->canvasView());
+    // FIXME: HACK: I really need to be tracking these parts/views correctly...
+    
+    [_private setPrimaryView:_private->dummyView];
+    
+    // Builder is owned (deleted) by parser...
+    KSVG::DocumentBuilder *builder = new KSVG::DocumentBuilder(dummySVGView);
+    KDOM::LibXMLParser *parser = new KDOM::LibXMLParser(KURL());
+    parser->setDocumentBuilder(builder);
+    
+    // no entity refs
+    parser->domConfig()->setParameter(KDOM::ENTITIES.implementation(), false);
+    parser->domConfig()->setParameter(KDOM::ELEMENT_CONTENT_WHITESPACE.implementation(), false);
+    
+    // Feed the parser the whole document (a total hack)
+    parser->doOneShotParse((const char *)[data bytes], [data length]);
+    
+    SVGDocumentImpl *svgDoc = static_cast<SVGDocumentImpl *>(parser->document().handle());
+    [_private setSVGDocument:svgDoc];
+    delete parser; // we're done parsing.
+    if(!_private->svgDocument) {
+        NSLog(@"Failed to get document!");
+        [self release];
+        return nil;
+    }
+    
+    // FIXME: temporary
+    // this needs to go somewhere in ksvg2
+    if ((_private->canvas->canvasSize() == QSize(-1,-1)) && _private->canvas->rootContainer()) {
+        QRect canvasBounds = _private->canvas->rootContainer()->bbox();
+        _private->canvas->setCanvasSize(QSize(abs(canvasBounds.x()) + canvasBounds.width(),
+                                              abs(canvasBounds.y()) + canvasBounds.height()));
+    }
+    
+    return self;
+}
+
+- (id)initWithContentsOfFile:(NSString *)path
+{
+    NSData *data = [NSData dataWithContentsOfFile:path];
+    if ([[path pathExtension] isEqualToString:@"svg"]) {
+        //NSLog(@"Loading SVG Data from file: %@", path);
+        self = [self initWithSVGData:data];
+    } else {
+        NSLog(@"Error: Asked to create DrawDocument from unsupported file type!  File: %@", path);
+        [self release];
+        self = nil;
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [_private release];
+    [super dealloc];
+}
+
+- (NSString *)title
+{
+    // Detect title if possible...
+    KDOM::DOMString title = _private->svgDocument->title();
+    return title.string().getNSString();
+}
+
+- (NSString *)description
+{
+    // Detect description if possible...
+//  KDOM::NodeListImpl *descList = _private->svgDocument->getElementsByTagName("desc");
+//  if(descList && (descList->length() > 0)) {
+//  SVGDescElementImpl *descImpl = dynamic_cast<SVGDescElementImpl *>(descList->item(0));
+//  return descImpl->description().string().getNSString();
+//  }
+    return nil;
+}
+
+// internal SPI
+- (DrawView *)primaryView
+{
+    if (_private->primaryView)
+        return _private->primaryView->view();
+    return nil;
+}
+
+- (void)setPrimaryView:(DrawView *)view
+{
+    [_private setPrimaryView:(KCanvasViewQuartz *)[view canvasView]];
+}
+
+- (void)registerView:(DrawView *)view
+{
+    if (!_private->primaryView || (_private->primaryView == _private->dummyView))
+        [self setPrimaryView:view];
+    else
+        _private->canvas->addView([view canvasView]);
+}
+
+- (void)unregisterView:(DrawView *)view
+{
+    _private->canvas->removeView([view canvasView]);
+}
+
+- (NSString *)svgText
+{
+    QString *dumpText = new QString();
+    QTextStream dumpStream(dumpText, IO_WriteOnly);
+    KDOM::Helper::PrintNode(dumpStream, _private->svgDocument);
+    NSString *svgText = dumpText->getNSString();
+    delete dumpText;
+    
+    return svgText;
+}
+
+@end
+
+@implementation DrawDocument (DrawMouseEvents)
+
+- (BOOL)documentListensForMouseMovedEvents
+{
+    SVGDocumentImpl *document = _private->svgDocument;
+    
+    return (document &&        
+            (document->hasListenerType(KDOM::DOMFOCUSOUT_EVENT) ||
+             document->hasListenerType(KDOM::MOUSEOVER_EVENT) ||
+             document->hasListenerType(KDOM::MOUSEMOVE_EVENT) ||
+             document->hasListenerType(KDOM::MOUSEOUT_EVENT)));
+}
+
+- (BOOL)documentListensForMouseDownEvents
+{
+    return (_private->svgDocument && _private->svgDocument->hasListenerType(KDOM::MOUSEDOWN_EVENT));
+}
+
+- (BOOL)documentListensForMouseUpEvents
+{
+    SVGDocumentImpl *document = _private->svgDocument;
+    
+    return (document &&
+            (document->hasListenerType(KDOM::DOMFOCUSIN_EVENT) ||
+             document->hasListenerType(KDOM::DOMACTIVATE_EVENT) ||
+             document->hasListenerType(KDOM::CLICK_EVENT) ||
+             document->hasListenerType(KDOM::MOUSEUP_EVENT)));
+}
+
+- (KDOM::MouseEventImpl *)newMouseEventWithEventId:(KDOM::EventId)eventId qMouseEvent:(QMouseEvent *)qevent
+{
+    if (!_private->svgDocument)
+        return NULL;
+    
+    KDOM::DOMString eventString = KDOM::DOMImplementationImpl::self()->idToType(eventId);
+    
+    SVGSVGElementImpl *root = _private->svgDocument->rootElement();
+    float scale = (root ? root->currentScale() : 1.0);
+    
+    // Setup kdom 'MouseEvent'...
+    KDOM::MouseEventImpl *event = static_cast<KDOM::MouseEventImpl *>(_private->svgDocument->createEvent("MouseEvents"));
+    event->ref();
+    
+    event->initMouseEvent(eventString, qevent, scale);
+    return event;
+}
+
+NSCursor *cursorForStyle(KDOM::RenderStyle *style)
+{
+    if(!style) return nil;
+    NSCursor *newCursor = nil;
+    switch(style->cursor())
+    {
+        case KDOM::CS_AUTO:
+        case KDOM::CS_DEFAULT:
+            newCursor = KCursor::arrowCursor().handle();
+            break;
+        case KDOM::CS_CROSS:
+        case KDOM::CS_PROGRESS:
+            newCursor = KCursor::crossCursor().handle();
+            break;
+        case KDOM::CS_POINTER:
+            newCursor = KCursor::handCursor().handle();
+            break;
+        case KDOM::CS_MOVE:
+            newCursor = KCursor::sizeAllCursor().handle();
+            break;
+        case KDOM::CS_E_RESIZE:
+        case KDOM::CS_W_RESIZE:
+            newCursor = KCursor::sizeHorCursor().handle();
+            break;
+        case KDOM::CS_NE_RESIZE:
+        case KDOM::CS_SW_RESIZE:
+            newCursor = KCursor::sizeBDiagCursor().handle();
+            break;
+        case KDOM::CS_NW_RESIZE:
+        case KDOM::CS_SE_RESIZE:
+            newCursor = KCursor::sizeFDiagCursor().handle();
+            break;
+        case KDOM::CS_N_RESIZE:
+        case KDOM::CS_S_RESIZE:
+            newCursor = KCursor::sizeVerCursor().handle();
+            break;
+        case KDOM::CS_TEXT:
+            newCursor = KCursor::ibeamCursor().handle();
+            break;
+        case KDOM::CS_WAIT:
+            newCursor = KCursor::waitCursor().handle();
+            break;
+        case KDOM::CS_HELP:
+            newCursor = KCursor::whatsThisCursor().handle();
+            break;
+        default:
+        NSLog(@"setting default mouse cursor");
+            newCursor = KCursor::arrowCursor().handle();
+    }
+    return newCursor;
+}
+
+- (NSCursor *)cursorAfterPropagatingMouseMovedEvent:(NSEvent *)theEvent fromView:(DrawView *)view
+{
+    NSCursor *newCursor = [NSCursor arrowCursor];
+    
+    QMouseEvent *event = new QMouseEvent(QEvent::MouseMove, theEvent);
+    KDOM::MouseEventImpl *mev = [self newMouseEventWithEventId:KDOM::MOUSEMOVE_EVENT qMouseEvent:event];
+    if(mev)
+    {
+        // FIXME this mapping should be done elsewhere...
+        NSPoint viewPoint = [view convertPoint:[theEvent locationInWindow] fromView:nil];
+        QPoint canvasPoint = QPoint([view mapViewPointToCanvas:viewPoint]);
+        _private->svgDocument->prepareMouseEvent(false, canvasPoint.x(), canvasPoint.y(), mev);
+        
+        KDOM::ElementImpl *target = static_cast<KDOM::ElementImpl *>(mev->relatedTarget());
+        if(target)
+        {
+            KDOM::RenderStyle *style = target->renderStyle();
+            newCursor = cursorForStyle(style);
+        }
+        mev->deref();
+    }
+    return newCursor;
+}
+
+- (void)propagateMouseUpEvent:(NSEvent *)theEvent fromView:(DrawView *)view
+{
+    QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonRelease, theEvent);
+    KDOM::MouseEventImpl *mev = [self newMouseEventWithEventId:KDOM::MOUSEUP_EVENT qMouseEvent:event];
+    if(mev)
+    {
+        // FIXME this mapping should be done elsewhere...
+        NSPoint viewPoint = [view  convertPoint:[theEvent locationInWindow] fromView:nil];
+        QPoint canvasPoint = QPoint([view mapViewPointToCanvas:viewPoint]);
+        _private->svgDocument->prepareMouseEvent(false, canvasPoint.x(), canvasPoint.y(), mev);
+        mev->deref();
+    }
+}
+
+- (void)propagateMouseDownEvent:(NSEvent *)theEvent fromView:(DrawView *)view
+{
+    QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonPress, theEvent);
+    KDOM::MouseEventImpl *mev = [self newMouseEventWithEventId:KDOM::MOUSEDOWN_EVENT qMouseEvent:event];
+    if(mev)
+    {
+        // FIXME this mapping should be done elsewhere...
+        NSPoint viewPoint = [view convertPoint:[theEvent locationInWindow] fromView:nil];
+        QPoint canvasPoint = QPoint([view mapViewPointToCanvas:viewPoint]);
+        _private->svgDocument->prepareMouseEvent(false, canvasPoint.x(), canvasPoint.y(), mev);
+        mev->deref();
+    }
+}
+
+
+@end
+
+@implementation DrawDocument (KCanvasManipulation)
+
+// SPI
+- (KCanvas *)canvas
+{
+    return _private->canvas;
+}
+
+- (NSSize)canvasSize
+{
+    KCanvas *canvas = [self canvas];
+    if (!canvas)
+        return NSZeroSize;
+    return NSSize(canvas->canvasSize());
+}
+
+
+- (void)sizeCanvasToFitContent
+{
+    NSRect canvasBounds = NSRect(_private->canvas->rootContainer()->bbox());
+    if (!NSEqualRects(canvasBounds, NSZeroRect)) {
+        NSLog(@"zooming to rect: %@", NSStringFromRect(canvasBounds));
+        _private->canvas->setCanvasSize(QSize(int(abs((int)canvasBounds.origin.x) + canvasBounds.size.width),
+                                              int(abs((int)canvasBounds.origin.y) + canvasBounds.size.height)));
+        // this pan should be moved out of the doc...
+        [[self primaryView] setCanvasVisibleOrigin:NSMakePoint(canvasBounds.origin.x * -1, canvasBounds.origin.y * -1)];
+    }
+}
+
+
+- (DrawCanvasItem *)canvasItemAtPoint:(NSPoint)canvasHitPoint
+{
+    KCanvasItemList hitItems;
+    
+    _private->canvas->collisions(QPoint(canvasHitPoint), hitItems);
+    
+    NSLog(@"canvasItemAtPoint:%@ hit %i items", NSStringFromPoint(canvasHitPoint), hitItems.count());
+    KCanvasItemList::Iterator it = hitItems.begin();
+    KCanvasItemList::Iterator end = hitItems.end();
+    for(; it != end; ++it) {
+        NSLog(@"canvasItemAtPoint: hit item with bbox: %@", NSStringFromRect(NSRect((*it)->bbox())));
+    }
+    
+    if (!hitItems.isEmpty())
+        return [DrawCanvasItem canvasItemForItem:(KCanvasItem *)hitItems.last()];
+    
+    return nil;
+}
+
+- (void)removeItemFromDOM:(DrawCanvasItem *)canvasItem
+{
+    if (canvasItem) {
+        KCanvasItem *cItem = [canvasItem item];
+        KDOM::NodeImpl *node = (KDOM::NodeImpl *)cItem->userData();
+        KDOM::NodeImpl *parent = node->parentNode();
+        parent->removeChild(node);
+    }
+}
+
+- (DrawCanvasItem *)createItemForTool:(int)tool atPoint:(NSPoint)mousePoint{
+    KDOM::ElementImpl *newElement = NULL;
+    KCanvasItem *newCanvasItem = NULL;
+    
+    switch (tool) {
+       case DrawViewToolElipse:
+       {
+            newElement = _private->svgDocument->createElement("ellipse");
+            newElement->setAttributeNS(KDOM::NS_SVG, "cx", QString::number(mousePoint.x));
+            newElement->setAttributeNS(KDOM::NS_SVG, "cy", QString::number(mousePoint.y));
+            break;
+       }
+       case DrawViewToolTriangle:
+            break;
+       case DrawViewToolRectangle:
+       {
+            newElement = _private->svgDocument->createElement("rect");
+            newElement->setAttributeNS(KDOM::NS_SVG, "x", QString::number(mousePoint.x));
+            newElement->setAttributeNS(KDOM::NS_SVG, "y", QString::number(mousePoint.y));
+            break;
+       }
+       case DrawViewToolLine:
+       case DrawViewToolPolyLine:
+       case DrawViewToolArc:
+            // these just don't really work with this model...
+       default:
+            NSLog(@"Can't create item for unsupported tool.");
+    }
+    if (newElement) {
+        newElement->setAttributeNS(KDOM::NS_SVG, "fill", "navy");
+        SVGSVGElementImpl *rootNode = _private->svgDocument->rootElement();
+        rootNode->appendChild(newElement);
+        newElement->ref(); // don't know why this is necessary...
+        newElement->attach(); // attach it to the canvas.
+        newCanvasItem = static_cast<SVGStyledElementImpl *>(newElement)->canvasItem();
+        NSLog(@"Successfully created element: %p, now canvasItem: %p", newElement,  newCanvasItem);
+        
+        if (newCanvasItem) {
+            // wrap it in a DrawCanvasItem, return.
+            return [DrawCanvasItem canvasItemForItem:newCanvasItem];
+        }
+    }
+    return nil;
+}
+
+@end
+
+@implementation DrawDocument (SuperPrivateSPIForDavid)
+
+
+// This is really "drawInRect: inCGContext:
+- (void)drawRect:(NSRect)destRect inCGContext:(CGContextRef)context
+{
+    if (!_private->canvas)
+        return;
+    
+    static KRenderingDeviceContextQuartz *__sharedQuartzContext = nil;
+    if (!__sharedQuartzContext)
+        __sharedQuartzContext = new KRenderingDeviceContextQuartz();
+    
+    KRenderingDevice *renderingDevice = _private->canvas->renderingDevice();
+    
+    // push the drawing context
+    __sharedQuartzContext->setCGContext(context);
+    renderingDevice->pushContext(__sharedQuartzContext);
+    CGContextSaveGState(context);
+    
+    // transform to the dest rect.
+    NSSize sourceSize = [self canvasSize];
+    CGRect sourceRect = {{0,0},{sourceSize.width, sourceSize.height}};
+    CGAffineTransform map = CGAffineTransformMakeMapBetweenRects(sourceRect,*(CGRect *)&destRect);
+    CGContextConcatCTM(context,map);
+    
+    // do the draw
+    _private->canvas->rootContainer()->draw(QRect(sourceRect));
+    
+    // restore drawing state
+    CGContextRestoreGState(context);
+    renderingDevice->popContext();
+}
+
+@end
+
diff --git a/WebCore/WebCore+SVG/DrawDocumentPrivate.h b/WebCore/WebCore+SVG/DrawDocumentPrivate.h
new file mode 100644 (file)
index 0000000..f65f4fa
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2005 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. 
+ */
+
+/*
+ WARNING: These files are temporary and exist solely for the purpose
+ of allowing greater testing of WebCore+SVG prior to full DOM integration.
+ Do NOT depend on these SPIs or files as they will soon be gone.
+*/
+
+
+#import <WebCore+SVG/DrawDocument.h>
+
+@class DrawView;
+@class DrawCanvasItem;
+
+@interface DrawDocument (PrivateMethods)
+
+// register as "primary" view (zoom/pan notifications)
+- (DrawView *)primaryView;
+- (void)setPrimaryView:(DrawView *)view;
+
+// register/unregister w/ DOM, etc.
+- (void)registerView:(DrawView *)view;
+- (void)unregisterView:(DrawView *)view;
+
+@end
+
+@interface DrawDocument (SuperPrivateSPIForDavid)
+- (void)drawRect:(NSRect)dirtyRect inCGContext:(CGContextRef)context;
+@end
+
+@interface DrawDocument (DrawMouseEvents)
+- (BOOL)documentListensForMouseMovedEvents;
+- (BOOL)documentListensForMouseDownEvents;
+- (BOOL)documentListensForMouseUpEvents;
+
+- (void)propagateMouseUpEvent:(NSEvent *)theEvent fromView:(DrawView *)view;
+- (void)propagateMouseDownEvent:(NSEvent *)theEvent fromView:(DrawView *)view;
+- (NSCursor *)cursorAfterPropagatingMouseMovedEvent:(NSEvent *)theEvent fromView:(DrawView *)view;
+
+@end
+
+/* This should probably break out into another file/class */
+@interface DrawDocument (KCanvasManipulation)
+
+- (NSSize)canvasSize;
+- (void)sizeCanvasToFitContent;
+
+/*
+ This currently (hackishly) manipulates the render tree.
+ This "design" decision was made because the dom hit testing
+ was not working properly in ksvg2 at the time.
+ Anyone writing a real editor should to hit testing against
+ the DOM, using Obj-C DOM interfaces, instead of this
+ very hackish DrawCanvasItem Obj-C RenderObject wrapper.
+*/
+- (DrawCanvasItem *)canvasItemAtPoint:(NSPoint)canvasHitPoint;
+- (void)removeItemFromDOM:(DrawCanvasItem *)item;
+- (DrawCanvasItem *)createItemForTool:(int)tool atPoint:(NSPoint)canvasPoint;
+
+@end
\ No newline at end of file
diff --git a/WebCore/WebCore+SVG/DrawView.h b/WebCore/WebCore+SVG/DrawView.h
new file mode 100644 (file)
index 0000000..7aaab7c
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2005 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. 
+ */
+
+/*
+ WARNING: These files are temporary and exist solely for the purpose
+ of allowing greater testing of WebCore+SVG prior to full DOM integration.
+ Do NOT depend on these SPIs or files as they will soon be gone.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+@class DrawViewPrivate;
+@class DrawDocument;
+
+typedef enum {
+    // viewing tools
+    DrawViewToolBrowse, // click on links, interact w/ javascript, etc.
+    DrawViewToolPan,
+    DrawViewToolZoom,
+    
+    // editing tools
+    DrawViewToolArrow, // select, change size, etc.
+    DrawViewToolLine,
+    DrawViewToolElipse,
+    DrawViewToolRectangle,
+    DrawViewToolTriangle, // generic polygon tool?
+    DrawViewToolPolyLine,
+    DrawViewToolArc,
+    
+} DrawViewTool;
+
+@interface DrawView : NSView {
+    
+@private
+    DrawViewTool _toolMode;
+    BOOL       _isEditable;
+    NSImageScaling _scaleRule;
+    
+    DrawViewPrivate *_private;
+}
+
+- (DrawDocument *)document;
+- (void)setDocument:(DrawDocument *)document;
+
+- (NSImageScaling)imageScaling;
+- (void)setImageScaling:(NSImageScaling)scaling;
+
+- (IBAction)zoomIn:(id)sender;
+- (IBAction)zoomOut:(id)sender;
+- (IBAction)zoomOriginal:(id)sender;
+- (IBAction)zoomToFit:(id)sender;
+
+// Will size the view to fit whatever SVG document it has in it.
+- (void)sizeToFitViewBox;
+// will fit whatever the canvas size is... (deprecated)
+- (void)sizeToFitCanvas;
+
+- (int)toolMode;
+- (void)setToolMode:(int)toolMode;
+
+/* Editing Support */
+
+- (BOOL)isEditable;
+- (void)setEditable:(BOOL)editable;
+
+- (IBAction)deleteSelection:(id)sender;
+- (IBAction)moveSelectionForward:(id)sender;
+- (IBAction)moveSelectionBackward:(id)sender;
+
+@end
diff --git a/WebCore/WebCore+SVG/DrawView.mm b/WebCore/WebCore+SVG/DrawView.mm
new file mode 100644 (file)
index 0000000..ae3dc0d
--- /dev/null
@@ -0,0 +1,902 @@
+/*
+ * Copyright (C) 2005 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 "DrawViewPrivate.h"
+#import "DrawCanvasItem.h"
+#import "DrawDocumentPrivate.h"
+
+#import <kcanvas/KCanvas.h>
+#import <kcanvas/KCanvasContainer.h>
+#import <kcanvas/device/quartz/KCanvasViewQuartz.h>
+#import <kcanvas/device/quartz/KRenderingDeviceQuartz.h>
+
+// This should go in the Prefix header eventually.
+#define foreacharray(__variable, __container) \
+for (int __variable##__i=0, __variable##__n=[__container count];  \
+     __variable##__i < __variable##__n && (__variable = [__container objectAtIndex:__variable##__i]);  \
+     ++__variable##__i)
+
+#define NSDifferencePoint(a,b) (NSMakePoint(a.x-b.x, a.y-b.y))
+#define NSSumPoint(a,b) (NSMakePoint(a.x+b.x, a.y+b.y))
+
+// editing knobs.
+#define KNOB_SIZE 6
+#define KNOB_HALF_SIZE 3
+
+typedef enum {
+    DragActionNone = 0,
+    DragActionPan,
+    DragActionResize,
+    DragActionMove,
+    DragActionSelection
+} DrawDragAction;
+
+// this is sorta a hack
+@interface DrawDocument (InternalCanvasMethod)
+- (KCanvas *)canvas;
+@end
+
+
+@interface DrawViewPrivate : NSObject {
+    @public
+    NSArray *selectedItems;
+    
+    DrawView *drawView; // pointer to "owner"
+    DrawDocument *document;
+    
+    NSColor *backgroundColor;
+    
+    int dragControlPointIndex;
+    NSPoint dragStartPoint;
+    NSPoint lastDragPoint;
+    NSPoint canvasDragAnchorPoint; // used mostly for group resize.
+    NSPoint canvasDragOriginOffset;
+    
+    int trackingRectTag;
+    DrawDragAction currentDragAction;
+    NSRect selectionRect;
+    
+    NSSize _maxSize;
+    
+    // temporary hack, will eventually be stored in scrollview/view
+    float canvasZoom;
+    NSPoint canvasvisibleOrigin;
+    
+    KCanvasViewQuartz *canvasView;
+    KRenderingDeviceContextQuartz *quartzContext;
+}
+@end 
+
+@implementation DrawViewPrivate
+
++ (void)setFilterSupportEnabled:(BOOL)enabled
+{
+    KRenderingDeviceQuartz::setFiltersEnabled(enabled);
+}
+
++ (BOOL)isFilterSupportEnabled
+{
+    return KRenderingDeviceQuartz::filtersEnabled();
+}
+
+- (id)initWithDrawView:(DrawView *)view
+{
+    if ((self = [super init])) {
+        drawView = view;
+        quartzContext = new KRenderingDeviceContextQuartz();
+        canvasView = new KCanvasViewQuartz();
+        canvasView->setView(drawView);
+        canvasView->setContext(quartzContext);
+    }
+    return self;
+}
+
+- (DrawDocument *)document
+{
+    return document;
+}
+
+- (void)setDocument:(DrawDocument *)doc
+{
+    if (doc != document) {
+        [document unregisterView:drawView];
+        [document release];
+        document = [doc retain];
+        [document registerView:drawView];
+        
+        delete canvasView;
+        canvasView = NULL;
+        if (document) {
+            canvasView = new KCanvasViewQuartz();
+            canvasView->init([document canvas], NULL);
+            canvasView->setView(drawView);
+            canvasView->setContext(quartzContext);
+        }
+    }
+}
+
+// c++ enabled drawing code.
+- (void)drawRect:(NSRect)dirtyViewRect
+{
+    if (![document canvas])
+        return;
+    if (!canvasView)
+        return;
+    
+    // push the drawing context
+    KRenderingDevice *renderingDevice = [document canvas]->renderingDevice();
+    
+    // Apply the top-level "world transform" for zoom/pan
+    CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+    quartzContext->setCGContext(context); // should probably just be set once...
+    renderingDevice->pushContext(quartzContext);
+    CGContextSaveGState(context);
+    CGContextConcatCTM(context, CGAffineTransformInvert([drawView transformFromViewToCanvas]));
+    
+    // do the draw
+    //[document drawRect:[drawView mapViewRectToCanvas:dirtyViewRect] inCGContext:context];
+    [document canvas]->rootContainer()->draw(QRect([drawView mapViewRectToCanvas:dirtyViewRect]));
+    
+    // restore drawing state
+    CGContextRestoreGState(context);
+    renderingDevice->popContext();
+    quartzContext->setCGContext(NULL);
+}
+
+- (void)dealloc
+{
+    // If we go away, make sure we clear the view pointer.
+    [document unregisterView:drawView];
+    delete canvasView;
+    delete quartzContext;
+    [super dealloc];
+}
+@end
+
+NSArray *DrawViewDragTypes;
+
+@interface DrawView (InternalMethods)
+- (void)drawKnobsForRect:(NSRect)rect;
+- (void)updateCanvasScale;
+- (void)enableMouseMovedEventsIfNeeded;
+@end
+
+@implementation DrawView
+
++ (void)initialize
+{
+    //DrawViewDragTypes = [[NSArray arrayWithObject:NSFilenamesPboardType] retain];
+    [self setKeys:[NSArray arrayWithObject:@"toolMode"] triggerChangeNotificationsForDependentKey:@"selectedCanvasItems"];
+}
+
+- (id)initWithFrame:(NSRect)frameRect
+{
+    if ((self = [super initWithFrame:frameRect]) != nil) {
+        _private = [[DrawViewPrivate alloc] initWithDrawView:self];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [_private release];
+    [super dealloc];
+}
+
+- (NSRect)selectionCanvasBoundingBox
+{
+    NSRect selectionBoundingBox = NSZeroRect;
+    DrawCanvasItem *item = nil;
+    NSArray *selectedItems = [self selectedCanvasItems];
+    foreacharray(item, selectedItems) {
+        selectionBoundingBox = NSUnionRect(selectionBoundingBox,[item boundingBox]);
+    }
+    return selectionBoundingBox;
+}
+
+- (void)_clearAndDrawBackground:(NSRect)dirtyRect
+{
+    [[NSColor lightGrayColor] set];
+    NSRectFill(dirtyRect);
+    
+    [[self backgroundColor] set];
+    NSSize canvasSize = [[self document] canvasSize];
+    NSRect canvasRect = NSMakeRect(0,0, canvasSize.width, canvasSize.height);
+    NSRectFill([self mapCanvasRectToView:canvasRect]);
+}
+
+- (void)_drawSelectionKnobs
+{
+    if ((_toolMode == DrawViewToolArrow) && [[self selectedCanvasItems] count]) {
+        NSRect viewSelectionBoundingBox = [self mapCanvasRectToView:[self selectionCanvasBoundingBox]];
+        [self drawKnobsForRect:viewSelectionBoundingBox];
+    }
+    
+    if (_private->currentDragAction == DragActionSelection) {
+        [[NSColor lightGrayColor] set];
+        NSFrameRect(_private->selectionRect);
+    }
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+    [self _clearAndDrawBackground:dirtyRect];
+    [_private drawRect:dirtyRect];
+    [self _drawSelectionKnobs];
+}
+
+- (void)setBackgroundColor:(NSColor *)color
+{
+    id oldColor = _private->backgroundColor ;
+    _private->backgroundColor = [color retain];
+    [oldColor release];
+}
+
+- (NSColor *)backgroundColor
+{
+    if (!_private->backgroundColor)
+        _private->backgroundColor = [[NSColor whiteColor] retain];
+    return _private->backgroundColor;
+}
+
+- (BOOL)isOpaque
+{
+    return ![_private->backgroundColor isEqual:[NSColor clearColor]];
+}
+
+- (BOOL)isFlipped
+{
+    return YES;
+}
+
+- (BOOL)acceptsFirstResponder
+{
+    return YES;
+}
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)event
+{
+    return ((_toolMode == DrawViewToolBrowse) || (_toolMode == DrawViewToolArrow));
+}
+
+- (NSImageScaling)imageScaling
+{
+    return _scaleRule;
+}
+
+- (void)setImageScaling:(NSImageScaling)scaling
+{
+    _scaleRule = scaling;
+    [self updateCanvasScale];
+}
+
+- (void)setFrame:(NSRect)newFrame
+{
+    [self removeTrackingRect:_private->trackingRectTag];
+    [self setFrameOrigin:newFrame.origin];
+    [self setFrameSize:newFrame.size];
+    _private->trackingRectTag =
+        [self addTrackingRect:[self frame]
+                        owner:self userData:NULL
+                 assumeInside:[self mouse:[NSEvent mouseLocation] inRect:[self bounds]]];
+}
+
+- (void)setFrameSize:(NSSize)newSize
+{
+    [super setFrameSize:newSize];
+    [self updateCanvasScale];
+}
+
+- (void)setDocument:(DrawDocument *)document
+{
+    if ([_private document] != document) {
+        [_private setDocument:document];
+        [self updateCanvasScale];
+        [self setNeedsDisplay:YES];
+    }
+}
+
+- (DrawDocument *)document
+{
+    return [_private document];
+}
+
+- (KCanvasViewQuartz *)canvasView
+{
+    return _private->canvasView;
+}
+
+#pragma mark -
+#pragma mark Editing support
+
+- (void)setEditable:(BOOL)editable
+{
+    [self unregisterDraggedTypes];
+    _isEditable = editable;
+    if (_isEditable)
+        [self registerForDraggedTypes:DrawViewDragTypes];
+}
+
+- (BOOL)isEditable
+{
+    return _isEditable;
+}
+
+- (NSRect)boundsForCanvasItem:(DrawCanvasItem *)canvasItem
+{
+    NSRect itemBBoxInCanvas = [canvasItem boundingBox];
+    NSRect itemBBoxInView = [self mapCanvasRectToView:itemBBoxInCanvas];
+    return NSInsetRect(itemBBoxInView, -KNOB_HALF_SIZE, -KNOB_HALF_SIZE);
+}
+
+- (NSArray *)selectedCanvasItems
+{
+    // selection only "exists" when using the arrow tool.
+    // but we sill remember selection between uses.
+    return _private->selectedItems;
+}
+
+- (void)setSelectedCanvasItems:(NSArray *)selectedItems
+{
+    DrawCanvasItem *newSelectedItem = nil;
+    NSMutableArray *newSelectedItems = [[NSMutableArray alloc] init];
+    foreacharray(newSelectedItem, selectedItems) {
+        [newSelectedItems addObject:newSelectedItem];
+    }
+    [_private->selectedItems release];
+    if ([newSelectedItems count])
+        _private->selectedItems = newSelectedItems;
+    else
+        _private->selectedItems = nil;
+    [self setNeedsDisplay:YES]; // FIXME: just invalidate the whole view for now.
+}
+
+- (IBAction)moveSelectionForward:(id)sender
+{
+    DrawCanvasItem *item = nil;
+    NSArray *selectedItems = [self selectedCanvasItems];
+    foreacharray(item, selectedItems) {
+        [item raise];
+    }
+}
+
+- (IBAction)moveSelectionBackward:(id)sender
+{
+    DrawCanvasItem *item = nil;
+    NSArray *selectedItems = [self selectedCanvasItems];
+    foreacharray(item, selectedItems) {
+        [item lower];
+    }
+}
+
+- (NSArray *)canvasControlPointsForSelection
+{
+    NSArray *selectedItems = [self selectedCanvasItems];
+    if ([selectedItems count] == 1)
+        return [[selectedItems objectAtIndex:0] controlPoints];
+    else if ([selectedItems count] > 1)
+        return [DrawCanvasItem controlPointsForRect:[self selectionCanvasBoundingBox]];
+    
+    return nil;
+}
+
+- (NSPoint)canvasDragAnchorPointForControlPointIndex:(int)controlPointIndex
+{
+    NSArray *selectedItems = [self selectedCanvasItems];
+    if ([selectedItems count] == 1) {
+        return [[selectedItems objectAtIndex:0] dragAnchorPointForControlPointIndex:controlPointIndex];
+    } else if ([selectedItems count] > 1) {
+        NSArray *controlPoints = [DrawCanvasItem controlPointsForRect:[self selectionCanvasBoundingBox]];
+        return [DrawCanvasItem dragAnchorPointForControlPointIndex:controlPointIndex fromRectControlPoints:controlPoints];
+    }
+    NSLog(@"Error, no selection, you shouldn't ask for drag anchor point!");
+    return NSZeroPoint;
+}
+
+- (int)controlPointIndexForCanvasHitPoint:(NSPoint)canvasPoint
+{
+    NSValue *controlPointValue = nil;
+    NSArray *controlPoints = [self canvasControlPointsForSelection];
+    
+    NSSize canvasKnobSize = [self mapViewSizeToCanvas:NSMakeSize(KNOB_SIZE, KNOB_SIZE)];
+    
+    NSRect controlRect = NSZeroRect;
+    controlRect.size = canvasKnobSize;
+    NSSize halfCanvasKnobSize = NSMakeSize(canvasKnobSize.width/2.f, canvasKnobSize.height/2.f);
+    int index = 0;
+    
+    foreacharray (controlPointValue, controlPoints) {
+        NSPoint controlPoint = [controlPointValue pointValue];
+        controlRect.origin.x = controlPoint.x - halfCanvasKnobSize.width;
+        controlRect.origin.y = controlPoint.y - halfCanvasKnobSize.height;
+        
+        if (NSPointInRect(canvasPoint, controlRect))
+            return index;
+        index++;
+    }
+    return NSNotFound;
+}
+
+- (BOOL)createCanvasItemAtPoint:(NSPoint)mousePoint
+{
+    // first map to canvas coords.
+    mousePoint = [self mapViewPointToCanvas:mousePoint];
+    
+    DrawCanvasItem *newItem = [[_private document] createItemForTool:_toolMode atPoint:mousePoint];
+    if (newItem) {
+        [self setSelectedCanvasItems:[NSArray arrayWithObject:newItem]];
+        return YES;
+    }
+    return NO;
+}
+
+- (IBAction)deleteSelection:(id)sender
+{
+    NSArray *oldItems = [[self selectedCanvasItems] retain];
+    [self setSelectedCanvasItems:nil];
+    DrawCanvasItem *oldItem = nil;
+    foreacharray(oldItem, oldItems) {
+        [[_private document] removeItemFromDOM:oldItem];
+    }
+    [oldItems release];
+}
+
+- (int)toolMode
+{
+    return _toolMode;
+}
+
+- (void)setToolMode:(int)newToolMode
+{
+    _toolMode = (DrawViewTool)newToolMode;
+    //[[self window] invalidateCursorRectsForView:self];
+    // Not getting called until the view becomes key...
+    [[self window] resetCursorRects]; // HACK?
+    if ([self mouse:[NSEvent mouseLocation] inRect:[self bounds]])
+        [self enableMouseMovedEventsIfNeeded];
+}
+
+- (void)resetCursorRects
+{
+    [super resetCursorRects];
+    
+    NSCursor *toolCursor = nil;
+    switch (_toolMode) {
+       case DrawViewToolPan:
+            toolCursor = [NSCursor openHandCursor];
+            break;
+       case DrawViewToolZoom:
+            toolCursor = [NSCursor closedHandCursor]; // for now...
+            break;
+       case DrawViewToolLine:
+       case DrawViewToolElipse:
+       case DrawViewToolRectangle:
+       case DrawViewToolPolyLine:
+       case DrawViewToolArc:
+            toolCursor = [NSCursor crosshairCursor];
+            break;
+       default:
+            break;
+    }
+    if (toolCursor)
+        [self addCursorRect:[self frame] cursor:toolCursor];
+}
+
+- (void)drawKnobsForRect:(NSRect)rect
+{
+    [[NSColor blackColor] set];
+    [NSBezierPath fillRect:NSMakeRect(rect.origin.x - KNOB_HALF_SIZE, rect.origin.y - KNOB_HALF_SIZE, KNOB_SIZE, KNOB_SIZE)];
+    [NSBezierPath fillRect:NSMakeRect(NSMaxX(rect) - KNOB_HALF_SIZE, rect.origin.y - KNOB_HALF_SIZE, KNOB_SIZE, KNOB_SIZE)];
+    [NSBezierPath fillRect:NSMakeRect(rect.origin.x - KNOB_HALF_SIZE, NSMaxY(rect) - KNOB_HALF_SIZE, KNOB_SIZE, KNOB_SIZE)];
+    [NSBezierPath fillRect:NSMakeRect(NSMaxX(rect) - KNOB_HALF_SIZE, NSMaxY(rect) - KNOB_HALF_SIZE, KNOB_SIZE, KNOB_SIZE)];
+}
+
+
+#pragma mark -
+#pragma mark Event support
+
+- (void)mouseDown:(NSEvent *)theEvent
+{
+    NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+    NSPoint canvasPoint = [self mapViewPointToCanvas:mousePoint];
+    _private->dragStartPoint = mousePoint;
+    _private->lastDragPoint = mousePoint;
+    
+    switch (_toolMode) {
+       case DrawViewToolBrowse:
+       {
+            // send mouse down events to DOM
+            if (![[_private document] documentListensForMouseDownEvents])
+                return;
+            [[_private document] propagateMouseDownEvent:theEvent fromView:self];
+            break;
+       }
+       case DrawViewToolArrow:
+       {
+            if ( (_private->dragControlPointIndex = [self controlPointIndexForCanvasHitPoint:canvasPoint]) != NSNotFound) {
+                _private->canvasDragAnchorPoint = [self canvasDragAnchorPointForControlPointIndex:_private->dragControlPointIndex];
+                NSLog(@"resize -- dragStartPoint: %@ canvasPoint: %@ controlIndex: %i canvasDragAnchorPoint: %@",
+                      NSStringFromPoint(mousePoint), NSStringFromPoint(canvasPoint),
+                      _private->dragControlPointIndex, NSStringFromPoint(_private->canvasDragAnchorPoint));
+                _private->currentDragAction = DragActionResize;
+            } else {
+                // FIXME: we really should select SVGElements, not canvas items...
+                DrawCanvasItem *hitItem = [[_private document] canvasItemAtPoint:canvasPoint];                 
+                //NSLog(@"move -- dragStartPoint: %@ canvasPoint: %@", NSStringFromPoint(mousePoint), NSStringFromPoint(canvasPoint));
+                if (hitItem) {
+                    NSArray *hitItems = [NSArray arrayWithObject:hitItem];
+                    [self setSelectedCanvasItems:hitItems];
+                    _private->currentDragAction = DragActionMove;
+                    NSPoint hitOrigin = [hitItem boundingBox].origin;
+                    _private->canvasDragOriginOffset = NSDifferencePoint(hitOrigin, canvasPoint);
+                } else {
+                    [self setSelectedCanvasItems:nil];
+                    _private->currentDragAction = DragActionSelection;
+                }
+            }
+            break;
+       }
+       case DrawViewToolPan:
+            [[NSCursor closedHandCursor] push];
+            _private->currentDragAction = DragActionPan;
+            //NSLog(@"mouseDown: %@", NSStringFromPoint(_private->lastDragPoint));
+            break;
+            // creation tools:
+       case DrawViewToolLine:
+       case DrawViewToolElipse:
+       case DrawViewToolTriangle:
+       case DrawViewToolRectangle:
+       case DrawViewToolPolyLine:
+       case DrawViewToolArc:
+       {
+            if ([self createCanvasItemAtPoint:mousePoint]) {
+                _private->currentDragAction = DragActionResize;
+                _private->canvasDragAnchorPoint = canvasPoint;
+                _private->dragControlPointIndex = 0;
+            }
+            break;
+       }
+       default:
+            break;
+    }
+}
+
+- (void)mouseDragged:(NSEvent *)theEvent
+{
+    NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+    
+    switch (_toolMode) {
+       case DrawViewToolBrowse:
+       {
+            // send mouse dragged events to DOM.
+            break;
+       }
+       case DrawViewToolArrow:
+       {
+            // move shapes here.
+            if (_private->currentDragAction == DragActionMove) {
+                NSSize dragOffset = NSMakeSize(mousePoint.x - _private->lastDragPoint.x, mousePoint.y - _private->lastDragPoint.y);
+                NSSize canvasDragOffset = [self mapViewSizeToCanvas:dragOffset];
+                NSLog(@"move: translating selection by: %@", NSStringFromSize(canvasDragOffset));
+                DrawCanvasItem *item = nil;
+                NSArray *selectedItems = [self selectedCanvasItems];
+                foreacharray(item, selectedItems) {
+                    [self setNeedsDisplayInRect:[self boundsForCanvasItem:item]];
+                    [item translateByOffset:canvasDragOffset];
+                    [self setNeedsDisplayInRect:[self boundsForCanvasItem:item]];
+                }
+            } else if (_private->currentDragAction == DragActionSelection) {
+                [self setNeedsDisplayInRect:_private->selectionRect];
+                _private->selectionRect = NSMakeRect(_private->dragStartPoint.x,
+                                                     _private->dragStartPoint.y,
+                                                     mousePoint.x - _private->dragStartPoint.x,
+                                                     mousePoint.y - _private->dragStartPoint.y);
+                [self setNeedsDisplayInRect:_private->selectionRect];
+            }
+            // fall through for resize code.
+       }
+       case DrawViewToolLine:
+       case DrawViewToolElipse:
+       case DrawViewToolTriangle:
+       case DrawViewToolRectangle:
+       case DrawViewToolPolyLine:
+       case DrawViewToolArc:
+       {
+            if (_private->currentDragAction == DragActionResize) {
+                NSPoint canvasPoint = [self mapViewPointToCanvas:mousePoint];
+                DrawCanvasItem *item = nil;
+                NSArray *selectedItems = [self selectedCanvasItems];
+                foreacharray(item, selectedItems) {
+                    [self setNeedsDisplayInRect:[self boundsForCanvasItem:item]];
+                    [item resizeWithPoint:canvasPoint usingControlPoint:_private->dragControlPointIndex dragAnchorPoint:_private->canvasDragAnchorPoint];
+                    [self setNeedsDisplayInRect:[self boundsForCanvasItem:item]];
+                }
+            }
+            break;
+       }
+            
+       case DrawViewToolPan:
+       {
+            NSPoint diff = NSDifferencePoint(mousePoint, _private->lastDragPoint);
+            NSPoint canvasOrigin = [self canvasVisibleOrigin];
+            NSPoint newOrigin = NSDifferencePoint(canvasOrigin, diff);
+            [self setCanvasVisibleOrigin:newOrigin];
+            //         NSLog(@"mouseDragged: %@  diff: %@ old origin: %@ newOrigin: %@",
+            //                 NSStringFromPoint(_private->lastDragPoint), 
+            //                 NSStringFromPoint(diff), NSStringFromPoint(canvasOrigin), NSStringFromPoint(newOrigin));
+            break;
+       }
+            
+       default:
+            break;
+    }
+    
+    // record the last drag point.
+    _private->lastDragPoint = mousePoint;
+}
+
+
+- (void)mouseUp:(NSEvent *)theEvent
+{
+    //NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+    
+    switch (_toolMode) {
+       case DrawViewToolBrowse:
+       {
+            if (![[_private document] documentListensForMouseUpEvents])
+                return;
+            [[_private document] propagateMouseUpEvent:theEvent fromView:self];
+       }
+       case DrawViewToolPan:
+            [NSCursor pop];
+            break;
+       case DrawViewToolArrow:
+            if (_private->currentDragAction == DragActionSelection) {
+                [self setNeedsDisplayInRect:_private->selectionRect];
+                // figure out what all was in that rect...
+                _private->selectionRect = NSZeroRect;
+            }
+            break;
+       default:
+            break;
+    }
+    _private->currentDragAction = DragActionNone;
+}
+
+- (void)disableMouseMovedEvents
+{
+    if ([[self window] acceptsMouseMovedEvents])
+        NSLog(@"Mouse move events now OFF");
+    [[self window] setAcceptsMouseMovedEvents:NO];
+}
+
+- (void)enableMouseMovedEventsIfNeeded
+{
+    // FIXME:  This could still be more efficient
+    BOOL needsMouseMoved = (_toolMode == DrawViewToolBrowse)
+    && [[_private document] documentListensForMouseMovedEvents];
+    if (needsMouseMoved != [[self window] acceptsMouseMovedEvents])
+        NSLog(@"Mouse move events now %@", needsMouseMoved ? @"ON" : @"OFF");
+    if (needsMouseMoved) {
+        [[self window] setAcceptsMouseMovedEvents:needsMouseMoved];
+    }
+}
+
+- (void)mouseEntered:(NSEvent *)theEvent
+{
+    [self enableMouseMovedEventsIfNeeded];
+}
+
+- (void)mouseExited:(NSEvent *)theEvent
+{
+    [self disableMouseMovedEvents];
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent
+{
+    //NSPoint mousePoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
+    
+    switch (_toolMode) {
+       case DrawViewToolBrowse:
+       {
+            if (![[_private document] documentListensForMouseMovedEvents])
+                return;
+            
+            NSCursor *cursor = [[_private document] cursorAfterPropagatingMouseMovedEvent:theEvent fromView:self];
+            if (cursor && (cursor != [NSCursor currentCursor])) NSLog(@"Changing cursor: %@ name: %@", cursor, [[cursor image] name]);
+            [cursor set];
+       }
+       default:
+            break;
+    }
+}
+
+- (void)keyDown:(NSEvent *)theEvent
+{
+    if (_toolMode == DrawViewToolArrow) {
+        unichar key = [[theEvent charactersIgnoringModifiers] characterAtIndex:0];
+        int flags = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+        if (([theEvent keyCode] == NSDeleteFunctionKey) || ((key == NSDeleteCharacter) && (flags == 0)) ) {
+            [self deleteSelection:nil];
+        }
+    } else if (_toolMode == DrawViewToolBrowse) {
+        // Propagate the key event up through the DOM
+    }
+}
+
+#pragma mark -
+#pragma mark Zoom/Pan support
+
+- (IBAction)zoomToFit:(id)sender
+{
+    NSSize canvasSize = [[_private document] canvasSize];
+    float widthScale = canvasSize.width / [self bounds].size.width;
+    float heightScale = canvasSize.height / [self bounds].size.height;
+    
+    float minScale = MAX(widthScale, heightScale);
+    [self setCanvasZoom:minScale];
+}
+
+- (void)updateCanvasScale
+{
+    if (_scaleRule == NSScaleProportionally) {
+        [self zoomToFit:nil];
+    } else if (_scaleRule == NSScaleToFit) {
+        // Not yet supported!
+    } else if (_scaleRule == NSScaleNone) {
+        [self setCanvasZoom:1.0];
+    }
+}
+
+- (void)sizeToFitCanvas
+{
+    NSSize canvasSize = [[_private document] canvasSize];
+    if ((canvasSize.width == 0) || (canvasSize.height == 0))
+        return; // avoid disappearing.
+    [self setFrameSize:canvasSize];
+}
+
+- (void)sizeToFitViewBox
+{
+    // FIXME: this is broken!
+    [self sizeToFitCanvas];
+}
+
+- (IBAction)zoomIn:(id)sender
+{
+    NSPoint center = [self canvasvisibleCenterPoint];
+    [self setCanvasZoom:([self canvasZoom] * 0.9)];
+    [self panToCanvasCenterPoint:center];
+}
+
+- (IBAction)zoomOut:(id)sender
+{
+    NSPoint center = [self canvasvisibleCenterPoint];
+    [self setCanvasZoom:([self canvasZoom] * 1.1)];
+    [self panToCanvasCenterPoint:center];
+}
+
+- (IBAction)zoomOriginal:(id)sender
+{
+    // do these need to call into the canvas or document instead?
+    [self setCanvasZoom:1.0];
+    [self setCanvasVisibleOrigin:NSMakePoint(0,0)];
+}
+
+- (CGAffineTransform)transformFromViewToCanvas
+{
+    float zoom = [self canvasZoom];
+    CGAffineTransform transform = CGAffineTransformMakeScale(zoom, zoom);
+    NSPoint origin = [self canvasVisibleOrigin];
+    return CGAffineTransformTranslate(transform,origin.x,origin.y);
+}
+
+- (NSPoint)mapViewPointToCanvas:(NSPoint)viewPoint
+{
+    CGPoint canvasPoint = CGPointApplyAffineTransform(*(CGPoint *)&viewPoint, [self transformFromViewToCanvas]);
+    return (*(NSPoint *)&canvasPoint);
+}
+- (NSRect)mapViewRectToCanvas:(NSRect)viewRect
+{
+    CGRect canvasRect = CGRectApplyAffineTransform(*(CGRect *)&viewRect, [self transformFromViewToCanvas]);
+    return (*(NSRect *)&canvasRect);
+}
+- (NSSize)mapViewSizeToCanvas:(NSSize)viewSize
+{
+    CGSize canvasSize = CGSizeApplyAffineTransform(*(CGSize *)&viewSize, [self transformFromViewToCanvas]);
+    return (*(NSSize *)&canvasSize);
+}
+
+- (NSPoint)mapCanvasPointToView:(NSPoint)canvasPoint
+{
+    CGPoint viewPoint = CGPointApplyAffineTransform(*(CGPoint *)&canvasPoint, CGAffineTransformInvert([self transformFromViewToCanvas]));
+    return (*(NSPoint *)&viewPoint);
+}
+- (NSRect)mapCanvasRectToView:(NSRect)canvasRect
+{
+    CGRect viewRect = CGRectApplyAffineTransform(*(CGRect *)&canvasRect, CGAffineTransformInvert([self transformFromViewToCanvas]));
+    return (*(NSRect *)&viewRect);
+}
+- (NSSize)mapCanvasSizeToView:(NSSize)canavsSize
+{
+    CGSize viewSize = CGSizeApplyAffineTransform(*(CGSize *)&canavsSize, CGAffineTransformInvert([self transformFromViewToCanvas]));
+    return (*(NSSize *)&viewSize);
+}
+#pragma mark -
+#pragma mark Canvas Zoom/Pan (Hack!)
+
+- (NSPoint)canvasVisibleOrigin
+{
+    return _private->canvasvisibleOrigin;
+}
+
+- (void)setCanvasVisibleOrigin:(NSPoint)newOrigin
+{
+    // will eventually move into NSScrollView I figure.
+    _private->canvasvisibleOrigin = newOrigin;
+    [self setNeedsDisplay:YES];
+}
+
+- (NSPoint)canvasvisibleCenterPoint
+{
+    NSPoint centerPoint = [self canvasVisibleOrigin];
+    NSSize canvasVisibleSize = [self mapViewSizeToCanvas:[self bounds].size];
+    centerPoint.x += canvasVisibleSize.width/2.f;
+    centerPoint.y += canvasVisibleSize.height/2.f;
+    // NSPoint cvo = [self canvasVisibleOrigin];
+    // NSLog(@"Visible center: %@  visible origin: %@  visible size: %@  farPoint: %@",
+    //         NSStringFromPoint(centerPoint), NSStringFromPoint(cvo),
+    //         NSStringFromSize(canvasVisibleSize), NSStringFromPoint(NSMakePoint(cvo.x + canvasVisibleSize.width, cvo.y + canvasVisibleSize.height)));
+    return centerPoint;
+}
+
+- (void)panToCanvasCenterPoint:(NSPoint)newCenter
+{
+    NSPoint newVisibleOrigin = newCenter;
+    NSSize canvasVisibleSize = [self mapViewSizeToCanvas:[self bounds].size];
+    newVisibleOrigin.x -= canvasVisibleSize.width/2.f;
+    newVisibleOrigin.y -= canvasVisibleSize.height/2.f;
+    // NSLog(@"setting new origin: %@  visible size: %@", NSStringFromPoint(newVisibleOrigin), NSStringFromSize(canvasVisibleSize));
+    [self setCanvasVisibleOrigin:newVisibleOrigin];
+} 
+
+- (float)canvasZoom
+{
+    return _private->canvasZoom;
+    //return [self scale].width;
+}
+
+- (void)setCanvasZoom:(float)newZoom
+{
+    if (_private->canvasZoom != newZoom) {
+        _private->canvasZoom = newZoom;
+        //[self setScale:NSMakeSize(newZoom, newZoom)];
+        [self setNeedsDisplay:YES];
+    }
+}
+
+@end
+
diff --git a/WebCore/WebCore+SVG/DrawViewPrivate.h b/WebCore/WebCore+SVG/DrawViewPrivate.h
new file mode 100644 (file)
index 0000000..d9a5929
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2005 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. 
+ */
+
+/*
+ WARNING: These files are temporary and exist solely for the purpose
+ of allowing greater testing of WebCore+SVG prior to full DOM integration.
+ Do NOT depend on these SPIs or files as they will soon be gone.
+*/
+
+#include <WebCore+SVG/DrawView.h>
+
+extern NSArray *DrawViewDragTypes;
+
+@interface DrawView (PrivateMethods)
+
+// For debuging (filter support is partially broken)
++ (void)setFilterSupportEnabled:(BOOL)enabled;
++ (BOOL)isFilterSupportEnabled;
+
+- (void)setBackgroundColor:(NSColor *)color;
+- (NSColor *)backgroundColor;
+
+// FIXME: should be Obj-C DOM objects, not render tree objects.
+- (NSArray *)selectedCanvasItems;
+
+// Zoom/Pan
+
+- (CGAffineTransform)transformFromViewToCanvas;
+
+- (NSPoint)mapViewPointToCanvas:(NSPoint)viewPoint;
+- (NSRect)mapViewRectToCanvas:(NSRect)viewRect;
+- (NSSize)mapViewSizeToCanvas:(NSSize)viewSize;
+- (NSPoint)mapCanvasPointToView:(NSPoint)canvasPoint;
+- (NSRect)mapCanvasRectToView:(NSRect)canvasRect;
+- (NSSize)mapCanvasSizeToView:(NSSize)viewSize;
+
+- (NSPoint)canvasVisibleOrigin;
+- (void)setCanvasVisibleOrigin:(NSPoint)newOrigin;
+
+- (NSPoint)canvasvisibleCenterPoint;
+- (void)panToCanvasCenterPoint:(NSPoint)newCenter;
+
+- (float)canvasZoom;
+- (void)setCanvasZoom:(float)newZoom;
+
+@end
diff --git a/WebCore/WebCore+SVG/NSSVGImageRep.h b/WebCore/WebCore+SVG/NSSVGImageRep.h
new file mode 100644 (file)
index 0000000..481846a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005 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. 
+ */
+
+/*
+ WARNING: These files are temporary and exist solely for the purpose
+ of allowing greater testing of WebCore+SVG prior to full DOM integration.
+ Do NOT depend on these SPIs or files as they will soon be gone.
+*/
+
+/*
+ NOTE: This specific file exists as a hack to allow WebKit (and the test 
+ apps which link against WebCore+SVG) to pass an SVG file to NSImage 
+ [NSImage imageWithContentsOfFile:]
+ and have NSImage be able to handle the SVG correctly.
+*/
+
+#import <Cocoa/Cocoa.h>
+
+@class DrawDocument;
+@class DrawView;
+
+@interface NSSVGImageRep : NSImageRep {
+    DrawDocument *_drawDocument;
+    DrawView *_view;
+    
+    NSBitmapImageRep *_cachedRepHack; // FIXME: total (temporary) HACK
+}
+
++ (id)imageRepWithData:(NSData *)svgData;
+- (id)initWithData:(NSData *)svgData;
+@end
diff --git a/WebCore/WebCore+SVG/NSSVGImageRep.m b/WebCore/WebCore+SVG/NSSVGImageRep.m
new file mode 100644 (file)
index 0000000..0de3492
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2005 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 "NSSVGImageRep.h"
+
+#import <WebCore+SVG/DrawDocumentPrivate.h>
+#import <WebCore+SVG/DrawView.h>
+
+static NSString *SVGDataPasteboardType = @"SVGDataPasteboardType";
+
+@implementation NSSVGImageRep
+
++ (void)load
+{
+    // Register this ImageRep subclass right when WebCore+SVG is loaded.
+    [NSImageRep registerImageRepClass:self];
+}
+
++ (BOOL)canInitWithData:(NSData *)data
+{
+    if (!data)
+        return NO;
+    
+    // This tests to see if the first 1k of the file has the string "svg"
+    // If it doesn't, we assume this is not an SVG file
+    // Clearly this doesn't work with svgz files.
+    int length = [data length];
+    if (length > 1024)
+        length = 1024;
+    NSString *testString = [[NSString alloc] initWithBytes:[data bytes] length:length encoding:NSUTF8StringEncoding];
+    NSRange range = [testString rangeOfString:@"svg" options:NSCaseInsensitiveSearch];
+    [testString release];
+    if ((range.location > 0) && (range.length == 3))
+        return YES;
+    
+    return NO;
+}
+
++ (BOOL)canInitWithPasteboard:(NSPasteboard *)pasteboard
+{
+    NSString *type = [pasteboard availableTypeFromArray:[self imageUnfilteredPasteboardTypes]];
+    if ([type isEqualToString:NSFilenamesPboardType]) {
+        NSArray *names = [pasteboard propertyListForType:NSFilenamesPboardType];
+        NSEnumerator *filenameEnumerator = [names objectEnumerator];
+        NSString *filename = nil;
+        while ((filename = [filenameEnumerator nextObject])) {
+            if ([[filename pathExtension] isEqualToString:@"svg"])
+                return YES;
+        }
+    }
+    return (type != nil);
+}
+
++ (NSArray *)imageUnfilteredFileTypes
+{
+    static NSArray *types = nil;
+    if (!types)
+        types = [[NSArray alloc]  initWithObjects:@"svg", nil];
+    return types;
+}
+
++ (NSArray *)imageUnfilteredPasteboardTypes
+{
+    static NSArray *types = nil;
+    if (!types)
+        types = [[NSArray alloc] initWithObjects:SVGDataPasteboardType, NSFilenamesPboardType, nil];
+    return types;
+}
+
+- (BOOL)draw
+{
+    NSLog(@"NSSVGImageRep draw");
+    return [_cachedRepHack draw];;
+}
+
+- (BOOL)drawAtPoint:(NSPoint)point
+{
+    NSLog(@"NSSVGImageRep drawAtPoint: %@", NSStringFromPoint(point));
+    return [_cachedRepHack drawAtPoint:point];
+}
+
+- (BOOL)drawInRect:(NSRect)rect
+{
+    NSLog(@"NSSVGImageRep drawInRect: %@", NSStringFromRect(rect));
+    return [_cachedRepHack drawInRect:rect];
+}
+
++ (id)imageRepWithData:(NSData *)svgData
+{
+    return [[[self alloc] initWithData:svgData] autorelease];
+}
+
+- (id)initWithData:(NSData *)svgData
+{
+    NSLog(@"NSSVGImageRep initWithData");
+    if ((self = [super init])) {
+        _drawDocument = [[DrawDocument alloc] initWithSVGData:svgData];
+        if (!_drawDocument) {
+            [self release];
+            return nil;
+        }
+        
+        [self setAlpha:YES];
+        //[self setBitsPerSample:32];
+        [self setColorSpaceName:NSCalibratedRGBColorSpace];
+        [self setOpaque:NO];
+        NSSize documentSize = [_drawDocument canvasSize];
+        [self setSize:documentSize];
+        [self setPixelsWide:(int)documentSize.width];
+        [self setPixelsHigh:(int)documentSize.height];
+        
+        _view = [[DrawView alloc] initWithFrame:NSMakeRect(0,0,documentSize.width,documentSize.width)];
+        [_view setDocument:_drawDocument];
+        [_view sizeToFitViewBox];
+        
+        // Drawing at other than 0,0, or at some zooms was not working correctly
+        // when I hacked this class together.  Hence the temporary
+        // "Convert to a NSBitmapImageRep and let it do everything" hack.
+        // This should be fixed once the rendering logic settles down a bit more.
+        // Currently drawing NSSVGImageReps at scaled sizes is very ugly as a result.
+        _cachedRepHack = [[_view bitmapImageRepForCachingDisplayInRect:[_view bounds]] retain];
+        [_view cacheDisplayInRect:[_view bounds] toBitmapImageRep:_cachedRepHack];
+    }
+    return self;
+}
+
+- (NSData *)representationUsingType:(NSBitmapImageFileType)storageType properties:(NSDictionary *)properties
+{
+    return [_cachedRepHack representationUsingType:storageType properties:properties];
+}
+
+- (void)setSize:(NSSize)newSize
+{
+    NSLog(@"NSSVGImageRep setSize:");
+    [super setSize:newSize];
+}
+
+@end