0e0ee6537206dd11d0bb81b048e56a1fd5250db3
[WebKit-https.git] / WebKit / WebView.subproj / WebPDFView.m
1 /*
2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #ifndef OMIT_TIGER_FEATURES
30
31 #import <WebKit/WebAssertions.h>
32 #import <WebKit/WebDataSource.h>
33 #import <WebKit/WebDocumentInternal.h>
34 #import <WebKit/WebFrame.h>
35 #import <WebKit/WebLocalizableStrings.h>
36 #import <WebKit/WebNSPasteboardExtras.h>
37 #import <WebKit/WebPDFView.h>
38 #import <WebKit/WebView.h>
39
40 #import <Quartz/Quartz.h>
41
42 // QuartzPrivate.h doesn't include the PDFKit private headers, so we can't get at PDFViewPriv.h. (3957971)
43 // Even if that was fixed, we'd have to tweak compile options to include QuartzPrivate.h. (3957839)
44
45 @interface PDFDocument (PDFKitSecretsIKnow)
46 - (NSPrintOperation *)getPrintOperationForPrintInfo:(NSPrintInfo *)printInfo autoRotate:(BOOL)doRotate;
47 @end
48
49 NSString *_NSPathForSystemFramework(NSString *framework);
50
51 @implementation WebPDFView
52
53 + (NSBundle *)PDFKitBundle
54 {
55     static NSBundle *PDFKitBundle = nil;
56     if (PDFKitBundle == nil) {
57         NSString *PDFKitPath = [_NSPathForSystemFramework(@"Quartz.framework") stringByAppendingString:@"/Frameworks/PDFKit.framework"];
58         if (PDFKitPath == nil) {
59             ERROR("Couldn't find PDFKit.framework");
60             return nil;
61         }
62         PDFKitBundle = [NSBundle bundleWithPath:PDFKitPath];
63         if (![PDFKitBundle load]) {
64             ERROR("Couldn't load PDFKit.framework");
65         }
66     }
67     return PDFKitBundle;
68 }
69
70 + (Class)PDFViewClass
71 {
72     static Class PDFViewClass = nil;
73     if (PDFViewClass == nil) {
74         PDFViewClass = [[WebPDFView PDFKitBundle] classNamed:@"PDFView"];
75         if (PDFViewClass == nil) {
76             ERROR("Couldn't find PDFView class in PDFKit.framework");
77         }
78     }
79     return PDFViewClass;
80 }
81
82 - (id)initWithFrame:(NSRect)frame
83 {
84     self = [super initWithFrame:frame];
85     if (self) {
86         [self setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
87         PDFSubview = [[[[self class] PDFViewClass] alloc] initWithFrame:frame];
88         [PDFSubview setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
89         [self addSubview:PDFSubview];
90         written = NO;
91     }
92     return self;
93 }
94
95 - (void)dealloc
96 {
97     [PDFSubview release];
98     [path release];
99     [super dealloc];
100 }
101
102 - (PDFView *)PDFSubview
103 {
104     return PDFSubview;
105 }
106
107 #define TEMP_PREFIX "/tmp/XXXXXX-"
108 #define OBJC_TEMP_PREFIX @"/tmp/XXXXXX-"
109
110 static void applicationInfoForMIMEType(NSString *type, NSString **name, NSImage **image)
111 {
112     NSURL *appURL = nil;
113     
114     OSStatus error = LSCopyApplicationForMIMEType((CFStringRef)type, kLSRolesAll, (CFURLRef *)&appURL);
115     if(error != noErr){
116         return;
117     }
118
119     NSString *appPath = [appURL path];
120     CFRelease (appURL);
121     
122     *image = [[NSWorkspace sharedWorkspace] iconForFile:appPath];  
123     [*image setSize:NSMakeSize(16.f,16.f)];  
124     
125     NSString *appName = [[NSFileManager defaultManager] displayNameAtPath:appPath];
126     *name = appName;
127 }
128
129
130 - (NSString *)path
131 {
132     // Generate path once.
133     if (path)
134         return path;
135         
136     NSString *filename = [[dataSource response] suggestedFilename];
137     NSFileManager *manager = [NSFileManager defaultManager];    
138     
139     path = [@"/tmp/" stringByAppendingPathComponent: filename];
140     if ([manager fileExistsAtPath:path]) {
141         path = [OBJC_TEMP_PREFIX stringByAppendingString:filename];
142         char *cpath = (char *)[path fileSystemRepresentation];
143         
144         int fd = mkstemps (cpath, strlen(cpath) - strlen(TEMP_PREFIX) + 1);
145         if (fd < 0) {
146             // Couldn't create a temporary file!  Should never happen.  Do
147             // we need an alert here?
148             path = nil;
149         }
150         else {
151             close (fd);
152             path = [manager stringWithFileSystemRepresentation:cpath length:strlen(cpath)];
153         }
154     }
155     
156     [path retain];
157     
158     return path;
159 }
160
161 - (NSView *)hitTest:(NSPoint)point
162 {
163     // Override hitTest so we can override menuForEvent.
164     NSEvent *event = [NSApp currentEvent];
165     NSEventType type = [event type];
166     if (type == NSRightMouseDown || (type == NSLeftMouseDown && ([event modifierFlags] & NSControlKeyMask))) {
167         return self;
168     }
169     return [super hitTest:point];
170 }
171
172 - (NSMenu *)menuForEvent:(NSEvent *)theEvent
173 {
174     NSMenu *menu = [PDFSubview menuForEvent:theEvent];
175     
176     NSString *appName = nil;
177     NSImage *appIcon = nil;
178     
179     applicationInfoForMIMEType([[dataSource response] MIMEType], &appName, &appIcon);
180     if (!appName)
181         appName = UI_STRING("Finder", "Default application name for Open With context menu");
182     
183     NSString *title = [NSString stringWithFormat:UI_STRING("Open with %@", "Open document using the Finder"), appName];
184     
185     NSMenuItem *item = [menu insertItemWithTitle:title action:@selector(openWithFinder:) keyEquivalent:@"" atIndex:0];
186     if (appIcon)
187         [item setImage:appIcon];
188         
189     [menu insertItem:[NSMenuItem separatorItem] atIndex:1];
190     
191     return menu;
192 }
193
194 - (void)_updateScalingToReflectTextSize
195 {
196     WebView *view = [[dataSource webFrame] webView];
197     
198     // The scale factor and text size multiplier conveniently use the same units, so we can just
199     // treat the values as interchangeable.
200     if (view != nil) {
201         [PDFSubview setScaleFactor:[view textSizeMultiplier]];          
202     }   
203 }
204
205 - (void)setDataSource:(WebDataSource *)ds
206 {
207     dataSource = ds;
208     [self setFrame:[[self superview] frame]];
209     [self _updateScalingToReflectTextSize];
210 }
211
212 - (void)dataSourceUpdated:(WebDataSource *)dataSource
213 {
214 }
215
216 - (void)setNeedsLayout:(BOOL)flag
217 {
218 }
219
220 - (void)layout
221 {
222 }
223
224 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
225 {
226 }
227
228 - (void)viewDidMoveToHostWindow
229 {
230 }
231
232 - (void)openWithFinder:(id)sender
233 {
234     NSString *opath = [self path];
235     
236     if (opath) {
237         if (!written) {
238             [[dataSource data] writeToFile:opath atomically:YES];
239             written = YES;
240         }
241     
242         if (![[NSWorkspace sharedWorkspace] openFile:opath]) {
243             // NSWorkspace couldn't open file.  Do we need an alert
244             // here?  We ignore the error elsewhere.
245         }
246     }
247 }
248
249 - (void)_web_textSizeMultiplierChanged
250 {
251     [self _updateScalingToReflectTextSize];
252 }
253
254 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag;
255 {
256     int options = 0;
257     if (!forward) {
258         options |= NSBackwardsSearch;
259     }
260     if (!caseFlag) {
261         options |= NSCaseInsensitiveSearch;
262     }
263     PDFDocument *document = [PDFSubview document];
264     PDFSelection *selection = [document findString:string fromSelection:[PDFSubview currentSelection] withOptions:options];
265     if (selection == nil && wrapFlag) {
266         selection = [document findString:string fromSelection:nil withOptions:options];
267     }
268     if (selection != nil) {
269         [PDFSubview setCurrentSelection:selection];
270         [PDFSubview scrollSelectionToVisible:nil];
271         return YES;
272     }
273     return NO;
274 }
275
276 - (void)takeFindStringFromSelection:(id)sender
277 {
278     [NSPasteboard _web_setFindPasteboardString:[[PDFSubview currentSelection] string] withOwner:self];
279 }
280
281 - (void)jumpToSelection:(id)sender
282 {
283     [PDFSubview scrollSelectionToVisible:nil];
284 }
285
286 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item 
287 {
288     SEL action = [item action];    
289     if (action == @selector(takeFindStringFromSelection:) || action == @selector(jumpToSelection:)) {
290         return [PDFSubview currentSelection] != nil;
291     }
292     return YES;
293 }
294
295 - (BOOL)canPrintHeadersAndFooters
296 {
297     return NO;
298 }
299
300 - (NSPrintOperation *)printOperationWithPrintInfo:(NSPrintInfo *)printInfo
301 {
302     return [[PDFSubview document] getPrintOperationForPrintInfo:printInfo autoRotate:YES];
303 }
304
305 @end
306
307 #endif // OMIT_TIGER_FEATURES