[WTF] Move currentCPUTime and sleep(Seconds) to CPUTime.h and Seconds.h respectively
[WebKit-https.git] / Source / WebKit / WebProcess / Plugins / PDF / PDFPlugin.mm
1 /*
2  * Copyright (C) 2009-2017 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 "PDFPlugin.h"
28
29 #if ENABLE(PDFKIT_PLUGIN)
30
31 #import "ArgumentCoders.h"
32 #import "DataReference.h"
33 #import "PDFAnnotationTextWidgetDetails.h"
34 #import "PDFLayerControllerSPI.h"
35 #import "PDFPluginAnnotation.h"
36 #import "PDFPluginPasswordField.h"
37 #import "PluginView.h"
38 #import "WKAccessibilityWebPageObjectMac.h"
39 #import "WKPageFindMatchesClient.h"
40 #import "WebCoreArgumentCoders.h"
41 #import "WebEvent.h"
42 #import "WebEventConversion.h"
43 #import "WebFindOptions.h"
44 #import "WebPage.h"
45 #import "WebPageProxyMessages.h"
46 #import "WebPasteboardProxyMessages.h"
47 #import "WebProcess.h"
48 #import <JavaScriptCore/JSContextRef.h>
49 #import <JavaScriptCore/JSObjectRef.h>
50 #import <JavaScriptCore/JSStringRef.h>
51 #import <JavaScriptCore/JSStringRefCF.h>
52 #import <PDFKit/PDFKit.h>
53 #import <QuartzCore/QuartzCore.h>
54 #import <WebCore/AXObjectCache.h>
55 #import <WebCore/ArchiveResource.h>
56 #import <WebCore/Chrome.h>
57 #import <WebCore/Cursor.h>
58 #import <WebCore/DictionaryLookup.h>
59 #import <WebCore/DocumentLoader.h>
60 #import <WebCore/EventNames.h>
61 #import <WebCore/FocusController.h>
62 #import <WebCore/FormState.h>
63 #import <WebCore/Frame.h>
64 #import <WebCore/FrameLoader.h>
65 #import <WebCore/FrameView.h>
66 #import <WebCore/GraphicsContext.h>
67 #import <WebCore/HTMLElement.h>
68 #import <WebCore/HTMLFormElement.h>
69 #import <WebCore/HTMLPlugInElement.h>
70 #import <WebCore/LegacyNSPasteboardTypes.h>
71 #import <WebCore/LocalizedStrings.h>
72 #import <WebCore/MainFrame.h>
73 #import <WebCore/MouseEvent.h>
74 #import <WebCore/PDFDocumentImage.h>
75 #import <WebCore/Page.h>
76 #import <WebCore/Pasteboard.h>
77 #import <WebCore/PluginData.h>
78 #import <WebCore/PluginDocument.h>
79 #import <WebCore/RenderBoxModelObject.h>
80 #import <WebCore/ScrollAnimator.h>
81 #import <WebCore/ScrollbarTheme.h>
82 #import <WebCore/Settings.h>
83 #import <WebCore/WheelEventTestTrigger.h>
84 #import <pal/spi/cg/CoreGraphicsSPI.h>
85 #import <pal/spi/mac/NSMenuSPI.h>
86 #import <wtf/UUID.h>
87
88 using namespace WebCore;
89
90 // Set overflow: hidden on the annotation container so <input> elements scrolled out of view don't show
91 // scrollbars on the body. We can't add annotations directly to the body, because overflow: hidden on the body
92 // will break rubber-banding.
93 static const char* annotationStyle =
94 "#annotationContainer {"
95 "    overflow: hidden; "
96 "    position: absolute; "
97 "    pointer-events: none; "
98 "    top: 0; "
99 "    left: 0; "
100 "    right: 0; "
101 "    bottom: 0; "
102 "    display: -webkit-box; "
103 "    -webkit-box-align: center; "
104 "    -webkit-box-pack: center; "
105 "} "
106 ".annotation { "
107 "    position: absolute; "
108 "    pointer-events: auto; "
109 "} "
110 "textarea.annotation { "
111 "    resize: none; "
112 "} "
113 "input.annotation[type='password'] { "
114 "    position: static; "
115 "    width: 200px; "
116 "    margin-top: 100px; "
117 "} ";
118
119 // In non-continuous modes, a single scroll event with a magnitude of >= 20px
120 // will jump to the next or previous page, to match PDFKit behavior.
121 static const int defaultScrollMagnitudeThresholdForPageFlip = 20;
122
123 @interface WKPDFPluginAccessibilityObject : NSObject {
124     PDFLayerController *_pdfLayerController;
125     NSObject *_parent;
126     WebKit::PDFPlugin* _pdfPlugin;
127 }
128
129 @property (assign) PDFLayerController *pdfLayerController;
130 @property (assign) NSObject *parent;
131 @property (assign) WebKit::PDFPlugin* pdfPlugin;
132
133 - (id)initWithPDFPlugin:(WebKit::PDFPlugin *)plugin;
134
135 @end
136
137 @implementation WKPDFPluginAccessibilityObject
138
139 @synthesize parent=_parent;
140 @synthesize pdfPlugin=_pdfPlugin;
141
142 - (id)initWithPDFPlugin:(WebKit::PDFPlugin *)plugin
143 {
144     if (!(self = [super init]))
145         return nil;
146
147     _pdfPlugin = plugin;
148
149     return self;
150 }
151
152 - (PDFLayerController *)pdfLayerController
153 {
154     return _pdfLayerController;
155 }
156
157 - (void)setPdfLayerController:(PDFLayerController *)pdfLayerController
158 {
159     _pdfLayerController = pdfLayerController;
160 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
161     [_pdfLayerController setAccessibilityParent:self];
162 #endif
163 }
164
165 - (BOOL)accessibilityIsIgnored
166 {
167     return NO;
168 }
169
170 // This is called by PDFAccessibilityNodes from inside PDFKit to get final bounds.
171 - (NSRect)convertRectToScreenSpace:(NSRect)rect
172 {
173     return _pdfPlugin->convertFromPDFViewToScreen(rect);
174 }
175
176 - (id)accessibilityAttributeValue:(NSString *)attribute
177 {
178     if ([attribute isEqualToString:NSAccessibilityParentAttribute])
179         return _parent;
180     if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute])
181         return [_parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
182     if ([attribute isEqualToString:NSAccessibilityWindowAttribute])
183         return [_parent accessibilityAttributeValue:NSAccessibilityWindowAttribute];
184     if ([attribute isEqualToString:NSAccessibilitySizeAttribute])
185         return [NSValue valueWithSize:_pdfPlugin->boundsOnScreen().size()];
186     if ([attribute isEqualToString:NSAccessibilityEnabledAttribute])
187         return [_parent accessibilityAttributeValue:NSAccessibilityEnabledAttribute];
188     if ([attribute isEqualToString:NSAccessibilityPositionAttribute])
189         return [NSValue valueWithPoint:_pdfPlugin->boundsOnScreen().location()];
190
191 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
192     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
193         return @[ _pdfLayerController ];
194     if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
195         return NSAccessibilityGroupRole;
196 #else
197     if ([attribute isEqualToString:NSAccessibilityValueAttribute])
198         return [_pdfLayerController accessibilityValueAttribute];
199     if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute])
200         return [_pdfLayerController accessibilitySelectedTextAttribute];
201     if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute])
202         return [_pdfLayerController accessibilitySelectedTextRangeAttribute];
203     if ([attribute isEqualToString:NSAccessibilityNumberOfCharactersAttribute])
204         return [_pdfLayerController accessibilityNumberOfCharactersAttribute];
205     if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute])
206         return [_pdfLayerController accessibilityVisibleCharacterRangeAttribute];
207     if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
208         return [_pdfLayerController accessibilityRoleAttribute];
209     if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute])
210         return [_pdfLayerController accessibilityRoleDescriptionAttribute];
211     if ([attribute isEqualToString:NSAccessibilityFocusedAttribute])
212         return [_parent accessibilityAttributeValue:NSAccessibilityFocusedAttribute];
213 #endif
214
215     return 0;
216 }
217
218 - (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter
219 {
220     if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
221         NSRect boundsInPDFViewCoordinates = [[_pdfLayerController accessibilityBoundsForRangeAttributeForParameter:parameter] rectValue];
222         NSRect boundsInScreenCoordinates = _pdfPlugin->convertFromPDFViewToScreen(boundsInPDFViewCoordinates);
223         return [NSValue valueWithRect:boundsInScreenCoordinates];
224     }
225
226     if ([attribute isEqualToString:NSAccessibilityLineForIndexParameterizedAttribute])
227         return [_pdfLayerController accessibilityLineForIndexAttributeForParameter:parameter];
228     if ([attribute isEqualToString:NSAccessibilityRangeForLineParameterizedAttribute])
229         return [_pdfLayerController accessibilityRangeForLineAttributeForParameter:parameter];
230     if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute])
231         return [_pdfLayerController accessibilityStringForRangeAttributeForParameter:parameter];
232
233     return 0;
234 }
235
236 - (CPReadingModel *)readingModel
237 {
238     return [_pdfLayerController readingModel];
239 }
240
241 - (NSArray *)accessibilityAttributeNames
242 {
243     static NSArray *attributeNames = 0;
244
245     if (!attributeNames) {
246         attributeNames = @[
247             NSAccessibilityParentAttribute,
248             NSAccessibilityWindowAttribute,
249             NSAccessibilityTopLevelUIElementAttribute,
250             NSAccessibilityRoleDescriptionAttribute,
251             NSAccessibilitySizeAttribute,
252             NSAccessibilityEnabledAttribute,
253             NSAccessibilityPositionAttribute,
254             NSAccessibilityFocusedAttribute,
255             // PDFLayerController has its own accessibilityChildren.
256 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
257             NSAccessibilityChildrenAttribute
258 #else
259             NSAccessibilityRoleAttribute,
260             NSAccessibilityValueAttribute,
261             NSAccessibilitySelectedTextAttribute,
262             NSAccessibilitySelectedTextRangeAttribute,
263             NSAccessibilityNumberOfCharactersAttribute,
264             NSAccessibilityVisibleCharacterRangeAttribute
265 #endif
266             ];
267         [attributeNames retain];
268     }
269
270     return attributeNames;
271 }
272
273 - (NSArray *)accessibilityActionNames
274 {
275 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
276     return nil;
277 #else
278     static NSArray *actionNames = 0;
279     
280     if (!actionNames)
281         actionNames = [[NSArray arrayWithObject:NSAccessibilityShowMenuAction] retain];
282     
283     return actionNames;
284 #endif
285 }
286
287 - (void)accessibilityPerformAction:(NSString *)action
288 {
289     if ([action isEqualToString:NSAccessibilityShowMenuAction])
290         _pdfPlugin->showContextMenuAtPoint(IntRect(IntPoint(), _pdfPlugin->size()).center());
291 }
292
293 - (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute
294 {
295     return [_pdfLayerController accessibilityIsAttributeSettable:attribute];
296 }
297
298 - (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute
299 {
300     return [_pdfLayerController accessibilitySetValue:value forAttribute:attribute];
301 }
302
303 - (NSArray *)accessibilityParameterizedAttributeNames
304 {
305 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
306     return nil;
307 #else
308     return [_pdfLayerController accessibilityParameterizedAttributeNames];
309 #endif
310 }
311
312 - (id)accessibilityFocusedUIElement
313 {
314 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
315     if (WebKit::PDFPluginAnnotation* activeAnnotation = _pdfPlugin->activeAnnotation()) {
316         if (AXObjectCache* existingCache = _pdfPlugin->axObjectCache()) {
317             if (AccessibilityObject* object = existingCache->getOrCreate(activeAnnotation->element()))
318 #pragma clang diagnostic push
319 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
320                 return [object->wrapper() accessibilityAttributeValue:@"_AXAssociatedPluginParent"];
321 #pragma clang diagnostic pop
322         }
323     }
324     return nil;
325 #else
326     return self;
327 #endif
328 }
329
330 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
331 - (id)accessibilityAssociatedControlForAnnotation:(PDFAnnotation *)annotation
332 {
333     // Only active annotations seem to have their associated controls available.
334     WebKit::PDFPluginAnnotation* activeAnnotation = _pdfPlugin->activeAnnotation();
335     if (!activeAnnotation || ![activeAnnotation->annotation() isEqual:annotation])
336         return nil;
337     
338     AXObjectCache* cache = _pdfPlugin->axObjectCache();
339     if (!cache)
340         return nil;
341     
342     AccessibilityObject* object = cache->getOrCreate(activeAnnotation->element());
343     if (!object)
344         return nil;
345
346     return object->wrapper();
347 }
348 #endif
349
350 - (id)accessibilityHitTest:(NSPoint)point
351 {
352 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
353     point = _pdfPlugin->convertFromRootViewToPDFView(IntPoint(point));
354     return [_pdfLayerController accessibilityHitTest:point];
355 #else
356     return self;
357 #endif
358 }
359
360 @end
361
362
363 @interface WKPDFPluginScrollbarLayer : CALayer {
364     WebKit::PDFPlugin* _pdfPlugin;
365 }
366
367 @property (assign) WebKit::PDFPlugin* pdfPlugin;
368
369 @end
370
371 @implementation WKPDFPluginScrollbarLayer
372
373 @synthesize pdfPlugin=_pdfPlugin;
374
375 - (id)initWithPDFPlugin:(WebKit::PDFPlugin *)plugin
376 {
377     if (!(self = [super init]))
378         return nil;
379     
380     _pdfPlugin = plugin;
381     
382     return self;
383 }
384
385 - (id<CAAction>)actionForKey:(NSString *)key
386 {
387     return nil;
388 }
389
390 - (void)drawInContext:(CGContextRef)ctx
391 {
392     _pdfPlugin->paintControlForLayerInContext(self, ctx);
393 }
394
395 @end
396
397 @interface WKPDFLayerControllerDelegate : NSObject<PDFLayerControllerDelegate> {
398     WebKit::PDFPlugin* _pdfPlugin;
399 }
400
401 @property (assign) WebKit::PDFPlugin* pdfPlugin;
402
403 @end
404
405 @implementation WKPDFLayerControllerDelegate
406
407 @synthesize pdfPlugin=_pdfPlugin;
408
409 - (id)initWithPDFPlugin:(WebKit::PDFPlugin *)plugin
410 {
411     if (!(self = [super init]))
412         return nil;
413     
414     _pdfPlugin = plugin;
415     
416     return self;
417 }
418
419 - (void)updateScrollPosition:(CGPoint)newPosition
420 {
421     _pdfPlugin->notifyScrollPositionChanged(IntPoint(newPosition));
422 }
423
424 - (void)writeItemsToPasteboard:(NSArray *)items withTypes:(NSArray *)types
425 {
426 #pragma clang diagnostic push
427 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
428     _pdfPlugin->writeItemsToPasteboard(NSGeneralPboard, items, types);
429 #pragma clang diagnostic pop
430 }
431
432 - (void)showDefinitionForAttributedString:(NSAttributedString *)string atPoint:(CGPoint)point
433 {
434     _pdfPlugin->showDefinitionForAttributedString(string, point);
435 }
436
437 - (void)performWebSearch:(NSString *)string
438 {
439     _pdfPlugin->performWebSearch(string);
440 }
441
442 - (void)performSpotlightSearch:(NSString *)string
443 {
444     _pdfPlugin->performSpotlightSearch(string);
445 }
446
447 - (void)openWithNativeApplication
448 {
449     _pdfPlugin->openWithNativeApplication();
450 }
451
452 - (void)saveToPDF
453 {
454     _pdfPlugin->saveToPDF();
455 }
456
457 - (void)pdfLayerController:(PDFLayerController *)pdfLayerController clickedLinkWithURL:(NSURL *)url
458 {
459     _pdfPlugin->clickedLink(url);
460 }
461
462 - (void)pdfLayerController:(PDFLayerController *)pdfLayerController didChangeActiveAnnotation:(PDFAnnotation *)annotation
463 {
464     _pdfPlugin->setActiveAnnotation(annotation);
465 }
466
467 - (void)pdfLayerController:(PDFLayerController *)pdfLayerController didChangeContentScaleFactor:(CGFloat)scaleFactor
468 {
469     _pdfPlugin->notifyContentScaleFactorChanged(scaleFactor);
470 }
471
472 - (void)pdfLayerController:(PDFLayerController *)pdfLayerController didChangeDisplayMode:(int)mode
473 {
474     _pdfPlugin->notifyDisplayModeChanged(mode);
475 }
476
477 - (void)pdfLayerController:(PDFLayerController *)pdfLayerController didChangeSelection:(PDFSelection *)selection
478 {
479     _pdfPlugin->notifySelectionChanged(selection);
480 }
481
482 - (void)setMouseCursor:(PDFLayerControllerCursorType)cursorType
483 {
484     _pdfPlugin->notifyCursorChanged(cursorType);
485 }
486
487 - (void)didChangeAnnotationState
488 {
489     _pdfPlugin->didMutatePDFDocument();
490 }
491
492 @end
493
494 @interface PDFViewLayout
495 - (NSPoint)convertPoint:(NSPoint)point toPage:(PDFPage *)page forScaleFactor:(CGFloat)scaleFactor;
496 - (NSRect)convertRect:(NSRect)rect fromPage:(PDFPage *) page forScaleFactor:(CGFloat) scaleFactor;
497 - (PDFPage *)pageNearestPoint:(NSPoint)point currentPage:(PDFPage *)currentPage;
498 @end
499
500 static const char* postScriptMIMEType = "application/postscript";
501 const uint64_t pdfDocumentRequestID = 1; // PluginController supports loading multiple streams, but we only need one for PDF.
502
503 static void appendValuesInPDFNameSubtreeToVector(CGPDFDictionaryRef subtree, Vector<CGPDFObjectRef>& values)
504 {
505     CGPDFArrayRef names;
506     if (CGPDFDictionaryGetArray(subtree, "Names", &names)) {
507         size_t nameCount = CGPDFArrayGetCount(names) / 2;
508         for (size_t i = 0; i < nameCount; ++i) {
509             CGPDFObjectRef object;
510             CGPDFArrayGetObject(names, 2 * i + 1, &object);
511             values.append(object);
512         }
513         return;
514     }
515
516     CGPDFArrayRef kids;
517     if (!CGPDFDictionaryGetArray(subtree, "Kids", &kids))
518         return;
519
520     size_t kidCount = CGPDFArrayGetCount(kids);
521     for (size_t i = 0; i < kidCount; ++i) {
522         CGPDFDictionaryRef kid;
523         if (!CGPDFArrayGetDictionary(kids, i, &kid))
524             continue;
525         appendValuesInPDFNameSubtreeToVector(kid, values);
526     }
527 }
528
529 static void getAllValuesInPDFNameTree(CGPDFDictionaryRef tree, Vector<CGPDFObjectRef>& allValues)
530 {
531     appendValuesInPDFNameSubtreeToVector(tree, allValues);
532 }
533
534 static void getAllScriptsInPDFDocument(CGPDFDocumentRef pdfDocument, Vector<RetainPtr<CFStringRef>>& scripts)
535 {
536     if (!pdfDocument)
537         return;
538
539     CGPDFDictionaryRef pdfCatalog = CGPDFDocumentGetCatalog(pdfDocument);
540     if (!pdfCatalog)
541         return;
542
543     // Get the dictionary of all document-level name trees.
544     CGPDFDictionaryRef namesDictionary;
545     if (!CGPDFDictionaryGetDictionary(pdfCatalog, "Names", &namesDictionary))
546         return;
547
548     // Get the document-level "JavaScript" name tree.
549     CGPDFDictionaryRef javaScriptNameTree;
550     if (!CGPDFDictionaryGetDictionary(namesDictionary, "JavaScript", &javaScriptNameTree))
551         return;
552
553     // The names are arbitrary. We are only interested in the values.
554     Vector<CGPDFObjectRef> objects;
555     getAllValuesInPDFNameTree(javaScriptNameTree, objects);
556     size_t objectCount = objects.size();
557
558     for (size_t i = 0; i < objectCount; ++i) {
559         CGPDFDictionaryRef javaScriptAction;
560         if (!CGPDFObjectGetValue(reinterpret_cast<CGPDFObjectRef>(objects[i]), kCGPDFObjectTypeDictionary, &javaScriptAction))
561             continue;
562
563         // A JavaScript action must have an action type of "JavaScript".
564         const char* actionType;
565         if (!CGPDFDictionaryGetName(javaScriptAction, "S", &actionType) || strcmp(actionType, "JavaScript"))
566             continue;
567
568         const UInt8* bytes = 0;
569         CFIndex length;
570         CGPDFStreamRef stream;
571         CGPDFStringRef string;
572         RetainPtr<CFDataRef> data;
573         if (CGPDFDictionaryGetStream(javaScriptAction, "JS", &stream)) {
574             CGPDFDataFormat format;
575             data = adoptCF(CGPDFStreamCopyData(stream, &format));
576             if (!data)
577                 continue;
578             bytes = CFDataGetBytePtr(data.get());
579             length = CFDataGetLength(data.get());
580         } else if (CGPDFDictionaryGetString(javaScriptAction, "JS", &string)) {
581             bytes = CGPDFStringGetBytePtr(string);
582             length = CGPDFStringGetLength(string);
583         }
584         if (!bytes)
585             continue;
586
587         CFStringEncoding encoding = (length > 1 && bytes[0] == 0xFE && bytes[1] == 0xFF) ? kCFStringEncodingUnicode : kCFStringEncodingUTF8;
588         RetainPtr<CFStringRef> script = adoptCF(CFStringCreateWithBytes(kCFAllocatorDefault, bytes, length, encoding, true));
589         if (!script)
590             continue;
591         
592         scripts.append(script);
593     }
594 }
595
596 namespace WebKit {
597
598 using namespace HTMLNames;
599
600 Ref<PDFPlugin> PDFPlugin::create(WebFrame& frame)
601 {
602     return adoptRef(*new PDFPlugin(frame));
603 }
604
605 inline PDFPlugin::PDFPlugin(WebFrame& frame)
606     : Plugin(PDFPluginType)
607     , m_frame(&frame)
608     , m_containerLayer(adoptNS([[CALayer alloc] init]))
609     , m_contentLayer(adoptNS([[CALayer alloc] init]))
610     , m_scrollCornerLayer(adoptNS([[WKPDFPluginScrollbarLayer alloc] initWithPDFPlugin:this]))
611     , m_pdfLayerController(adoptNS([[pdfLayerControllerClass() alloc] init]))
612     , m_pdfLayerControllerDelegate(adoptNS([[WKPDFLayerControllerDelegate alloc] initWithPDFPlugin:this]))
613 {
614     m_pdfLayerController.get().delegate = m_pdfLayerControllerDelegate.get();
615     m_pdfLayerController.get().parentLayer = m_contentLayer.get();
616
617     if (supportsForms()) {
618         Document* document = webFrame()->coreFrame()->document();
619         m_annotationContainer = document->createElement(divTag, false);
620         m_annotationContainer->setAttributeWithoutSynchronization(idAttr, AtomicString("annotationContainer", AtomicString::ConstructFromLiteral));
621
622         auto annotationStyleElement = document->createElement(styleTag, false);
623         annotationStyleElement->setTextContent(annotationStyle);
624
625         m_annotationContainer->appendChild(annotationStyleElement);
626         document->bodyOrFrameset()->appendChild(*m_annotationContainer);
627     }
628
629     m_accessibilityObject = adoptNS([[WKPDFPluginAccessibilityObject alloc] initWithPDFPlugin:this]);
630     [m_accessibilityObject setPdfLayerController:m_pdfLayerController.get()];
631     [m_accessibilityObject setParent:webFrame()->page()->accessibilityRemoteObject()];
632
633     [m_containerLayer addSublayer:m_contentLayer.get()];
634     [m_containerLayer addSublayer:m_scrollCornerLayer.get()];
635 }
636
637 PDFPlugin::~PDFPlugin()
638 {
639 }
640
641 PluginInfo PDFPlugin::pluginInfo()
642 {
643     PluginInfo info;
644     info.name = builtInPDFPluginName();
645     info.isApplicationPlugin = true;
646     info.clientLoadPolicy = PluginLoadClientPolicyUndefined;
647
648     MimeClassInfo pdfMimeClassInfo;
649     pdfMimeClassInfo.type = "application/pdf";
650     pdfMimeClassInfo.desc = pdfDocumentTypeDescription();
651     pdfMimeClassInfo.extensions.append("pdf");
652     info.mimes.append(pdfMimeClassInfo);
653
654     MimeClassInfo textPDFMimeClassInfo;
655     textPDFMimeClassInfo.type = "text/pdf";
656     textPDFMimeClassInfo.desc = pdfDocumentTypeDescription();
657     textPDFMimeClassInfo.extensions.append("pdf");
658     info.mimes.append(textPDFMimeClassInfo);
659
660     MimeClassInfo postScriptMimeClassInfo;
661     postScriptMimeClassInfo.type = postScriptMIMEType;
662     postScriptMimeClassInfo.desc = postScriptDocumentTypeDescription();
663     postScriptMimeClassInfo.extensions.append("ps");
664     info.mimes.append(postScriptMimeClassInfo);
665     
666     return info;
667 }
668
669 void PDFPlugin::updateScrollbars()
670 {
671     bool hadScrollbars = m_horizontalScrollbar || m_verticalScrollbar;
672
673     if (m_horizontalScrollbar) {
674         if (m_size.width() >= m_pdfDocumentSize.width())
675             destroyScrollbar(HorizontalScrollbar);
676     } else if (m_size.width() < m_pdfDocumentSize.width())
677         m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
678
679     if (m_verticalScrollbar) {
680         if (m_size.height() >= m_pdfDocumentSize.height())
681             destroyScrollbar(VerticalScrollbar);
682     } else if (m_size.height() < m_pdfDocumentSize.height())
683         m_verticalScrollbar = createScrollbar(VerticalScrollbar);
684
685     IntSize scrollbarSpace = scrollbarIntrusion();
686
687     if (m_horizontalScrollbar) {
688         m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), m_firstPageHeight);
689         m_horizontalScrollbar->setProportion(m_size.width() - scrollbarSpace.width(), m_pdfDocumentSize.width());
690         IntRect scrollbarRect(pluginView()->x(), pluginView()->y() + m_size.height() - m_horizontalScrollbar->height(), m_size.width(), m_horizontalScrollbar->height());
691         if (m_verticalScrollbar)
692             scrollbarRect.contract(m_verticalScrollbar->width(), 0);
693         m_horizontalScrollbar->setFrameRect(scrollbarRect);
694     }
695
696     if (m_verticalScrollbar) {
697         m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), m_firstPageHeight);
698         m_verticalScrollbar->setProportion(m_size.height() - scrollbarSpace.height(), m_pdfDocumentSize.height());
699         IntRect scrollbarRect(IntRect(pluginView()->x() + m_size.width() - m_verticalScrollbar->width(), pluginView()->y(), m_verticalScrollbar->width(), m_size.height()));
700         if (m_horizontalScrollbar)
701             scrollbarRect.contract(0, m_horizontalScrollbar->height());
702         m_verticalScrollbar->setFrameRect(scrollbarRect);
703     }
704
705     FrameView* frameView = m_frame->coreFrame()->view();
706     if (!frameView)
707         return;
708
709     bool hasScrollbars = m_horizontalScrollbar || m_verticalScrollbar;
710     if (hadScrollbars != hasScrollbars) {
711         if (hasScrollbars)
712             frameView->addScrollableArea(this);
713         else
714             frameView->removeScrollableArea(this);
715
716         frameView->setNeedsLayout();
717     }
718     
719     if (m_verticalScrollbarLayer) {
720         m_verticalScrollbarLayer.get().frame = verticalScrollbar()->frameRect();
721         [m_verticalScrollbarLayer setNeedsDisplay];
722     }
723     
724     if (m_horizontalScrollbarLayer) {
725         m_horizontalScrollbarLayer.get().frame = horizontalScrollbar()->frameRect();
726         [m_horizontalScrollbarLayer setNeedsDisplay];
727     }
728     
729     if (m_scrollCornerLayer) {
730         m_scrollCornerLayer.get().frame = scrollCornerRect();
731         [m_scrollCornerLayer setNeedsDisplay];
732     }
733 }
734
735 PluginView* PDFPlugin::pluginView()
736 {
737     return static_cast<PluginView*>(controller());
738 }
739
740 const PluginView* PDFPlugin::pluginView() const
741 {
742     return static_cast<const PluginView*>(controller());
743 }
744
745 Ref<Scrollbar> PDFPlugin::createScrollbar(ScrollbarOrientation orientation)
746 {
747     auto widget = Scrollbar::createNativeScrollbar(*this, orientation, RegularScrollbar);
748     if (orientation == HorizontalScrollbar) {
749         m_horizontalScrollbarLayer = adoptNS([[WKPDFPluginScrollbarLayer alloc] initWithPDFPlugin:this]);
750         [m_containerLayer addSublayer:m_horizontalScrollbarLayer.get()];
751     } else {
752         m_verticalScrollbarLayer = adoptNS([[WKPDFPluginScrollbarLayer alloc] initWithPDFPlugin:this]);
753         [m_containerLayer addSublayer:m_verticalScrollbarLayer.get()];
754     }
755     didAddScrollbar(widget.ptr(), orientation);
756     if (Frame* frame = webFrame()->coreFrame()) {
757         if (Page* page = frame->page()) {
758             if (page->expectsWheelEventTriggers())
759                 scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
760         }
761     }
762     pluginView()->frame()->view()->addChild(widget);
763     return widget;
764 }
765
766 void PDFPlugin::destroyScrollbar(ScrollbarOrientation orientation)
767 {
768     RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_horizontalScrollbar : m_verticalScrollbar;
769     if (!scrollbar)
770         return;
771
772     willRemoveScrollbar(scrollbar.get(), orientation);
773     scrollbar->removeFromParent();
774     scrollbar = nullptr;
775
776     if (orientation == HorizontalScrollbar) {
777         [m_horizontalScrollbarLayer removeFromSuperlayer];
778         m_horizontalScrollbarLayer = 0;
779     } else {
780         [m_verticalScrollbarLayer removeFromSuperlayer];
781         m_verticalScrollbarLayer = 0;
782     }
783 }
784
785 IntRect PDFPlugin::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntRect& scrollbarRect) const
786 {
787     IntRect rect = scrollbarRect;
788     rect.move(scrollbar.location() - pluginView()->location());
789
790     return pluginView()->frame()->view()->convertFromRendererToContainingView(pluginView()->pluginElement()->renderer(), rect);
791 }
792
793 IntRect PDFPlugin::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntRect& parentRect) const
794 {
795     IntRect rect = pluginView()->frame()->view()->convertFromContainingViewToRenderer(pluginView()->pluginElement()->renderer(), parentRect);
796     rect.move(pluginView()->location() - scrollbar.location());
797
798     return rect;
799 }
800
801 IntPoint PDFPlugin::convertFromScrollbarToContainingView(const Scrollbar& scrollbar, const IntPoint& scrollbarPoint) const
802 {
803     IntPoint point = scrollbarPoint;
804     point.move(scrollbar.location() - pluginView()->location());
805
806     return pluginView()->frame()->view()->convertFromRendererToContainingView(pluginView()->pluginElement()->renderer(), point);
807 }
808
809 IntPoint PDFPlugin::convertFromContainingViewToScrollbar(const Scrollbar& scrollbar, const IntPoint& parentPoint) const
810 {
811     IntPoint point = pluginView()->frame()->view()->convertFromContainingViewToRenderer(pluginView()->pluginElement()->renderer(), parentPoint);
812     point.move(pluginView()->location() - scrollbar.location());
813     
814     return point;
815 }
816
817 bool PDFPlugin::handleScroll(ScrollDirection direction, ScrollGranularity granularity)
818 {
819     return scroll(direction, granularity);
820 }
821
822 IntRect PDFPlugin::scrollCornerRect() const
823 {
824     if (!m_horizontalScrollbar || !m_verticalScrollbar)
825         return IntRect();
826     if (m_horizontalScrollbar->isOverlayScrollbar()) {
827         ASSERT(m_verticalScrollbar->isOverlayScrollbar());
828         return IntRect();
829     }
830     return IntRect(pluginView()->width() - m_verticalScrollbar->width(), pluginView()->height() - m_horizontalScrollbar->height(), m_verticalScrollbar->width(), m_horizontalScrollbar->height());
831 }
832
833 ScrollableArea* PDFPlugin::enclosingScrollableArea() const
834 {
835     // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
836     return nullptr;
837 }
838
839 IntRect PDFPlugin::scrollableAreaBoundingBox(bool*) const
840 {
841     return pluginView()->frameRect();
842 }
843
844 int PDFPlugin::scrollSize(ScrollbarOrientation orientation) const
845 {
846     Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
847     return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
848 }
849
850 bool PDFPlugin::isActive() const
851 {
852     if (Frame* coreFrame = m_frame->coreFrame()) {
853         if (Page* page = coreFrame->page())
854             return page->focusController().isActive();
855     }
856
857     return false;
858 }
859
860 bool PDFPlugin::forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const
861 {
862     if (Frame* coreFrame = m_frame->coreFrame()) {
863         if (Page* page = coreFrame->page())
864             return page->settings().forceUpdateScrollbarsOnMainThreadForPerformanceTesting();
865     }
866
867     return false;
868 }
869
870 int PDFPlugin::scrollOffset(ScrollbarOrientation orientation) const
871 {
872     if (orientation == HorizontalScrollbar)
873         return m_scrollOffset.width();
874
875     if (orientation == VerticalScrollbar)
876         return m_scrollOffset.height();
877
878     ASSERT_NOT_REACHED();
879     return 0;
880 }
881
882 ScrollPosition PDFPlugin::scrollPosition() const
883 {
884     return IntPoint(m_scrollOffset.width(), m_scrollOffset.height());
885 }
886
887 ScrollPosition PDFPlugin::minimumScrollPosition() const
888 {
889     return IntPoint();
890 }
891
892 ScrollPosition PDFPlugin::maximumScrollPosition() const
893 {
894     IntSize scrollbarSpace = scrollbarIntrusion();
895
896     IntPoint maximumOffset(m_pdfDocumentSize.width() - m_size.width() + scrollbarSpace.width(), m_pdfDocumentSize.height() - m_size.height() + scrollbarSpace.height());
897     maximumOffset.clampNegativeToZero();
898     return maximumOffset;
899 }
900
901 void PDFPlugin::scrollbarStyleChanged(ScrollbarStyle style, bool forceUpdate)
902 {
903     if (!forceUpdate)
904         return;
905
906     // If the PDF was scrolled all the way to bottom right and scrollbars change to overlay style, we don't want to display white rectangles where scrollbars were.
907     IntPoint newScrollOffset = IntPoint(m_scrollOffset).shrunkTo(maximumScrollPosition());
908     setScrollOffset(newScrollOffset);
909     
910     ScrollableArea::scrollbarStyleChanged(style, forceUpdate);
911     // As size of the content area changes, scrollbars may need to appear or to disappear.
912     updateScrollbars();
913 }
914
915 void PDFPlugin::addArchiveResource()
916 {
917     // FIXME: It's a hack to force add a resource to DocumentLoader. PDF documents should just be fetched as CachedResources.
918
919     // Add just enough data for context menu handling and web archives to work.
920     NSDictionary* headers = @{ @"Content-Disposition": (NSString *)m_suggestedFilename, @"Content-Type" : @"application/pdf" };
921     RetainPtr<NSURLResponse> response = adoptNS([[NSHTTPURLResponse alloc] initWithURL:m_sourceURL statusCode:200 HTTPVersion:(NSString*)kCFHTTPVersion1_1 headerFields:headers]);
922     ResourceResponse synthesizedResponse(response.get());
923
924     RefPtr<ArchiveResource> resource = ArchiveResource::create(SharedBuffer::create(m_data.get()), m_sourceURL, "application/pdf", String(), String(), synthesizedResponse);
925     pluginView()->frame()->document()->loader()->addArchiveResource(resource.releaseNonNull());
926 }
927
928 static void jsPDFDocInitialize(JSContextRef ctx, JSObjectRef object)
929 {
930     PDFPlugin* pdfView = static_cast<PDFPlugin*>(JSObjectGetPrivate(object));
931     pdfView->ref();
932 }
933
934 static void jsPDFDocFinalize(JSObjectRef object)
935 {
936     PDFPlugin* pdfView = static_cast<PDFPlugin*>(JSObjectGetPrivate(object));
937     pdfView->deref();
938 }
939
940 JSValueRef PDFPlugin::jsPDFDocPrint(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
941 {
942     PDFPlugin* pdfView = static_cast<PDFPlugin*>(JSObjectGetPrivate(thisObject));
943
944     WebFrame* frame = pdfView->m_frame;
945     if (!frame)
946         return JSValueMakeUndefined(ctx);
947
948     Frame* coreFrame = frame->coreFrame();
949     if (!coreFrame)
950         return JSValueMakeUndefined(ctx);
951
952     Page* page = coreFrame->page();
953     if (!page)
954         return JSValueMakeUndefined(ctx);
955
956     page->chrome().print(*coreFrame);
957
958     return JSValueMakeUndefined(ctx);
959 }
960
961 JSObjectRef PDFPlugin::makeJSPDFDoc(JSContextRef ctx)
962 {
963     static JSStaticFunction jsPDFDocStaticFunctions[] = {
964         { "print", jsPDFDocPrint, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
965         { 0, 0, 0 },
966     };
967
968     static JSClassDefinition jsPDFDocClassDefinition = {
969         0,
970         kJSClassAttributeNone,
971         "Doc",
972         0,
973         0,
974         jsPDFDocStaticFunctions,
975         jsPDFDocInitialize, jsPDFDocFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
976     };
977
978     static JSClassRef jsPDFDocClass = JSClassCreate(&jsPDFDocClassDefinition);
979
980     return JSObjectMake(ctx, jsPDFDocClass, this);
981 }
982
983 void PDFPlugin::convertPostScriptDataIfNeeded()
984 {
985     if (!m_isPostScript)
986         return;
987
988     m_suggestedFilename = String(m_suggestedFilename + ".pdf");
989     m_data = PDFDocumentImage::convertPostScriptDataToPDF(WTFMove(m_data));
990 }
991
992 void PDFPlugin::pdfDocumentDidLoad()
993 {
994     addArchiveResource();
995     
996     RetainPtr<PDFDocument> document = adoptNS([[pdfDocumentClass() alloc] initWithData:rawData()]);
997
998     setPDFDocument(document);
999
1000     updatePageAndDeviceScaleFactors();
1001
1002     [m_pdfLayerController setFrameSize:size()];
1003     m_pdfLayerController.get().document = document.get();
1004
1005     if (handlesPageScaleFactor())
1006         pluginView()->setPageScaleFactor([m_pdfLayerController contentScaleFactor], IntPoint());
1007
1008     notifyScrollPositionChanged(IntPoint([m_pdfLayerController scrollPosition]));
1009
1010     calculateSizes();
1011     updateScrollbars();
1012
1013     runScriptsInPDFDocument();
1014
1015     if ([document isLocked])
1016         createPasswordEntryForm();
1017
1018 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
1019     if ([m_pdfLayerController respondsToSelector:@selector(setURLFragment:)]) {
1020         String pdfURLFragment = webFrame()->url().fragmentIdentifier();
1021         [m_pdfLayerController setURLFragment:pdfURLFragment];
1022     }
1023 #endif
1024 }
1025     
1026 void PDFPlugin::streamDidReceiveResponse(uint64_t streamID, const URL&, uint32_t, uint32_t, const String& mimeType, const String&, const String& suggestedFilename)
1027 {
1028     ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
1029
1030     m_suggestedFilename = suggestedFilename;
1031
1032     if (equalIgnoringASCIICase(mimeType, postScriptMIMEType))
1033         m_isPostScript = true;
1034 }
1035
1036 void PDFPlugin::streamDidReceiveData(uint64_t streamID, const char* bytes, int length)
1037 {
1038     ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
1039
1040     if (!m_data)
1041         m_data = adoptCF(CFDataCreateMutable(0, 0));
1042
1043     CFDataAppendBytes(m_data.get(), reinterpret_cast<const UInt8*>(bytes), length);
1044 }
1045
1046 void PDFPlugin::streamDidFinishLoading(uint64_t streamID)
1047 {
1048     ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
1049
1050     convertPostScriptDataIfNeeded();
1051     pdfDocumentDidLoad();
1052 }
1053
1054 void PDFPlugin::streamDidFail(uint64_t streamID, bool wasCancelled)
1055 {
1056     ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
1057
1058     m_data.clear();
1059 }
1060
1061 void PDFPlugin::manualStreamDidReceiveResponse(const URL& responseURL, uint32_t streamLength,  uint32_t lastModifiedTime, const String& mimeType, const String& headers, const String& suggestedFilename)
1062 {
1063     m_suggestedFilename = suggestedFilename;
1064
1065     if (equalIgnoringASCIICase(mimeType, postScriptMIMEType))
1066         m_isPostScript = true;
1067 }
1068
1069 void PDFPlugin::manualStreamDidReceiveData(const char* bytes, int length)
1070 {
1071     if (!m_data)
1072         m_data = adoptCF(CFDataCreateMutable(0, 0));
1073
1074     CFDataAppendBytes(m_data.get(), reinterpret_cast<const UInt8*>(bytes), length);
1075 }
1076
1077 void PDFPlugin::manualStreamDidFinishLoading()
1078 {
1079     convertPostScriptDataIfNeeded();
1080     pdfDocumentDidLoad();
1081 }
1082
1083 void PDFPlugin::manualStreamDidFail(bool)
1084 {
1085     m_data.clear();
1086 }
1087
1088 void PDFPlugin::runScriptsInPDFDocument()
1089 {
1090     Vector<RetainPtr<CFStringRef>> scripts;
1091     getAllScriptsInPDFDocument([m_pdfDocument documentRef], scripts);
1092
1093     size_t scriptCount = scripts.size();
1094     if (!scriptCount)
1095         return;
1096
1097     JSGlobalContextRef ctx = JSGlobalContextCreate(0);
1098     JSObjectRef jsPDFDoc = makeJSPDFDoc(ctx);
1099
1100     for (size_t i = 0; i < scriptCount; ++i) {
1101         JSStringRef script = JSStringCreateWithCFString(scripts[i].get());
1102         JSEvaluateScript(ctx, script, jsPDFDoc, 0, 0, 0);
1103         JSStringRelease(script);
1104     }
1105     
1106     JSGlobalContextRelease(ctx);
1107 }
1108
1109 void PDFPlugin::createPasswordEntryForm()
1110 {
1111     m_passwordField = PDFPluginPasswordField::create(m_pdfLayerController.get(), this);
1112     m_passwordField->attach(m_annotationContainer.get());
1113 }
1114
1115 void PDFPlugin::attemptToUnlockPDF(const String& password)
1116 {
1117     [m_pdfLayerController attemptToUnlockWithPassword:password];
1118
1119     if (![pdfDocument() isLocked]) {
1120         m_passwordField = nullptr;
1121
1122         calculateSizes();
1123         updateScrollbars();
1124     }
1125 }
1126
1127 void PDFPlugin::updatePageAndDeviceScaleFactors()
1128 {
1129     double newScaleFactor = controller()->contentsScaleFactor();
1130     if (!handlesPageScaleFactor())
1131         newScaleFactor *= webFrame()->page()->pageScaleFactor();
1132
1133     if (newScaleFactor != [m_pdfLayerController deviceScaleFactor])
1134         [m_pdfLayerController setDeviceScaleFactor:newScaleFactor];
1135 }
1136
1137 void PDFPlugin::contentsScaleFactorChanged(float)
1138 {
1139     updatePageAndDeviceScaleFactors();
1140 }
1141
1142 void PDFPlugin::calculateSizes()
1143 {
1144     if ([pdfDocument() isLocked]) {
1145         m_firstPageHeight = 0;
1146         setPDFDocumentSize(IntSize(0, 0));
1147         return;
1148     }
1149
1150     m_firstPageHeight = [m_pdfDocument pageCount] ? static_cast<unsigned>(CGCeiling([[m_pdfDocument pageAtIndex:0] boundsForBox:kPDFDisplayBoxCropBox].size.height)) : 0;
1151     setPDFDocumentSize(IntSize([m_pdfLayerController contentSizeRespectingZoom]));
1152 }
1153
1154 bool PDFPlugin::initialize(const Parameters& parameters)
1155 {
1156     m_sourceURL = parameters.url;
1157     if (!parameters.shouldUseManualLoader && !parameters.url.isEmpty())
1158         controller()->loadURL(pdfDocumentRequestID, "GET", parameters.url.string(), String(), HTTPHeaderMap(), Vector<uint8_t>(), false);
1159
1160     controller()->didInitializePlugin();
1161     return true;
1162 }
1163
1164 void PDFPlugin::willDetachRenderer()
1165 {
1166     if (webFrame()) {
1167         if (FrameView* frameView = webFrame()->coreFrame()->view())
1168             frameView->removeScrollableArea(this);
1169     }
1170 }
1171
1172 void PDFPlugin::destroy()
1173 {
1174     m_pdfLayerController.get().delegate = 0;
1175
1176     if (webFrame()) {
1177         if (FrameView* frameView = webFrame()->coreFrame()->view())
1178             frameView->removeScrollableArea(this);
1179     }
1180
1181     m_activeAnnotation = nullptr;
1182     m_annotationContainer = nullptr;
1183
1184     destroyScrollbar(HorizontalScrollbar);
1185     destroyScrollbar(VerticalScrollbar);
1186     
1187     [m_scrollCornerLayer removeFromSuperlayer];
1188     [m_contentLayer removeFromSuperlayer];
1189 }
1190
1191 void PDFPlugin::updateControlTints(GraphicsContext& graphicsContext)
1192 {
1193     ASSERT(graphicsContext.updatingControlTints());
1194
1195     if (m_horizontalScrollbar)
1196         m_horizontalScrollbar->invalidate();
1197     if (m_verticalScrollbar)
1198         m_verticalScrollbar->invalidate();
1199     invalidateScrollCorner(scrollCornerRect());
1200 }
1201
1202 void PDFPlugin::paintControlForLayerInContext(CALayer *layer, CGContextRef context)
1203 {
1204     GraphicsContext graphicsContext(context);
1205     GraphicsContextStateSaver stateSaver(graphicsContext);
1206     
1207     graphicsContext.setIsCALayerContext(true);
1208     
1209     if (layer == m_scrollCornerLayer) {
1210         IntRect scrollCornerRect = this->scrollCornerRect();
1211         graphicsContext.translate(-scrollCornerRect.x(), -scrollCornerRect.y());
1212         ScrollbarTheme::theme().paintScrollCorner(nullptr, graphicsContext, scrollCornerRect);
1213         return;
1214     }
1215     
1216     Scrollbar* scrollbar = nullptr;
1217     
1218     if (layer == m_verticalScrollbarLayer)
1219         scrollbar = verticalScrollbar();
1220     else if (layer == m_horizontalScrollbarLayer)
1221         scrollbar = horizontalScrollbar();
1222
1223     if (!scrollbar)
1224         return;
1225     
1226     graphicsContext.translate(-scrollbar->x(), -scrollbar->y());
1227     scrollbar->paint(graphicsContext, scrollbar->frameRect());
1228 }
1229
1230 RefPtr<ShareableBitmap> PDFPlugin::snapshot()
1231 {
1232     if (size().isEmpty())
1233         return nullptr;
1234
1235     float contentsScaleFactor = controller()->contentsScaleFactor();
1236     IntSize backingStoreSize = size();
1237     backingStoreSize.scale(contentsScaleFactor);
1238
1239     RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(backingStoreSize, { });
1240     auto context = bitmap->createGraphicsContext();
1241
1242     context->scale(FloatSize(contentsScaleFactor, -contentsScaleFactor));
1243     context->translate(-m_scrollOffset.width(), -m_pdfDocumentSize.height() + m_scrollOffset.height());
1244
1245     [m_pdfLayerController snapshotInContext:context->platformContext()];
1246
1247     return bitmap;
1248 }
1249
1250 PlatformLayer* PDFPlugin::pluginLayer()
1251 {
1252     return m_containerLayer.get();
1253 }
1254
1255 IntPoint PDFPlugin::convertFromPluginToPDFView(const IntPoint& point) const
1256 {
1257     return IntPoint(point.x(), size().height() - point.y());
1258 }
1259
1260 IntPoint PDFPlugin::convertFromRootViewToPlugin(const IntPoint& point) const
1261 {
1262     return m_rootViewToPluginTransform.mapPoint(point);
1263 }
1264
1265 IntPoint PDFPlugin::convertFromPDFViewToRootView(const IntPoint& point) const
1266 {
1267     IntPoint pointInPluginCoordinates(point.x(), size().height() - point.y());
1268     return m_rootViewToPluginTransform.inverse().value_or(AffineTransform()).mapPoint(pointInPluginCoordinates);
1269 }
1270     
1271 IntPoint PDFPlugin::convertFromRootViewToPDFView(const IntPoint& point) const
1272 {
1273     IntPoint pointInPluginCoordinates = m_rootViewToPluginTransform.mapPoint(point);
1274     return IntPoint(pointInPluginCoordinates.x(), size().height() - pointInPluginCoordinates.y());
1275 }
1276
1277 FloatRect PDFPlugin::convertFromPDFViewToScreen(const FloatRect& rect) const
1278 {
1279     FrameView* frameView = webFrame()->coreFrame()->view();
1280
1281     if (!frameView)
1282         return FloatRect();
1283
1284     FloatRect updatedRect = rect;
1285     updatedRect.setLocation(convertFromPDFViewToRootView(IntPoint(updatedRect.location())));
1286     return webFrame()->coreFrame()->page()->chrome().rootViewToScreen(enclosingIntRect(updatedRect));
1287 }
1288
1289 IntRect PDFPlugin::boundsOnScreen() const
1290 {
1291     FrameView* frameView = webFrame()->coreFrame()->view();
1292
1293     if (!frameView)
1294         return IntRect();
1295
1296     FloatRect bounds = FloatRect(FloatPoint(), size());
1297     FloatRect rectInRootViewCoordinates = m_rootViewToPluginTransform.inverse().value_or(AffineTransform()).mapRect(bounds);
1298     return frameView->contentsToScreen(enclosingIntRect(rectInRootViewCoordinates));
1299 }
1300
1301 void PDFPlugin::geometryDidChange(const IntSize& pluginSize, const IntRect&, const AffineTransform& pluginToRootViewTransform)
1302 {
1303     if (size() == pluginSize && pluginView()->pageScaleFactor() == [m_pdfLayerController contentScaleFactor])
1304         return;
1305
1306     m_size = pluginSize;
1307     m_rootViewToPluginTransform = pluginToRootViewTransform.inverse().value_or(AffineTransform());
1308     [m_pdfLayerController setFrameSize:pluginSize];
1309
1310     [CATransaction begin];
1311     [CATransaction setDisableActions:YES];
1312     CATransform3D transform = CATransform3DMakeScale(1, -1, 1);
1313     transform = CATransform3DTranslate(transform, 0, -pluginSize.height(), 0);
1314     
1315     if (handlesPageScaleFactor()) {
1316         CGFloat magnification = pluginView()->pageScaleFactor() - [m_pdfLayerController contentScaleFactor];
1317
1318         // FIXME: Instead of m_lastMousePositionInPluginCoordinates, we should use the zoom origin from PluginView::setPageScaleFactor.
1319         if (magnification)
1320             [m_pdfLayerController magnifyWithMagnification:magnification atPoint:convertFromPluginToPDFView(m_lastMousePositionInPluginCoordinates) immediately:NO];
1321     } else {
1322         // If we don't handle page scale ourselves, we need to respect our parent page's
1323         // scale, which may have changed.
1324         updatePageAndDeviceScaleFactors();
1325     } 
1326
1327     calculateSizes();
1328     updateScrollbars();
1329
1330     if (m_activeAnnotation)
1331         m_activeAnnotation->updateGeometry();
1332
1333     [m_contentLayer setSublayerTransform:transform];
1334     [CATransaction commit];
1335 }
1336
1337 void PDFPlugin::frameDidFinishLoading(uint64_t)
1338 {
1339     ASSERT_NOT_REACHED();
1340 }
1341
1342 void PDFPlugin::frameDidFail(uint64_t, bool)
1343 {
1344     ASSERT_NOT_REACHED();
1345 }
1346
1347 void PDFPlugin::didEvaluateJavaScript(uint64_t, const WTF::String&)
1348 {
1349     ASSERT_NOT_REACHED();
1350 }
1351
1352     
1353 static NSUInteger modifierFlagsFromWebEvent(const WebEvent& event)
1354 {
1355     return (event.shiftKey() ? NSEventModifierFlagShift : 0)
1356         | (event.controlKey() ? NSEventModifierFlagControl : 0)
1357         | (event.altKey() ? NSEventModifierFlagOption : 0)
1358         | (event.metaKey() ? NSEventModifierFlagCommand : 0);
1359 }
1360     
1361 static bool getEventTypeFromWebEvent(const WebEvent& event, NSEventType& eventType)
1362 {
1363     switch (event.type()) {
1364     case WebEvent::KeyDown:
1365         eventType = NSEventTypeKeyDown;
1366         return true;
1367     case WebEvent::KeyUp:
1368         eventType = NSEventTypeKeyUp;
1369         return true;
1370     case WebEvent::MouseDown:
1371         switch (static_cast<const WebMouseEvent&>(event).button()) {
1372         case WebMouseEvent::LeftButton:
1373             eventType = NSEventTypeLeftMouseDown;
1374             return true;
1375         case WebMouseEvent::RightButton:
1376             eventType = NSEventTypeRightMouseDown;
1377             return true;
1378         default:
1379             return false;
1380         }
1381     case WebEvent::MouseUp:
1382         switch (static_cast<const WebMouseEvent&>(event).button()) {
1383         case WebMouseEvent::LeftButton:
1384             eventType = NSEventTypeLeftMouseUp;
1385             return true;
1386         case WebMouseEvent::RightButton:
1387             eventType = NSEventTypeRightMouseUp;
1388             return true;
1389         default:
1390             return false;
1391         }
1392     case WebEvent::MouseMove:
1393         switch (static_cast<const WebMouseEvent&>(event).button()) {
1394         case WebMouseEvent::LeftButton:
1395             eventType = NSEventTypeLeftMouseDragged;
1396             return true;
1397         case WebMouseEvent::RightButton:
1398             eventType = NSEventTypeRightMouseDragged;
1399             return true;
1400         case WebMouseEvent::NoButton:
1401             eventType = NSEventTypeMouseMoved;
1402             return true;
1403         default:
1404             return false;
1405         }
1406     default:
1407         return false;
1408     }
1409 }
1410     
1411 NSEvent *PDFPlugin::nsEventForWebMouseEvent(const WebMouseEvent& event)
1412 {
1413     m_lastMousePositionInPluginCoordinates = convertFromRootViewToPlugin(event.position());
1414
1415     IntPoint positionInPDFViewCoordinates(convertFromPluginToPDFView(m_lastMousePositionInPluginCoordinates));
1416
1417     NSEventType eventType;
1418
1419     if (!getEventTypeFromWebEvent(event, eventType))
1420         return 0;
1421
1422     NSUInteger modifierFlags = modifierFlagsFromWebEvent(event);
1423
1424     return [NSEvent mouseEventWithType:eventType location:positionInPDFViewCoordinates modifierFlags:modifierFlags timestamp:0 windowNumber:0 context:nil eventNumber:0 clickCount:event.clickCount() pressure:0];
1425 }
1426
1427 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
1428 void PDFPlugin::updateCursor(const WebMouseEvent& event, UpdateCursorMode mode)
1429 {
1430     HitTestResult hitTestResult = None;
1431
1432     PDFSelection *selectionUnderMouse = [m_pdfLayerController getSelectionForWordAtPoint:convertFromPluginToPDFView(event.position())];
1433     if (selectionUnderMouse && [[selectionUnderMouse string] length])
1434         hitTestResult = Text;
1435
1436     if (hitTestResult == m_lastHitTestResult && mode == UpdateIfNeeded)
1437         return;
1438
1439     webFrame()->page()->send(Messages::WebPageProxy::SetCursor(hitTestResult == Text ? iBeamCursor() : pointerCursor()));
1440     m_lastHitTestResult = hitTestResult;
1441 }
1442 #endif
1443
1444 bool PDFPlugin::handleMouseEvent(const WebMouseEvent& event)
1445 {
1446     PlatformMouseEvent platformEvent = platform(event);
1447     IntPoint mousePosition = convertFromRootViewToPlugin(event.position());
1448
1449     m_lastMouseEvent = event;
1450
1451     RefPtr<Scrollbar> targetScrollbar;
1452     RefPtr<Scrollbar> targetScrollbarForLastMousePosition;
1453
1454     if (m_verticalScrollbarLayer) {
1455         IntRect verticalScrollbarFrame(m_verticalScrollbarLayer.get().frame);
1456         if (verticalScrollbarFrame.contains(mousePosition))
1457             targetScrollbar = verticalScrollbar();
1458         if (verticalScrollbarFrame.contains(m_lastMousePositionInPluginCoordinates))
1459             targetScrollbarForLastMousePosition = verticalScrollbar();
1460     }
1461
1462     if (m_horizontalScrollbarLayer) {
1463         IntRect horizontalScrollbarFrame(m_horizontalScrollbarLayer.get().frame);
1464         if (horizontalScrollbarFrame.contains(mousePosition))
1465             targetScrollbar = horizontalScrollbar();
1466         if (horizontalScrollbarFrame.contains(m_lastMousePositionInPluginCoordinates))
1467             targetScrollbarForLastMousePosition = horizontalScrollbar();
1468     }
1469
1470     if (m_scrollCornerLayer && IntRect(m_scrollCornerLayer.get().frame).contains(mousePosition))
1471         return false;
1472
1473     if ([pdfDocument() isLocked])
1474         return false;
1475
1476     // Right-clicks and Control-clicks always call handleContextMenuEvent as well.
1477     if (event.button() == WebMouseEvent::RightButton || (event.button() == WebMouseEvent::LeftButton && event.controlKey()))
1478         return true;
1479
1480     NSEvent *nsEvent = nsEventForWebMouseEvent(event);
1481
1482     switch (event.type()) {
1483     case WebEvent::MouseMove:
1484         mouseMovedInContentArea();
1485 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
1486         updateCursor(event);
1487 #endif
1488
1489         if (targetScrollbar) {
1490             if (!targetScrollbarForLastMousePosition) {
1491                 targetScrollbar->mouseEntered();
1492                 return true;
1493             }
1494             return targetScrollbar->mouseMoved(platformEvent);
1495         }
1496
1497         if (!targetScrollbar && targetScrollbarForLastMousePosition)
1498             targetScrollbarForLastMousePosition->mouseExited();
1499
1500         switch (event.button()) {
1501         case WebMouseEvent::LeftButton:
1502             [m_pdfLayerController mouseDragged:nsEvent];
1503             return true;
1504         case WebMouseEvent::RightButton:
1505         case WebMouseEvent::MiddleButton:
1506             return false;
1507         case WebMouseEvent::NoButton:
1508             [m_pdfLayerController mouseMoved:nsEvent];
1509             return true;
1510         }
1511         break;
1512     case WebEvent::MouseDown:
1513         switch (event.button()) {
1514         case WebMouseEvent::LeftButton:
1515             if (targetScrollbar)
1516                 return targetScrollbar->mouseDown(platformEvent);
1517
1518             [m_pdfLayerController mouseDown:nsEvent];
1519             return true;
1520         case WebMouseEvent::RightButton:
1521             [m_pdfLayerController rightMouseDown:nsEvent];
1522             return true;
1523         case WebMouseEvent::MiddleButton:
1524         case WebMouseEvent::NoButton:
1525             return false;
1526         }
1527         break;
1528     case WebEvent::MouseUp:
1529         switch (event.button()) {
1530         case WebMouseEvent::LeftButton:
1531             if (targetScrollbar)
1532                 return targetScrollbar->mouseUp(platformEvent);
1533
1534             [m_pdfLayerController mouseUp:nsEvent];
1535             return true;
1536         case WebMouseEvent::RightButton:
1537         case WebMouseEvent::MiddleButton:
1538         case WebMouseEvent::NoButton:
1539             return false;
1540         }
1541         break;
1542     default:
1543         break;
1544     }
1545
1546     return false;
1547 }
1548
1549 bool PDFPlugin::handleMouseEnterEvent(const WebMouseEvent& event)
1550 {
1551     mouseEnteredContentArea();
1552 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
1553     updateCursor(event, ForceUpdate);
1554 #endif
1555     return false;
1556 }
1557
1558 bool PDFPlugin::handleMouseLeaveEvent(const WebMouseEvent&)
1559 {
1560     mouseExitedContentArea();
1561     return false;
1562 }
1563     
1564 bool PDFPlugin::showContextMenuAtPoint(const IntPoint& point)
1565 {
1566     FrameView* frameView = webFrame()->coreFrame()->view();
1567     IntPoint contentsPoint = frameView->contentsToRootView(point);
1568     WebMouseEvent event(WebEvent::MouseDown, WebMouseEvent::RightButton, 0, contentsPoint, contentsPoint, 0, 0, 0, 1, static_cast<WebEvent::Modifiers>(0), WallTime::now(), WebCore::ForceAtClick);
1569     return handleContextMenuEvent(event);
1570 }
1571
1572 bool PDFPlugin::handleContextMenuEvent(const WebMouseEvent& event)
1573 {
1574     FrameView* frameView = webFrame()->coreFrame()->view();
1575     IntPoint point = frameView->contentsToScreen(IntRect(frameView->windowToContents(event.position()), IntSize())).location();
1576     
1577     if (NSMenu *nsMenu = [m_pdfLayerController menuForEvent:nsEventForWebMouseEvent(event)]) {
1578         _NSPopUpCarbonMenu3(nsMenu, nil, nil, point, -1, nil, 0, nil, NSPopUpMenuTypeContext, nil);
1579         return true;
1580     }
1581     
1582     return false;
1583 }
1584
1585 bool PDFPlugin::handleKeyboardEvent(const WebKeyboardEvent& event)
1586 {
1587     NSEventType eventType;
1588
1589     if (!getEventTypeFromWebEvent(event, eventType))
1590         return false;
1591
1592     NSUInteger modifierFlags = modifierFlagsFromWebEvent(event);
1593     
1594     NSEvent *fakeEvent = [NSEvent keyEventWithType:eventType location:NSZeroPoint modifierFlags:modifierFlags timestamp:0 windowNumber:0 context:0 characters:event.text() charactersIgnoringModifiers:event.unmodifiedText() isARepeat:event.isAutoRepeat() keyCode:event.nativeVirtualKeyCode()];
1595     
1596     switch (event.type()) {
1597     case WebEvent::KeyDown:
1598         return [m_pdfLayerController keyDown:fakeEvent];
1599     default:
1600         return false;
1601     }
1602     
1603     return false;
1604 }
1605     
1606 bool PDFPlugin::handleEditingCommand(const String& commandName, const String& argument)
1607 {
1608     if (commandName == "copy")
1609         [m_pdfLayerController copySelection];
1610     else if (commandName == "selectAll")
1611         [m_pdfLayerController selectAll];
1612     else if (commandName == "takeFindStringFromSelection") {
1613         NSString *string = [m_pdfLayerController currentSelection].string;
1614 #pragma clang diagnostic push
1615 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1616         if (string.length)
1617             writeItemsToPasteboard(NSFindPboard, @[ [string dataUsingEncoding:NSUTF8StringEncoding] ], @[ NSPasteboardTypeString ]);
1618 #pragma clang diagnostic pop
1619     }
1620
1621     return true;
1622 }
1623
1624 bool PDFPlugin::isEditingCommandEnabled(const String& commandName)
1625 {
1626     if (commandName == "copy" || commandName == "takeFindStringFromSelection")
1627         return [m_pdfLayerController currentSelection];
1628
1629     if (commandName == "selectAll")
1630         return true;
1631
1632     return false;
1633 }
1634
1635 void PDFPlugin::setScrollOffset(const ScrollOffset& offset)
1636 {
1637     m_scrollOffset = IntSize(offset.x(), offset.y());
1638
1639     [CATransaction begin];
1640     [m_pdfLayerController setScrollPosition:offset];
1641
1642     if (m_activeAnnotation)
1643         m_activeAnnotation->updateGeometry();
1644
1645     [CATransaction commit];
1646 }
1647
1648 void PDFPlugin::invalidateScrollbarRect(Scrollbar& scrollbar, const IntRect& rect)
1649 {
1650     if (&scrollbar == horizontalScrollbar())
1651         [m_horizontalScrollbarLayer setNeedsDisplay];
1652     else if (&scrollbar == verticalScrollbar())
1653         [m_verticalScrollbarLayer setNeedsDisplay];
1654 }
1655
1656 void PDFPlugin::invalidateScrollCornerRect(const IntRect& rect)
1657 {
1658     [m_scrollCornerLayer setNeedsDisplay];
1659 }
1660
1661 bool PDFPlugin::isFullFramePlugin() const
1662 {
1663     // <object> or <embed> plugins will appear to be in their parent frame, so we have to
1664     // check whether our frame's widget is exactly our PluginView.
1665     Document* document = webFrame()->coreFrame()->document();
1666     return document->isPluginDocument() && static_cast<PluginDocument*>(document)->pluginWidget() == pluginView();
1667 }
1668
1669 bool PDFPlugin::handlesPageScaleFactor() const
1670 {
1671     return webFrame()->isMainFrame() && isFullFramePlugin();
1672 }
1673
1674 void PDFPlugin::clickedLink(NSURL *url)
1675 {
1676     URL coreURL = url;
1677     if (protocolIsJavaScript(coreURL))
1678         return;
1679
1680     Frame* frame = webFrame()->coreFrame();
1681
1682     RefPtr<Event> coreEvent;
1683     if (m_lastMouseEvent.type() != WebEvent::NoType)
1684         coreEvent = MouseEvent::create(eventNames().clickEvent, frame->document()->defaultView(), platform(m_lastMouseEvent), 0, 0);
1685
1686     frame->loader().urlSelected(coreURL, emptyString(), coreEvent.get(), LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, ShouldOpenExternalURLsPolicy::ShouldAllow);
1687 }
1688
1689 void PDFPlugin::setActiveAnnotation(PDFAnnotation *annotation)
1690 {
1691     if (!supportsForms())
1692         return;
1693
1694     if (m_activeAnnotation)
1695         m_activeAnnotation->commit();
1696
1697     if (annotation) {
1698 #pragma clang diagnostic push
1699 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
1700         if ([annotation isKindOfClass:pdfAnnotationTextWidgetClass()] && static_cast<PDFAnnotationTextWidget *>(annotation).isReadOnly) {
1701             m_activeAnnotation = nullptr;
1702             return;
1703         }
1704 #pragma clang diagnostic pop
1705
1706         m_activeAnnotation = PDFPluginAnnotation::create(annotation, m_pdfLayerController.get(), this);
1707         m_activeAnnotation->attach(m_annotationContainer.get());
1708     } else
1709         m_activeAnnotation = nullptr;
1710 }
1711
1712 bool PDFPlugin::supportsForms()
1713 {
1714     // FIXME: We support forms for full-main-frame and <iframe> PDFs, but not <embed> or <object>, because those cases do not have their own Document into which to inject form elements.
1715     return isFullFramePlugin();
1716 }
1717
1718 void PDFPlugin::notifyContentScaleFactorChanged(CGFloat scaleFactor)
1719 {
1720     if (handlesPageScaleFactor())
1721         pluginView()->setPageScaleFactor(scaleFactor, IntPoint());
1722
1723     calculateSizes();
1724     updateScrollbars();
1725 }
1726
1727 void PDFPlugin::notifyDisplayModeChanged(int)
1728 {
1729     calculateSizes();
1730     updateScrollbars();
1731 }
1732
1733 RefPtr<SharedBuffer> PDFPlugin::liveResourceData() const
1734 {
1735     NSData *pdfData = liveData();
1736
1737     if (!pdfData)
1738         return nullptr;
1739
1740     return SharedBuffer::create(pdfData);
1741 }
1742
1743 bool PDFPlugin::pluginHandlesContentOffsetForAccessibilityHitTest() const
1744 {
1745     // The PDF plugin handles the scroll view offset natively as part of the layer conversions.
1746 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
1747     return true;
1748 #else
1749     return false;
1750 #endif
1751 }
1752
1753     
1754 void PDFPlugin::saveToPDF()
1755 {
1756     // FIXME: We should probably notify the user that they can't save before the document is finished loading.
1757     // PDFViewController does an NSBeep(), but that seems insufficient.
1758     if (!pdfDocument())
1759         return;
1760
1761     NSData *data = liveData();
1762     webFrame()->page()->savePDFToFileInDownloadsFolder(m_suggestedFilename, webFrame()->url(), static_cast<const unsigned char *>([data bytes]), [data length]);
1763 }
1764
1765 void PDFPlugin::openWithNativeApplication()
1766 {
1767     if (!m_temporaryPDFUUID) {
1768         // FIXME: We should probably notify the user that they can't save before the document is finished loading.
1769         // PDFViewController does an NSBeep(), but that seems insufficient.
1770         if (!pdfDocument())
1771             return;
1772
1773         NSData *data = liveData();
1774
1775         m_temporaryPDFUUID = createCanonicalUUIDString();
1776         ASSERT(m_temporaryPDFUUID);
1777
1778         webFrame()->page()->savePDFToTemporaryFolderAndOpenWithNativeApplication(m_suggestedFilename, webFrame()->url(), static_cast<const unsigned char *>([data bytes]), [data length], m_temporaryPDFUUID);
1779         return;
1780     }
1781
1782     webFrame()->page()->send(Messages::WebPageProxy::OpenPDFFromTemporaryFolderWithNativeApplication(m_temporaryPDFUUID));
1783 }
1784
1785 void PDFPlugin::writeItemsToPasteboard(NSString *pasteboardName, NSArray *items, NSArray *types)
1786 {
1787     Vector<String> pasteboardTypes;
1788
1789     for (NSString *type in types)
1790         pasteboardTypes.append(type);
1791
1792     uint64_t newChangeCount;
1793     auto& webProcess = WebProcess::singleton();
1794     webProcess.parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::SetPasteboardTypes(pasteboardName, pasteboardTypes),
1795         Messages::WebPasteboardProxy::SetPasteboardTypes::Reply(newChangeCount), 0);
1796
1797     for (NSUInteger i = 0, count = items.count; i < count; ++i) {
1798         NSString *type = [types objectAtIndex:i];
1799         NSData *data = [items objectAtIndex:i];
1800
1801         // We don't expect the data for any items to be empty, but aren't completely sure.
1802         // Avoid crashing in the SharedMemory constructor in release builds if we're wrong.
1803         ASSERT(data.length);
1804         if (!data.length)
1805             continue;
1806
1807         if ([type isEqualToString:legacyStringPasteboardType()] || [type isEqualToString:NSPasteboardTypeString]) {
1808             RetainPtr<NSString> plainTextString = adoptNS([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
1809             webProcess.parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::SetPasteboardStringForType(pasteboardName, type, plainTextString.get()), Messages::WebPasteboardProxy::SetPasteboardStringForType::Reply(newChangeCount), 0);
1810         } else {
1811             RefPtr<SharedBuffer> buffer = SharedBuffer::create(data);
1812
1813             if (!buffer)
1814                 continue;
1815
1816             SharedMemory::Handle handle;
1817             RefPtr<SharedMemory> sharedMemory = SharedMemory::allocate(buffer->size());
1818             memcpy(sharedMemory->data(), buffer->data(), buffer->size());
1819             sharedMemory->createHandle(handle, SharedMemory::Protection::ReadOnly);
1820             webProcess.parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::SetPasteboardBufferForType(pasteboardName, type, handle, buffer->size()), Messages::WebPasteboardProxy::SetPasteboardBufferForType::Reply(newChangeCount), 0);
1821         }
1822     }
1823 }
1824
1825 void PDFPlugin::showDefinitionForAttributedString(NSAttributedString *string, CGPoint point)
1826 {
1827     DictionaryPopupInfo dictionaryPopupInfo;
1828     dictionaryPopupInfo.origin = convertFromPDFViewToRootView(IntPoint(point));
1829     dictionaryPopupInfo.attributedString = string;
1830
1831     webFrame()->page()->send(Messages::WebPageProxy::DidPerformDictionaryLookup(dictionaryPopupInfo));
1832 }
1833
1834 unsigned PDFPlugin::countFindMatches(const String& target, WebCore::FindOptions options, unsigned /*maxMatchCount*/)
1835 {
1836     // FIXME: Why is it OK to ignore the passed-in maximum match count?
1837
1838     if (!target.length())
1839         return 0;
1840
1841     NSStringCompareOptions nsOptions = options.contains(WebCore::CaseInsensitive) ? NSCaseInsensitiveSearch : 0;
1842     return [[pdfDocument() findString:target withOptions:nsOptions] count];
1843 }
1844
1845 PDFSelection *PDFPlugin::nextMatchForString(const String& target, BOOL searchForward, BOOL caseSensitive, BOOL wrapSearch, PDFSelection *initialSelection, BOOL startInSelection)
1846 {
1847     if (!target.length())
1848         return nil;
1849
1850     NSStringCompareOptions options = 0;
1851     if (!searchForward)
1852         options |= NSBackwardsSearch;
1853     if (!caseSensitive)
1854         options |= NSCaseInsensitiveSearch;
1855
1856     PDFDocument *document = pdfDocument().get();
1857
1858     RetainPtr<PDFSelection> selectionForInitialSearch = adoptNS([initialSelection copy]);
1859     if (startInSelection) {
1860         // Initially we want to include the selected text in the search. So we must modify the starting search
1861         // selection to fit PDFDocument's search requirements: selection must have a length >= 1, begin before
1862         // the current selection (if searching forwards) or after (if searching backwards).
1863         int initialSelectionLength = [[initialSelection string] length];
1864         if (searchForward) {
1865             [selectionForInitialSearch extendSelectionAtStart:1];
1866             [selectionForInitialSearch extendSelectionAtEnd:-initialSelectionLength];
1867         } else {
1868             [selectionForInitialSearch extendSelectionAtEnd:1];
1869             [selectionForInitialSearch extendSelectionAtStart:-initialSelectionLength];
1870         }
1871     }
1872
1873     PDFSelection *foundSelection = [document findString:target fromSelection:selectionForInitialSearch.get() withOptions:options];
1874
1875     // If we first searched in the selection, and we found the selection, search again from just past the selection.
1876     if (startInSelection && [foundSelection isEqual:initialSelection])
1877         foundSelection = [document findString:target fromSelection:initialSelection withOptions:options];
1878
1879     if (!foundSelection && wrapSearch) {
1880         auto emptySelection = adoptNS([[pdfSelectionClass() alloc] initWithDocument:document]);
1881         foundSelection = [document findString:target fromSelection:emptySelection.get() withOptions:options];
1882     }
1883
1884     return foundSelection;
1885 }
1886
1887 bool PDFPlugin::findString(const String& target, WebCore::FindOptions options, unsigned maxMatchCount)
1888 {
1889     bool searchForward = !options.contains(WebCore::Backwards);
1890     bool caseSensitive = !options.contains(WebCore::CaseInsensitive);
1891     bool wrapSearch = options.contains(WebCore::WrapAround);
1892
1893     // If the max was zero, any result means we exceeded the max, so we can skip computing the actual count.
1894     // FIXME: How can always returning true without searching if passed a max of 0 be right?
1895     // Even if it is right, why not put that special case inside countFindMatches instead of here?
1896     bool foundMatch = !maxMatchCount || countFindMatches(target, options, maxMatchCount);
1897
1898     if (target.isEmpty()) {
1899         auto searchSelection = [m_pdfLayerController searchSelection];
1900         [m_pdfLayerController findString:target caseSensitive:caseSensitive highlightMatches:YES];
1901         [m_pdfLayerController setSearchSelection:searchSelection];
1902         m_lastFoundString = emptyString();
1903         return false;
1904     }
1905
1906     if (m_lastFoundString == target) {
1907         auto selection = nextMatchForString(target, searchForward, caseSensitive, wrapSearch, [m_pdfLayerController searchSelection], NO);
1908         if (!selection)
1909             return false;
1910         [m_pdfLayerController setSearchSelection:selection];
1911         [m_pdfLayerController gotoSelection:selection];
1912     } else {
1913         [m_pdfLayerController findString:target caseSensitive:caseSensitive highlightMatches:YES];
1914         m_lastFoundString = target;
1915     }
1916
1917     return foundMatch;
1918 }
1919
1920 bool PDFPlugin::performDictionaryLookupAtLocation(const WebCore::FloatPoint& point)
1921 {
1922     IntPoint localPoint = convertFromRootViewToPlugin(roundedIntPoint(point));
1923     PDFSelection* lookupSelection = [m_pdfLayerController getSelectionForWordAtPoint:convertFromPluginToPDFView(localPoint)];
1924     if ([[lookupSelection string] length])
1925         [m_pdfLayerController searchInDictionaryWithSelection:lookupSelection];
1926     return true;
1927 }
1928
1929 void PDFPlugin::focusNextAnnotation()
1930 {
1931     [m_pdfLayerController activateNextAnnotation:false];
1932 }
1933
1934 void PDFPlugin::focusPreviousAnnotation()
1935 {
1936     [m_pdfLayerController activateNextAnnotation:true];
1937 }
1938
1939 void PDFPlugin::notifySelectionChanged(PDFSelection *)
1940 {
1941     webFrame()->page()->didChangeSelection();
1942 }
1943
1944 static const Cursor& coreCursor(PDFLayerControllerCursorType type)
1945 {
1946     switch (type) {
1947     case kPDFLayerControllerCursorTypeHand:
1948         return handCursor();
1949     case kPDFLayerControllerCursorTypeIBeam:
1950         return iBeamCursor();
1951     case kPDFLayerControllerCursorTypePointer:
1952     default:
1953         return pointerCursor();
1954     }
1955 }
1956
1957 void PDFPlugin::notifyCursorChanged(uint64_t type)
1958 {
1959     webFrame()->page()->send(Messages::WebPageProxy::SetCursor(coreCursor(static_cast<PDFLayerControllerCursorType>(type))));
1960 }
1961
1962 String PDFPlugin::getSelectionString() const
1963 {
1964     return [[m_pdfLayerController currentSelection] string];
1965 }
1966
1967 String PDFPlugin::getSelectionForWordAtPoint(const WebCore::FloatPoint& point) const
1968 {
1969     IntPoint pointInView = convertFromPluginToPDFView(convertFromRootViewToPlugin(roundedIntPoint(point)));
1970     PDFSelection *selectionForWord = [m_pdfLayerController getSelectionForWordAtPoint:pointInView];
1971     [m_pdfLayerController setCurrentSelection:selectionForWord];
1972     return [selectionForWord string];
1973 }
1974
1975 bool PDFPlugin::existingSelectionContainsPoint(const WebCore::FloatPoint& locationInViewCoordinates) const
1976 {
1977     PDFSelection *currentSelection = [m_pdfLayerController currentSelection];
1978     if (!currentSelection)
1979         return false;
1980     
1981     IntPoint pointInPDFView = convertFromPluginToPDFView(convertFromRootViewToPlugin(roundedIntPoint(locationInViewCoordinates)));
1982     PDFSelection *selectionForWord = [m_pdfLayerController getSelectionForWordAtPoint:pointInPDFView];
1983
1984     NSUInteger currentPageIndex = [m_pdfLayerController currentPageIndex];
1985     
1986     NSArray *selectionRects = [m_pdfLayerController rectsForSelectionInLayoutSpace:currentSelection];
1987     if (!selectionRects || !selectionRects.count)
1988         return false;
1989     
1990     if (currentPageIndex >= selectionRects.count)
1991         currentPageIndex = selectionRects.count - 1;
1992
1993     NSArray *wordSelectionRects = [m_pdfLayerController rectsForSelectionInLayoutSpace:selectionForWord];
1994     if (!wordSelectionRects || !wordSelectionRects.count)
1995         return false;
1996
1997     NSValue *selectionBounds = [selectionRects objectAtIndex:currentPageIndex];
1998     NSValue *wordSelectionBounds = [wordSelectionRects objectAtIndex:0];
1999
2000     NSRect selectionBoundsRect = selectionBounds.rectValue;
2001     NSRect wordSelectionBoundsRect = wordSelectionBounds.rectValue;
2002     return NSIntersectsRect(wordSelectionBoundsRect, selectionBoundsRect);
2003 }
2004
2005 static NSPoint pointInLayoutSpaceForPointInWindowSpace(PDFLayerController* pdfLayerController, NSPoint pointInView)
2006 {
2007     CGPoint point = NSPointToCGPoint(pointInView);
2008     CGPoint scrollOffset = [pdfLayerController scrollPosition];
2009     CGFloat scaleFactor = [pdfLayerController contentScaleFactor];
2010
2011     scrollOffset.y = [pdfLayerController contentSizeRespectingZoom].height - NSRectToCGRect([pdfLayerController frame]).size.height - scrollOffset.y;
2012
2013     CGPoint newPoint = CGPointMake(scrollOffset.x + point.x, scrollOffset.y + point.y);
2014     newPoint.x /= scaleFactor;
2015     newPoint.y /= scaleFactor;
2016     return NSPointFromCGPoint(newPoint);
2017 }
2018
2019 std::tuple<String, PDFSelection *, NSDictionary *> PDFPlugin::lookupTextAtLocation(const WebCore::FloatPoint& locationInViewCoordinates, WebHitTestResultData& data) const
2020 {
2021     auto selection = [m_pdfLayerController currentSelection];
2022     if (existingSelectionContainsPoint(locationInViewCoordinates))
2023         return { selection.string, selection, nil };
2024
2025     IntPoint pointInPDFView = convertFromPluginToPDFView(convertFromRootViewToPlugin(roundedIntPoint(locationInViewCoordinates)));
2026     selection = [m_pdfLayerController getSelectionForWordAtPoint:pointInPDFView];
2027     if (!selection)
2028         return { emptyString(), nil, nil };
2029
2030     NSPoint pointInLayoutSpace = pointInLayoutSpaceForPointInWindowSpace(m_pdfLayerController.get(), pointInPDFView);
2031     PDFPage *currentPage = [[m_pdfLayerController layout] pageNearestPoint:pointInLayoutSpace currentPage:[m_pdfLayerController currentPage]];
2032     NSPoint pointInPageSpace = [[m_pdfLayerController layout] convertPoint:pointInLayoutSpace toPage:currentPage forScaleFactor:1.0];
2033
2034     for (PDFAnnotation *annotation in currentPage.annotations) {
2035         if (![annotation isKindOfClass:pdfAnnotationLinkClass()])
2036             continue;
2037
2038         NSRect bounds = annotation.bounds;
2039         if (!NSPointInRect(pointInPageSpace, bounds))
2040             continue;
2041
2042 #pragma clang diagnostic push
2043 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2044         PDFAnnotationLink *linkAnnotation = (PDFAnnotationLink *)annotation;
2045 #pragma clang diagnostic pop
2046         NSURL *url = linkAnnotation.URL;
2047         if (!url)
2048             continue;
2049
2050         data.absoluteLinkURL = url.absoluteString;
2051         data.linkLabel = selection.string;
2052         return { selection.string, selection, nil };
2053     }
2054
2055     NSDictionary *options = nil;
2056     NSString *lookupText = DictionaryLookup::stringForPDFSelection(selection, &options);
2057     if (!lookupText.length)
2058         return { emptyString(), selection, nil };
2059
2060     [m_pdfLayerController setCurrentSelection:selection];
2061     return { lookupText, selection, options };
2062 }
2063
2064 static NSRect rectInViewSpaceForRectInLayoutSpace(PDFLayerController* pdfLayerController, NSRect layoutSpaceRect)
2065 {
2066     CGRect newRect = NSRectToCGRect(layoutSpaceRect);
2067     CGFloat scaleFactor = pdfLayerController.contentScaleFactor;
2068     CGPoint scrollOffset = pdfLayerController.scrollPosition;
2069
2070     scrollOffset.y = pdfLayerController.contentSizeRespectingZoom.height - NSRectToCGRect(pdfLayerController.frame).size.height - scrollOffset.y;
2071
2072     newRect.origin.x *= scaleFactor;
2073     newRect.origin.y *= scaleFactor;
2074     newRect.size.width *= scaleFactor;
2075     newRect.size.height *= scaleFactor;
2076
2077     newRect.origin.x -= scrollOffset.x;
2078     newRect.origin.y -= scrollOffset.y;
2079
2080     return NSRectFromCGRect(newRect);
2081 }
2082     
2083 WebCore::AXObjectCache* PDFPlugin::axObjectCache() const
2084 {
2085     return webFrame()->coreFrame()->document()->axObjectCache();
2086 }
2087
2088 WebCore::FloatRect PDFPlugin::rectForSelectionInRootView(PDFSelection *selection) const
2089 {
2090     PDFPage *currentPage = nil;
2091     NSArray *pages = selection.pages;
2092     if (pages.count)
2093         currentPage = (PDFPage *)[pages objectAtIndex:0];
2094
2095     if (!currentPage)
2096         currentPage = [m_pdfLayerController currentPage];
2097
2098     NSRect rectInPageSpace = [selection boundsForPage:currentPage];
2099     NSRect rectInLayoutSpace = [[m_pdfLayerController layout] convertRect:rectInPageSpace fromPage:currentPage forScaleFactor:1.0];
2100     NSRect rectInView = rectInViewSpaceForRectInLayoutSpace(m_pdfLayerController.get(), rectInLayoutSpace);
2101
2102     rectInView.origin = convertFromPDFViewToRootView(IntPoint(rectInView.origin));
2103
2104     return rectInView;
2105 }
2106
2107 CGFloat PDFPlugin::scaleFactor() const
2108 {
2109     return [m_pdfLayerController contentScaleFactor];
2110 }
2111
2112 void PDFPlugin::performWebSearch(NSString *string)
2113 {
2114     webFrame()->page()->send(Messages::WebPageProxy::SearchTheWeb(string));
2115 }
2116
2117 void PDFPlugin::performSpotlightSearch(NSString *string)
2118 {
2119     webFrame()->page()->send(Messages::WebPageProxy::SearchWithSpotlight(string));
2120 }
2121
2122 bool PDFPlugin::handleWheelEvent(const WebWheelEvent& event)
2123 {
2124     PDFDisplayMode displayMode = [m_pdfLayerController displayMode];
2125
2126     if (displayMode == kPDFDisplaySinglePageContinuous || displayMode == kPDFDisplayTwoUpContinuous)
2127         return ScrollableArea::handleWheelEvent(platform(event));
2128
2129     NSUInteger currentPageIndex = [m_pdfLayerController currentPageIndex];
2130     bool inFirstPage = !currentPageIndex;
2131     bool inLastPage = [m_pdfLayerController lastPageIndex] == currentPageIndex;
2132
2133     bool atScrollTop = !scrollPosition().y();
2134     bool atScrollBottom = scrollPosition().y() == maximumScrollPosition().y();
2135
2136     bool inMomentumScroll = event.momentumPhase() != WebWheelEvent::PhaseNone;
2137
2138     int scrollMagnitudeThresholdForPageFlip = defaultScrollMagnitudeThresholdForPageFlip;
2139
2140     // Imprecise input devices should have a lower threshold so that "clicky" scroll wheels can flip pages.
2141     if (!event.hasPreciseScrollingDeltas())
2142         scrollMagnitudeThresholdForPageFlip = 0;
2143
2144     if (atScrollBottom && !inLastPage && event.delta().height() < 0) {
2145         if (event.delta().height() <= -scrollMagnitudeThresholdForPageFlip && !inMomentumScroll)
2146             [m_pdfLayerController gotoNextPage];
2147         return true;
2148     }
2149
2150     if (atScrollTop && !inFirstPage && event.delta().height() > 0) {
2151         if (event.delta().height() >= scrollMagnitudeThresholdForPageFlip && !inMomentumScroll) {
2152             [CATransaction begin];
2153             [m_pdfLayerController gotoPreviousPage];
2154             scrollToOffsetWithoutAnimation(maximumScrollPosition());
2155             [CATransaction commit];
2156         }
2157         return true;
2158     }
2159
2160     return ScrollableArea::handleWheelEvent(platform(event));
2161 }
2162
2163 NSData *PDFPlugin::liveData() const
2164 {
2165     if (m_activeAnnotation)
2166         m_activeAnnotation->commit();
2167
2168     // Save data straight from the resource instead of PDFKit if the document is
2169     // untouched by the user, so that PDFs which PDFKit can't display will still be downloadable.
2170     if (m_pdfDocumentWasMutated)
2171         return [m_pdfDocument dataRepresentation];
2172
2173     return rawData();
2174 }
2175
2176 id PDFPlugin::accessibilityAssociatedPluginParentForElement(WebCore::Element* element) const
2177 {
2178 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
2179     if (!m_activeAnnotation)
2180         return nil;
2181
2182     if (m_activeAnnotation->element() != element)
2183         return nil;
2184
2185     return [m_activeAnnotation->annotation() accessibilityNode];
2186 #else
2187     return nil;
2188 #endif
2189 }
2190
2191 NSObject *PDFPlugin::accessibilityObject() const
2192 {
2193     return m_accessibilityObject.get();
2194 }
2195
2196 } // namespace WebKit
2197
2198 #endif // ENABLE(PDFKIT_PLUGIN)