initial import
[vuplus_webkit] / Source / WebKit2 / UIProcess / API / mac / PDFViewController.mm
1 /*
2  * Copyright (C) 2010, 2011 Apple 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "PDFViewController.h"
28
29 #import "DataReference.h"
30 #import "WKAPICast.h"
31 #import "WKView.h"
32 #import "WebData.h"
33 #import "WebEventFactory.h"
34 #import "WebPageGroup.h"
35 #import "WebPageProxy.h"
36 #import "WebPreferences.h"
37 #import <PDFKit/PDFKit.h>
38 #import <WebCore/LocalizedStrings.h>
39 #import <wtf/text/CString.h>
40 #import <wtf/text/WTFString.h>
41
42 // Redeclarations of PDFKit notifications. We can't use the API since we use a weak link to the framework.
43 #define _webkit_PDFViewDisplayModeChangedNotification @"PDFViewDisplayModeChanged"
44 #define _webkit_PDFViewScaleChangedNotification @"PDFViewScaleChanged"
45 #define _webkit_PDFViewPageChangedNotification @"PDFViewChangedPage"
46
47 using namespace WebKit;
48
49 @class PDFDocument;
50 @class PDFView;
51
52 @interface PDFDocument (PDFDocumentDetails)
53 - (NSPrintOperation *)getPrintOperationForPrintInfo:(NSPrintInfo *)printInfo autoRotate:(BOOL)doRotate;
54 @end
55
56 extern "C" NSString *_NSPathForSystemFramework(NSString *framework);
57
58 // MARK: C UTILITY FUNCTIONS
59
60 static void _applicationInfoForMIMEType(NSString *type, NSString **name, NSImage **image)
61 {
62     ASSERT(name);
63     ASSERT(image);
64     
65     CFURLRef appURL = 0;
66
67     OSStatus error = LSCopyApplicationForMIMEType((CFStringRef)type, kLSRolesAll, &appURL);
68     if (error != noErr)
69         return;
70
71     NSString *appPath = [(NSURL *)appURL path];
72     if (appURL)
73         CFRelease(appURL);
74
75     *image = [[NSWorkspace sharedWorkspace] iconForFile:appPath];
76     [*image setSize:NSMakeSize(16, 16)];
77
78     *name = [[NSFileManager defaultManager] displayNameAtPath:appPath];
79 }
80
81 // FIXME 4182876: We can eliminate this function in favor if -isEqual: if [PDFSelection isEqual:] is overridden
82 // to compare contents.
83 static BOOL _PDFSelectionsAreEqual(PDFSelection *selectionA, PDFSelection *selectionB)
84 {
85     NSArray *aPages = [selectionA pages];
86     NSArray *bPages = [selectionB pages];
87
88     if (![aPages isEqual:bPages])
89         return NO;
90
91     NSUInteger count = [aPages count];
92     for (NSUInteger i = 0; i < count; ++i) {
93         NSRect aBounds = [selectionA boundsForPage:[aPages objectAtIndex:i]];
94         NSRect bBounds = [selectionB boundsForPage:[bPages objectAtIndex:i]];
95         if (!NSEqualRects(aBounds, bBounds))
96             return NO;
97     }
98
99     return YES;
100 }
101
102 @interface WKPDFView : NSView
103 {
104     PDFViewController* _pdfViewController;
105
106     RetainPtr<NSView> _pdfPreviewView;
107     PDFView *_pdfView;
108     BOOL _ignoreScaleAndDisplayModeAndPageNotifications;
109     BOOL _willUpdatePreferencesSoon;
110 }
111
112 - (id)initWithFrame:(NSRect)frame PDFViewController:(PDFViewController*)pdfViewController;
113 - (void)invalidate;
114 - (PDFView *)pdfView;
115 - (void)setDocument:(PDFDocument *)pdfDocument;
116
117 - (void)_applyPDFPreferences;
118 - (PDFSelection *)_nextMatchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag fromSelection:(PDFSelection *)initialSelection startInSelection:(BOOL)startInSelection;
119 @end
120
121 @implementation WKPDFView
122
123 - (id)initWithFrame:(NSRect)frame PDFViewController:(PDFViewController*)pdfViewController
124 {
125     if ((self = [super initWithFrame:frame])) {
126         _pdfViewController = pdfViewController;
127
128         [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
129
130         Class previewViewClass = PDFViewController::pdfPreviewViewClass();
131         ASSERT(previewViewClass);
132
133         _pdfPreviewView.adoptNS([[previewViewClass alloc] initWithFrame:frame]);
134         [_pdfPreviewView.get() setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
135         [self addSubview:_pdfPreviewView.get()];
136
137         _pdfView = [_pdfPreviewView.get() performSelector:@selector(pdfView)];
138         [_pdfView setDelegate:self];
139     }
140
141     return self;
142 }
143
144 - (void)invalidate
145 {
146     _pdfViewController = 0;
147 }
148
149 - (PDFView *)pdfView
150 {
151     return _pdfView;
152 }
153
154 - (void)setDocument:(PDFDocument *)pdfDocument
155 {
156     _ignoreScaleAndDisplayModeAndPageNotifications = YES;
157     [_pdfView setDocument:pdfDocument];
158     [self _applyPDFPreferences];
159     _ignoreScaleAndDisplayModeAndPageNotifications = NO;
160 }
161
162 - (void)_applyPDFPreferences
163 {
164     if (!_pdfViewController)
165         return;
166
167     WebPreferences *preferences = _pdfViewController->page()->pageGroup()->preferences();
168
169     CGFloat scaleFactor = preferences->pdfScaleFactor();
170     if (!scaleFactor)
171         [_pdfView setAutoScales:YES];
172     else {
173         [_pdfView setAutoScales:NO];
174         [_pdfView setScaleFactor:scaleFactor];
175     }
176     [_pdfView setDisplayMode:preferences->pdfDisplayMode()];
177 }
178
179 - (void)_updatePreferences:(id)ignored
180 {
181     _willUpdatePreferencesSoon = NO;
182
183     if (!_pdfViewController)
184         return;
185
186     WebPreferences* preferences = _pdfViewController->page()->pageGroup()->preferences();
187
188     CGFloat scaleFactor = [_pdfView autoScales] ? 0 : [_pdfView scaleFactor];
189     preferences->setPDFScaleFactor(scaleFactor);
190     preferences->setPDFDisplayMode([_pdfView displayMode]);
191 }
192
193 - (void)_updatePreferencesSoon
194 {   
195     if (_willUpdatePreferencesSoon)
196         return;
197
198     [self performSelector:@selector(_updatePreferences:) withObject:nil afterDelay:0];
199     _willUpdatePreferencesSoon = YES;
200 }
201
202 - (void)_scaleOrDisplayModeOrPageChanged:(NSNotification *)notification
203 {
204     ASSERT_ARG(notification, [notification object] == _pdfView);
205     if (!_ignoreScaleAndDisplayModeAndPageNotifications)
206         [self _updatePreferencesSoon];
207 }
208
209 - (void)_openWithFinder:(id)sender
210 {
211     _pdfViewController->openPDFInFinder();
212 }
213
214 - (PDFSelection *)_nextMatchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag fromSelection:(PDFSelection *)initialSelection startInSelection:(BOOL)startInSelection
215 {
216     if (![string length])
217         return nil;
218
219     int options = 0;
220     if (!forward)
221         options |= NSBackwardsSearch;
222
223     if (!caseFlag)
224         options |= NSCaseInsensitiveSearch;
225
226     PDFDocument *document = [_pdfView document];
227
228     PDFSelection *selectionForInitialSearch = [initialSelection copy];
229     if (startInSelection) {
230         // Initially we want to include the selected text in the search.  So we must modify the starting search 
231         // selection to fit PDFDocument's search requirements: selection must have a length >= 1, begin before 
232         // the current selection (if searching forwards) or after (if searching backwards).
233         int initialSelectionLength = [[initialSelection string] length];
234         if (forward) {
235             [selectionForInitialSearch extendSelectionAtStart:1];
236             [selectionForInitialSearch extendSelectionAtEnd:-initialSelectionLength];
237         } else {
238             [selectionForInitialSearch extendSelectionAtEnd:1];
239             [selectionForInitialSearch extendSelectionAtStart:-initialSelectionLength];
240         }
241     }
242     PDFSelection *foundSelection = [document findString:string fromSelection:selectionForInitialSearch withOptions:options];
243     [selectionForInitialSearch release];
244
245     // If we first searched in the selection, and we found the selection, search again from just past the selection
246     if (startInSelection && _PDFSelectionsAreEqual(foundSelection, initialSelection))
247         foundSelection = [document findString:string fromSelection:initialSelection withOptions:options];
248
249     if (!foundSelection && wrapFlag)
250         foundSelection = [document findString:string fromSelection:nil withOptions:options];
251
252     return foundSelection;
253 }
254
255 - (NSUInteger)_countMatches:(NSString *)string caseSensitive:(BOOL)caseFlag
256 {
257     if (![string length])
258         return 0;
259
260     int options = caseFlag ? 0 : NSCaseInsensitiveSearch;
261
262     return [[[_pdfView document] findString:string withOptions:options] count];
263 }
264
265 // MARK: NSView overrides
266
267 - (void)viewDidMoveToWindow
268 {
269     if (![self window])
270         return;
271
272     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
273     [notificationCenter addObserver:self selector:@selector(_scaleOrDisplayModeOrPageChanged:) name:_webkit_PDFViewScaleChangedNotification object:_pdfView];
274     [notificationCenter addObserver:self selector:@selector(_scaleOrDisplayModeOrPageChanged:) name:_webkit_PDFViewDisplayModeChangedNotification object:_pdfView];
275     [notificationCenter addObserver:self selector:@selector(_scaleOrDisplayModeOrPageChanged:) name:_webkit_PDFViewPageChangedNotification object:_pdfView];
276 }
277
278 - (void)viewWillMoveToWindow:(NSWindow *)newWindow
279 {
280     if (![self window])
281         return;
282
283     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
284     [notificationCenter removeObserver:self name:_webkit_PDFViewScaleChangedNotification object:_pdfView];
285     [notificationCenter removeObserver:self name:_webkit_PDFViewDisplayModeChangedNotification object:_pdfView];
286     [notificationCenter removeObserver:self name:_webkit_PDFViewPageChangedNotification object:_pdfView];
287 }
288
289 - (NSView *)hitTest:(NSPoint)point
290 {
291     // Override hitTest so we can override menuForEvent.
292     NSEvent *event = [NSApp currentEvent];
293     NSEventType type = [event type];
294     if (type == NSRightMouseDown || (type == NSLeftMouseDown && ([event modifierFlags] & NSControlKeyMask)))
295         return self;
296
297     return [super hitTest:point];
298 }
299
300 - (NSMenu *)menuForEvent:(NSEvent *)theEvent
301 {
302     NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
303
304     NSEnumerator *menuItemEnumerator = [[[_pdfView menuForEvent:theEvent] itemArray] objectEnumerator];
305     while (NSMenuItem *item = [menuItemEnumerator nextObject]) {
306         NSMenuItem *itemCopy = [item copy];
307         [menu addItem:itemCopy];
308         [itemCopy release];
309
310         if ([item action] != @selector(copy:))
311             continue;
312
313         // Add in an "Open with <default PDF viewer>" item
314         NSString *appName = nil;
315         NSImage *appIcon = nil;
316
317         _applicationInfoForMIMEType(@"application/pdf", &appName, &appIcon);
318         if (!appName)
319             appName = WEB_UI_STRING("Finder", "Default application name for Open With context menu");
320
321         // To match the PDFKit style, we'll add Open with Preview even when there's no document yet to view, and
322         // disable it using validateUserInterfaceItem.
323         NSString *title = [NSString stringWithFormat:WEB_UI_STRING("Open with %@", "context menu item for PDF"), appName];
324
325         item = [[NSMenuItem alloc] initWithTitle:title action:@selector(_openWithFinder:) keyEquivalent:@""];
326         if (appIcon)
327             [item setImage:appIcon];
328         [menu addItem:[NSMenuItem separatorItem]];
329         [menu addItem:item];
330         [item release];
331     }
332
333     return [menu autorelease];
334 }
335
336 // MARK: NSUserInterfaceValidations PROTOCOL IMPLEMENTATION
337
338 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
339 {
340     SEL action = [item action];
341     if (action == @selector(_openWithFinder:))
342         return [_pdfView document] != nil;
343     return YES;
344 }
345
346 // MARK: PDFView delegate methods
347
348 - (void)PDFViewWillClickOnLink:(PDFView *)sender withURL:(NSURL *)URL
349 {
350     _pdfViewController->linkClicked([URL absoluteString]);
351 }
352
353 - (void)PDFViewOpenPDFInNativeApplication:(PDFView *)sender
354 {
355     _pdfViewController->openPDFInFinder();
356 }
357
358 - (void)PDFViewSavePDFToDownloadFolder:(PDFView *)sender
359 {
360     _pdfViewController->savePDFToDownloadsFolder();
361 }
362
363 @end
364
365 namespace WebKit {
366
367 PassOwnPtr<PDFViewController> PDFViewController::create(WKView *wkView)
368 {
369     return adoptPtr(new PDFViewController(wkView));
370 }
371
372 PDFViewController::PDFViewController(WKView *wkView)
373     : m_wkView(wkView)
374     , m_wkPDFView(AdoptNS, [[WKPDFView alloc] initWithFrame:[m_wkView bounds] PDFViewController:this])
375     , m_pdfView([m_wkPDFView.get() pdfView])
376     , m_hasWrittenPDFToDisk(false)
377 {
378     [m_wkView addSubview:m_wkPDFView.get()];
379 }
380
381 PDFViewController::~PDFViewController()
382 {
383     [m_wkPDFView.get() removeFromSuperview];
384     [m_wkPDFView.get() invalidate];
385     m_wkPDFView = nullptr;
386 }
387
388 WebPageProxy* PDFViewController::page() const
389 {
390     return toImpl([m_wkView pageRef]);
391 }
392
393 NSView* PDFViewController::pdfView() const
394
395     return m_wkPDFView.get(); 
396 }
397     
398 static RetainPtr<CFDataRef> convertPostScriptDataSourceToPDF(const CoreIPC::DataReference& dataReference)
399 {
400     // Convert PostScript to PDF using Quartz 2D API
401     // http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_ps_convert/chapter_16_section_1.html
402     
403     CGPSConverterCallbacks callbacks = { 0, 0, 0, 0, 0, 0, 0, 0 };    
404     RetainPtr<CGPSConverterRef> converter(AdoptCF, CGPSConverterCreate(0, &callbacks, 0));
405     ASSERT(converter);
406
407     RetainPtr<NSData> nsData(AdoptNS, [[NSData alloc] initWithBytesNoCopy:const_cast<uint8_t*>(dataReference.data()) length:dataReference.size() freeWhenDone:NO]);   
408
409     RetainPtr<CGDataProviderRef> provider(AdoptCF, CGDataProviderCreateWithCFData((CFDataRef)nsData.get()));
410     ASSERT(provider);
411
412     RetainPtr<CFMutableDataRef> result(AdoptCF, CFDataCreateMutable(kCFAllocatorDefault, 0));
413     ASSERT(result);
414     
415     RetainPtr<CGDataConsumerRef> consumer(AdoptCF, CGDataConsumerCreateWithCFData(result.get()));
416     ASSERT(consumer);
417     
418     CGPSConverterConvert(converter.get(), provider.get(), consumer.get(), 0);
419
420     if (!result)
421         return 0;
422
423     return result;
424 }
425
426 void PDFViewController::setPDFDocumentData(const String& mimeType, const String& suggestedFilename, const CoreIPC::DataReference& dataReference)
427 {
428     if (equalIgnoringCase(mimeType, "application/postscript")) {
429         m_pdfData = convertPostScriptDataSourceToPDF(dataReference);
430         if (!m_pdfData)
431             return;
432     } else {
433         // Make sure to copy the data.
434         m_pdfData.adoptCF(CFDataCreate(0, dataReference.data(), dataReference.size()));
435     }
436
437     m_suggestedFilename = suggestedFilename;
438
439     RetainPtr<PDFDocument> pdfDocument(AdoptNS, [[pdfDocumentClass() alloc] initWithData:(NSData *)m_pdfData.get()]);
440     [m_wkPDFView.get() setDocument:pdfDocument.get()];
441 }
442
443 double PDFViewController::zoomFactor() const
444 {
445     return [m_pdfView scaleFactor];
446 }
447
448 void PDFViewController::setZoomFactor(double zoomFactor)
449 {
450     [m_pdfView setScaleFactor:zoomFactor];
451 }
452
453 Class PDFViewController::pdfDocumentClass()
454 {
455     static Class pdfDocumentClass = [pdfKitBundle() classNamed:@"PDFDocument"];
456     
457     return pdfDocumentClass;
458 }
459
460 Class PDFViewController::pdfPreviewViewClass()
461 {
462     static Class pdfPreviewViewClass = [pdfKitBundle() classNamed:@"PDFPreviewView"];
463     
464     return pdfPreviewViewClass;
465 }
466     
467 NSBundle* PDFViewController::pdfKitBundle()
468 {
469     static NSBundle *pdfKitBundle;
470     if (pdfKitBundle)
471         return pdfKitBundle;
472
473     NSString *pdfKitPath = [_NSPathForSystemFramework(@"Quartz.framework") stringByAppendingString:@"/Frameworks/PDFKit.framework"];
474     if (!pdfKitPath) {
475         LOG_ERROR("Couldn't find PDFKit.framework");
476         return nil;
477     }
478
479     pdfKitBundle = [NSBundle bundleWithPath:pdfKitPath];
480     if (![pdfKitBundle load])
481         LOG_ERROR("Couldn't load PDFKit.framework");
482     return pdfKitBundle;
483 }
484
485 NSPrintOperation *PDFViewController::makePrintOperation(NSPrintInfo *printInfo)
486 {
487     return [[m_pdfView document] getPrintOperationForPrintInfo:printInfo autoRotate:YES];
488 }
489
490 void PDFViewController::openPDFInFinder()
491 {
492     // We don't want to open the PDF until we have a document to write. (see 4892525).
493     if (![m_pdfView document]) {
494         NSBeep();
495         return;
496     }
497
498     NSString *path = pathToPDFOnDisk();
499     if (!path)
500         return;
501
502     if (!m_hasWrittenPDFToDisk) {
503         // Create a PDF file with the minimal permissions (only accessible to the current user, see 4145714).
504         RetainPtr<NSNumber> permissions(AdoptNS, [[NSNumber alloc] initWithInt:S_IRUSR]);
505         RetainPtr<NSDictionary> fileAttributes(AdoptNS, [[NSDictionary alloc] initWithObjectsAndKeys:permissions.get(), NSFilePosixPermissions, nil]);
506
507         if (![[NSFileManager defaultManager] createFileAtPath:path contents:(NSData *)m_pdfData.get() attributes:fileAttributes.get()])
508             return;
509
510         m_hasWrittenPDFToDisk = true;
511     }
512
513     [[NSWorkspace sharedWorkspace] openFile:path];
514 }
515
516 static void releaseCFData(unsigned char*, const void* data)
517 {
518     ASSERT(CFGetTypeID(data) == CFDataGetTypeID());
519
520     // Balanced by CFRetain in savePDFToDownloadsFolder.
521     CFRelease(data);
522 }
523
524 void PDFViewController::savePDFToDownloadsFolder()
525 {
526     // We don't want to write the file until we have a document to write. (see 5267607).
527     if (![m_pdfView document]) {
528         NSBeep();
529         return;
530     }
531
532     ASSERT(m_pdfData);
533
534     // Balanced by CFRelease in releaseCFData.
535     CFRetain(m_pdfData.get());
536
537     RefPtr<WebData> data = WebData::createWithoutCopying(CFDataGetBytePtr(m_pdfData.get()), CFDataGetLength(m_pdfData.get()), releaseCFData, m_pdfData.get());
538
539     page()->saveDataToFileInDownloadsFolder(m_suggestedFilename.get(), page()->mainFrame()->mimeType(), page()->mainFrame()->url(), data.get());
540 }
541
542 static NSString *temporaryPDFDirectoryPath()
543 {
544     static NSString *temporaryPDFDirectoryPath;
545
546     if (!temporaryPDFDirectoryPath) {
547         NSString *temporaryDirectoryTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"WebKitPDFs-XXXXXX"];
548         CString templateRepresentation = [temporaryDirectoryTemplate fileSystemRepresentation];
549
550         if (mkdtemp(templateRepresentation.mutableData()))
551             temporaryPDFDirectoryPath = [[[NSFileManager defaultManager] stringWithFileSystemRepresentation:templateRepresentation.data() length:templateRepresentation.length()] copy];
552     }
553
554     return temporaryPDFDirectoryPath;
555 }
556
557 NSString *PDFViewController::pathToPDFOnDisk()
558 {
559     if (m_pathToPDFOnDisk)
560         return m_pathToPDFOnDisk.get();
561
562     NSString *pdfDirectoryPath = temporaryPDFDirectoryPath();
563     if (!pdfDirectoryPath)
564         return nil;
565
566     NSString *path = [pdfDirectoryPath stringByAppendingPathComponent:m_suggestedFilename.get()];
567
568     NSFileManager *fileManager = [NSFileManager defaultManager];
569     if ([fileManager fileExistsAtPath:path]) {
570         NSString *pathTemplatePrefix = [pdfDirectoryPath stringByAppendingString:@"XXXXXX-"];
571         NSString *pathTemplate = [pathTemplatePrefix stringByAppendingPathComponent:m_suggestedFilename.get()];
572         CString pathTemplateRepresentation = [pathTemplate fileSystemRepresentation];
573
574         int fd = mkstemps(pathTemplateRepresentation.mutableData(), pathTemplateRepresentation.length() - strlen([pathTemplatePrefix fileSystemRepresentation]) + 1);
575         if (fd < 0)
576             return nil;
577
578         close(fd);
579         path = [fileManager stringWithFileSystemRepresentation:pathTemplateRepresentation.data() length:pathTemplateRepresentation.length()];
580     }
581
582     m_pathToPDFOnDisk.adoptNS([path copy]);
583     return path;
584 }
585
586 void PDFViewController::linkClicked(const String& url)
587 {
588     NSEvent* nsEvent = [NSApp currentEvent];
589     WebMouseEvent event;
590     switch ([nsEvent type]) {
591     case NSLeftMouseUp:
592     case NSRightMouseUp:
593     case NSOtherMouseUp:
594         event = WebEventFactory::createWebMouseEvent(nsEvent, m_pdfView);
595     default:
596         // For non mouse-clicks or for keyboard events, pass an empty WebMouseEvent
597         // through.  The event is only used by the WebFrameLoaderClient to determine
598         // the modifier keys and which mouse button is down.  These queries will be
599         // valid with an empty event.
600         break;
601     }
602     
603     page()->linkClicked(url, event);
604 }
605
606 void PDFViewController::findString(const String& string, FindOptions options, unsigned maxMatchCount)
607 {
608     BOOL forward = !(options & FindOptionsBackwards);
609     BOOL caseFlag = !(options & FindOptionsCaseInsensitive);
610     BOOL wrapFlag = options & FindOptionsWrapAround;
611
612     PDFSelection *selection = [m_wkPDFView.get() _nextMatchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag fromSelection:[m_pdfView currentSelection] startInSelection:NO];
613     if (!selection) {
614         page()->didFailToFindString(string);
615         return;
616     }
617
618     NSUInteger matchCount;
619     if (!maxMatchCount) {
620         // If the max was zero, any result means we exceeded the max. We can skip computing the actual count.
621         matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount);
622     } else {
623         matchCount = [m_wkPDFView.get() _countMatches:string caseSensitive:caseFlag];
624         if (matchCount > maxMatchCount)
625             matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount);
626     }
627
628     [m_pdfView setCurrentSelection:selection];
629     [m_pdfView scrollSelectionToVisible:nil];
630     page()->didFindString(string, matchCount);
631 }
632
633 void PDFViewController::countStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
634 {
635     BOOL caseFlag = !(options & FindOptionsCaseInsensitive);
636
637     NSUInteger matchCount = [m_wkPDFView.get() _countMatches:string caseSensitive:caseFlag];
638     if (matchCount > maxMatchCount)
639         matchCount = maxMatchCount;
640     page()->didCountStringMatches(string, matchCount);
641 }
642
643 } // namespace WebKit