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