Reviewed by John.
[WebKit-https.git] / WebKit / WebView.subproj / WebImageView.m
1 /*      
2     WebImageView.m
3     Copyright 2002, Apple, Inc. All rights reserved.
4 */
5
6 #import <WebKit/WebImageView.h>
7
8 #import <WebKit/WebAssertions.h>
9 #import <WebKit/WebDataSource.h>
10 #import <WebKit/WebDocument.h>
11 #import <WebKit/WebFrameView.h>
12 #import <WebKit/WebImageRenderer.h>
13 #import <WebKit/WebImageRendererFactory.h>
14 #import <WebKit/WebImageRepresentation.h>
15 #import <WebKit/WebNSObjectExtras.h>
16 #import <WebKit/WebNSPasteboardExtras.h>
17 #import <WebKit/WebNSViewExtras.h>
18 #import <WebKit/WebViewPrivate.h>
19 #import <WebKit/WebUIDelegatePrivate.h>
20
21 #import <WebCore/WebCoreImageRenderer.h>
22
23 #import <Foundation/NSFileManager_NSURLExtras.h>
24
25 @implementation WebImageView
26
27 + (void)initialize
28 {
29     [NSApp registerServicesMenuSendTypes:[NSArray arrayWithObject:NSTIFFPboardType] returnTypes:nil];
30 }
31
32 + (NSArray *)supportedImageMIMETypes
33 {
34     static NSMutableArray *imageMIMETypes = nil;
35     if (imageMIMETypes == nil) {
36         imageMIMETypes = [[[WebImageRendererFactory sharedFactory] supportedMIMETypes] mutableCopy];
37         [imageMIMETypes removeObject:@"application/pdf"];
38         [imageMIMETypes removeObject:@"application/postscript"];
39     }
40     return imageMIMETypes;
41 }
42
43 - (id)initWithFrame:(NSRect)frame
44 {
45     self = [super initWithFrame:frame];
46     [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
47     return self;
48 }
49
50 - (void)dealloc
51 {
52     [[rep image] stopAnimation];
53     [rep release];
54     [mouseDownEvent release];
55     
56     [super dealloc];
57 }
58
59 - (void)finalize
60 {
61     [[rep image] stopAnimation];
62     [super finalize];
63 }
64
65 - (BOOL)haveCompleteImage
66 {
67     NSSize imageSize = [[rep image] size];
68     return [rep doneLoading] && imageSize.width > 0 && imageSize.width > 0;
69 }
70
71 - (BOOL)isFlipped 
72 {
73     return YES;
74 }
75
76 - (BOOL)acceptsFirstResponder
77 {
78     // Being first responder is useful for scrolling from the keyboard at least.
79     return YES;
80 }
81
82 - (NSRect)drawingRect
83 {
84     NSSize imageSize = [[rep image] size];
85     return NSMakeRect(0, 0, imageSize.width, imageSize.height);
86 }
87
88 - (void)drawRect:(NSRect)rect
89 {
90     if (needsLayout) {
91         [self layout];
92     }
93     
94     if ([[self _webView] drawsBackground]) {
95         [[NSColor whiteColor] set];
96         NSRectFill(rect);
97     }
98     
99     NSRect drawingRect = [self drawingRect];
100     [[rep image] drawImageInRect:drawingRect fromRect:drawingRect];
101 }
102
103 - (void)adjustFrameSize
104 {
105     NSSize size = [[rep image] size];
106     
107     // When drawing on screen, ensure that the view always fills the content area 
108     // (so we draw over the entire previous page), and that the view is at least 
109     // as large as the image.. Otherwise we're printing, and we want the image to 
110     // fill the view so that the printed size doesn't depend on the window size.
111     if ([NSGraphicsContext currentContextDrawingToScreen]) {
112         NSSize clipViewSize = [[self _web_superviewOfClass:[NSClipView class]] frame].size;
113         size.width = MAX(size.width, clipViewSize.width);
114         size.height = MAX(size.height, clipViewSize.height);
115     }
116     
117     [super setFrameSize:size];
118 }
119
120 - (void)setFrameSize:(NSSize)size
121 {
122     [self adjustFrameSize];
123 }
124
125 - (void)layout
126 {
127     [self adjustFrameSize];    
128     needsLayout = NO;
129 }
130
131 - (void)setDataSource:(WebDataSource *)dataSource
132 {
133     ASSERT(!rep);
134     rep = [[dataSource representation] retain];
135 }
136
137 - (void)dataSourceUpdated:(WebDataSource *)dataSource
138 {
139     NSSize imageSize = [[rep image] size];
140     if (imageSize.width > 0 && imageSize.height > 0) {
141         [self setNeedsLayout:YES];
142         [self setNeedsDisplay:YES];
143     }
144 }
145
146 - (void)setNeedsLayout: (BOOL)flag
147 {
148     needsLayout = flag;
149 }
150
151 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
152 {
153 }
154
155 - (void)viewDidMoveToHostWindow
156 {
157 }
158
159 - (void)viewDidMoveToWindow
160 {
161     if (![self window]){
162         [[rep image] stopAnimation];
163     }
164     
165     [super viewDidMoveToWindow];
166 }
167
168 - (WebView *)webView
169 {
170     return [self _web_parentWebView];
171 }
172
173 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
174 {
175     if ([item action] == @selector(copy:)){
176         return [self haveCompleteImage];
177     }
178
179     return YES;
180 }
181
182 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
183 {
184     if (sendType && [sendType isEqualToString:NSTIFFPboardType]){
185         return self;
186     }
187
188     return [super validRequestorForSendType:sendType returnType:returnType];
189 }
190
191 - (BOOL)writeImageToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
192 {    
193     if ([self haveCompleteImage]) {
194         [pasteboard _web_writeImage:[rep image] URL:[rep URL] title:nil archive:[rep archive] types:types];
195         return YES;
196     }
197     
198     return NO;
199 }
200
201 - (void)copy:(id)sender
202 {
203     [self writeImageToPasteboard:[NSPasteboard generalPasteboard] types:[NSPasteboard _web_writableTypesForImage]];
204 }
205
206 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
207 {
208     return [self writeImageToPasteboard:pasteboard types:types];
209 }
210
211 - (NSDictionary *)elementAtPoint:(NSPoint)point
212 {
213     WebFrame *frame = [[self _web_parentWebFrameView] webFrame];
214     ASSERT(frame);
215     
216     return [NSDictionary dictionaryWithObjectsAndKeys:
217         [rep image],                            WebElementImageKey,
218         [NSValue valueWithRect:[self bounds]],  WebElementImageRectKey,
219         [rep URL],                              WebElementImageURLKey,
220         [NSNumber numberWithBool:NO],           WebElementIsSelectedKey,
221         frame,                                  WebElementFrameKey, nil];
222 }
223
224 - (NSMenu *)menuForEvent:(NSEvent *)theEvent
225 {
226     WebView *webView = [self webView];
227     ASSERT(webView);
228     return [webView _menuForElement:[self elementAtPoint:NSZeroPoint]];
229 }
230
231 - (void)mouseDown:(NSEvent *)event
232 {
233     ignoringMouseDraggedEvents = NO;
234     [mouseDownEvent release];
235     mouseDownEvent = [event retain];
236     
237     WebView *webView = [self webView];
238     NSPoint point = [webView convertPoint:[mouseDownEvent locationInWindow] fromView:nil];
239     dragSourceActionMask = [[webView _UIDelegateForwarder] webView:webView dragSourceActionMaskForPoint:point];
240     
241     [super mouseDown:event];
242 }
243
244 - (void)mouseDragged:(NSEvent *)mouseDraggedEvent
245 {
246     if (ignoringMouseDraggedEvents || ![self haveCompleteImage] || !(dragSourceActionMask & WebDragSourceActionImage)) {
247         return;
248     }
249     
250     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
251     id source = [pasteboard _web_declareAndWriteDragImage:[rep image]
252                                                       URL:[rep URL]
253                                                     title:nil
254                                                   archive:[rep archive]
255                                                    source:self];
256     
257     WebView *webView = [self webView];
258     NSPoint point = [webView convertPoint:[mouseDownEvent locationInWindow] fromView:nil];
259     [[webView _UIDelegateForwarder] webView:webView willPerformDragSourceAction:WebDragSourceActionImage fromPoint:point withPasteboard:pasteboard];
260     
261     [[self webView] _setInitiatedDrag:YES];
262     
263     // Retain this view during the drag because it may be released before the drag ends.
264     [self retain];
265     
266     [self _web_dragImage:[rep image]
267                     rect:[self drawingRect]
268                    event:mouseDraggedEvent
269               pasteboard:pasteboard
270                   source:source
271                   offset:NULL];
272 }
273
274 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
275 {
276     // FIXME: Report an error if we fail to create a file.
277     NSString *path = [[dropDestination path] stringByAppendingPathComponent:[rep filename]];
278     path = [[NSFileManager defaultManager] _web_pathWithUniqueFilenameForPath:path];
279     [[rep data] writeToFile:path atomically:NO];
280     return [NSArray arrayWithObject:[path lastPathComponent]];
281 }
282
283 - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
284 {
285     // Prevent queued mouseDragged events from coming after the drag which can cause a double drag.
286     ignoringMouseDraggedEvents = YES;
287     
288     [[self webView] _setInitiatedDrag:NO];
289
290     // Balance the previous retain from when the drag started.
291     [self release];
292 }
293
294 - (NSImage *)image
295 {
296     return [[rep image] image];
297 }
298
299 #pragma mark PRINTING
300
301 - (void)drawPageBorderWithSize:(NSSize)borderSize
302 {
303     ASSERT(NSEqualSizes(borderSize, [[[NSPrintOperation currentOperation] printInfo] paperSize]));
304     // FIXME: How to determine the number of pages required to print the whole image?
305     [[self webView] _drawHeaderAndFooter];
306 }
307
308 - (void)beginDocument
309 {
310     [self adjustFrameSize];
311     [[self webView] _adjustPrintingMarginsForHeaderAndFooter];
312     [super beginDocument];
313 }
314
315 - (void)endDocument
316 {
317     [super endDocument];
318     [self adjustFrameSize];
319 }
320
321 - (BOOL)canPrintHeadersAndFooters
322 {
323     return YES;
324 }
325
326 @end