2
* Copyright (C) 2009, 2011, 2012 Apple Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
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.
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.
27
#import "SimplePDFPlugin.h"
29
#import "PDFKitImports.h"
30
#import "PluginView.h"
31
#import "ShareableBitmap.h"
33
#import "WebEventConversion.h"
34
#import <JavaScriptCore/JSContextRef.h>
35
#import <JavaScriptCore/JSObjectRef.h>
36
#import <JavaScriptCore/JSStringRef.h>
37
#import <JavaScriptCore/JSStringRefCF.h>
38
#import <PDFKit/PDFKit.h>
39
#import <WebCore/ArchiveResource.h>
40
#import <WebCore/Chrome.h>
41
#import <WebCore/DocumentLoader.h>
42
#import <WebCore/FocusController.h>
43
#import <WebCore/Frame.h>
44
#import <WebCore/FrameView.h>
45
#import <WebCore/GraphicsContext.h>
46
#import <WebCore/HTTPHeaderMap.h>
47
#import <WebCore/LocalizedStrings.h>
48
#import <WebCore/Page.h>
49
#import <WebCore/PluginData.h>
50
#import <WebCore/RenderBoxModelObject.h>
51
#import <WebCore/ScrollAnimator.h>
52
#import <WebCore/ScrollbarTheme.h>
54
using namespace WebCore;
57
static void appendValuesInPDFNameSubtreeToVector(CGPDFDictionaryRef subtree, Vector<CGPDFObjectRef>& values)
60
if (CGPDFDictionaryGetArray(subtree, "Names", &names)) {
61
size_t nameCount = CGPDFArrayGetCount(names) / 2;
62
for (size_t i = 0; i < nameCount; ++i) {
63
CGPDFObjectRef object;
64
CGPDFArrayGetObject(names, 2 * i + 1, &object);
65
values.append(object);
71
if (!CGPDFDictionaryGetArray(subtree, "Kids", &kids))
74
size_t kidCount = CGPDFArrayGetCount(kids);
75
for (size_t i = 0; i < kidCount; ++i) {
76
CGPDFDictionaryRef kid;
77
if (!CGPDFArrayGetDictionary(kids, i, &kid))
79
appendValuesInPDFNameSubtreeToVector(kid, values);
83
static void getAllValuesInPDFNameTree(CGPDFDictionaryRef tree, Vector<CGPDFObjectRef>& allValues)
85
appendValuesInPDFNameSubtreeToVector(tree, allValues);
88
static void getAllScriptsInPDFDocument(CGPDFDocumentRef pdfDocument, Vector<RetainPtr<CFStringRef> >& scripts)
93
CGPDFDictionaryRef pdfCatalog = CGPDFDocumentGetCatalog(pdfDocument);
97
// Get the dictionary of all document-level name trees.
98
CGPDFDictionaryRef namesDictionary;
99
if (!CGPDFDictionaryGetDictionary(pdfCatalog, "Names", &namesDictionary))
102
// Get the document-level "JavaScript" name tree.
103
CGPDFDictionaryRef javaScriptNameTree;
104
if (!CGPDFDictionaryGetDictionary(namesDictionary, "JavaScript", &javaScriptNameTree))
107
// The names are arbitrary. We are only interested in the values.
108
Vector<CGPDFObjectRef> objects;
109
getAllValuesInPDFNameTree(javaScriptNameTree, objects);
110
size_t objectCount = objects.size();
112
for (size_t i = 0; i < objectCount; ++i) {
113
CGPDFDictionaryRef javaScriptAction;
114
if (!CGPDFObjectGetValue(reinterpret_cast<CGPDFObjectRef>(objects[i]), kCGPDFObjectTypeDictionary, &javaScriptAction))
117
// A JavaScript action must have an action type of "JavaScript".
118
const char* actionType;
119
if (!CGPDFDictionaryGetName(javaScriptAction, "S", &actionType) || strcmp(actionType, "JavaScript"))
122
const UInt8* bytes = 0;
124
CGPDFStreamRef stream;
125
CGPDFStringRef string;
126
RetainPtr<CFDataRef> data;
127
if (CGPDFDictionaryGetStream(javaScriptAction, "JS", &stream)) {
128
CGPDFDataFormat format;
129
data.adoptCF(CGPDFStreamCopyData(stream, &format));
132
bytes = CFDataGetBytePtr(data.get());
133
length = CFDataGetLength(data.get());
134
} else if (CGPDFDictionaryGetString(javaScriptAction, "JS", &string)) {
135
bytes = CGPDFStringGetBytePtr(string);
136
length = CGPDFStringGetLength(string);
141
CFStringEncoding encoding = (length > 1 && bytes[0] == 0xFE && bytes[1] == 0xFF) ? kCFStringEncodingUnicode : kCFStringEncodingUTF8;
142
RetainPtr<CFStringRef> script(AdoptCF, CFStringCreateWithBytes(kCFAllocatorDefault, bytes, length, encoding, true));
146
scripts.append(script);
152
const uint64_t pdfDocumentRequestID = 1; // PluginController supports loading multiple streams, but we only need one for PDF.
154
const int gutterHeight = 10;
155
const int shadowOffsetX = 0;
156
const int shadowOffsetY = -2;
157
const int shadowSize = 7;
159
PassRefPtr<SimplePDFPlugin> SimplePDFPlugin::create(WebFrame* frame)
161
return adoptRef(new SimplePDFPlugin(frame));
164
SimplePDFPlugin::SimplePDFPlugin(WebFrame* frame)
169
SimplePDFPlugin::~SimplePDFPlugin()
173
PluginInfo SimplePDFPlugin::pluginInfo()
176
info.name = builtInPDFPluginName();
178
MimeClassInfo mimeClassInfo;
179
mimeClassInfo.type = "application/pdf";
180
mimeClassInfo.desc = pdfDocumentTypeDescription();
181
mimeClassInfo.extensions.append("pdf");
183
info.mimes.append(mimeClassInfo);
187
PluginView* SimplePDFPlugin::pluginView()
189
return static_cast<PluginView*>(controller());
192
const PluginView* SimplePDFPlugin::pluginView() const
194
return static_cast<const PluginView*>(controller());
197
void SimplePDFPlugin::updateScrollbars()
199
bool hadScrollbars = m_horizontalScrollbar || m_verticalScrollbar;
201
if (m_horizontalScrollbar) {
202
if (m_size.width() >= m_pdfDocumentSize.width())
203
destroyScrollbar(HorizontalScrollbar);
204
} else if (m_size.width() < m_pdfDocumentSize.width())
205
m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
207
if (m_verticalScrollbar) {
208
if (m_size.height() >= m_pdfDocumentSize.height())
209
destroyScrollbar(VerticalScrollbar);
210
} else if (m_size.height() < m_pdfDocumentSize.height())
211
m_verticalScrollbar = createScrollbar(VerticalScrollbar);
213
int horizontalScrollbarHeight = (m_horizontalScrollbar && !m_horizontalScrollbar->isOverlayScrollbar()) ? m_horizontalScrollbar->height() : 0;
214
int verticalScrollbarWidth = (m_verticalScrollbar && !m_verticalScrollbar->isOverlayScrollbar()) ? m_verticalScrollbar->width() : 0;
216
int pageStep = m_pageBoxes.isEmpty() ? 0 : m_pageBoxes[0].height();
218
if (m_horizontalScrollbar) {
219
m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
220
m_horizontalScrollbar->setProportion(m_size.width() - verticalScrollbarWidth, m_pdfDocumentSize.width());
221
IntRect scrollbarRect(pluginView()->x(), pluginView()->y() + m_size.height() - m_horizontalScrollbar->height(), m_size.width(), m_horizontalScrollbar->height());
222
if (m_verticalScrollbar)
223
scrollbarRect.contract(m_verticalScrollbar->width(), 0);
224
m_horizontalScrollbar->setFrameRect(scrollbarRect);
226
if (m_verticalScrollbar) {
227
m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
228
m_verticalScrollbar->setProportion(m_size.height() - horizontalScrollbarHeight, m_pdfDocumentSize.height());
229
IntRect scrollbarRect(IntRect(pluginView()->x() + m_size.width() - m_verticalScrollbar->width(), pluginView()->y(), m_verticalScrollbar->width(), m_size.height()));
230
if (m_horizontalScrollbar)
231
scrollbarRect.contract(0, m_horizontalScrollbar->height());
232
m_verticalScrollbar->setFrameRect(scrollbarRect);
235
FrameView* frameView = m_frame->coreFrame()->view();
239
bool hasScrollbars = m_horizontalScrollbar || m_verticalScrollbar;
240
if (hadScrollbars != hasScrollbars) {
242
frameView->addScrollableArea(this);
244
frameView->removeScrollableArea(this);
246
frameView->setNeedsLayout();
250
PassRefPtr<Scrollbar> SimplePDFPlugin::createScrollbar(ScrollbarOrientation orientation)
252
RefPtr<Scrollbar> widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
253
if (orientation == HorizontalScrollbar)
254
didAddHorizontalScrollbar(widget.get());
256
didAddVerticalScrollbar(widget.get());
257
pluginView()->frame()->view()->addChild(widget.get());
258
return widget.release();
261
void SimplePDFPlugin::destroyScrollbar(ScrollbarOrientation orientation)
263
RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_horizontalScrollbar : m_verticalScrollbar;
267
if (orientation == HorizontalScrollbar)
268
willRemoveHorizontalScrollbar(scrollbar.get());
270
willRemoveVerticalScrollbar(scrollbar.get());
272
scrollbar->removeFromParent();
273
scrollbar->disconnectFromScrollableArea();
277
void SimplePDFPlugin::addArchiveResource()
279
// FIXME: It's a hack to force add a resource to DocumentLoader. PDF documents should just be fetched as CachedResources.
281
// Add just enough data for context menu handling and web archives to work.
282
ResourceResponse synthesizedResponse;
283
synthesizedResponse.setSuggestedFilename(m_suggestedFilename);
284
synthesizedResponse.setURL(m_sourceURL); // Needs to match the HitTestResult::absolutePDFURL.
285
synthesizedResponse.setMimeType("application/pdf");
287
RefPtr<ArchiveResource> resource = ArchiveResource::create(SharedBuffer::wrapCFData(m_data.get()), m_sourceURL, "application/pdf", String(), String(), synthesizedResponse);
288
pluginView()->frame()->document()->loader()->addArchiveResource(resource.release());
291
static void jsPDFDocInitialize(JSContextRef ctx, JSObjectRef object)
293
SimplePDFPlugin* pdfView = static_cast<SimplePDFPlugin*>(JSObjectGetPrivate(object));
297
static void jsPDFDocFinalize(JSObjectRef object)
299
SimplePDFPlugin* pdfView = static_cast<SimplePDFPlugin*>(JSObjectGetPrivate(object));
303
JSValueRef SimplePDFPlugin::jsPDFDocPrint(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
305
SimplePDFPlugin* pdfView = static_cast<SimplePDFPlugin*>(JSObjectGetPrivate(thisObject));
307
WebFrame* frame = pdfView->m_frame;
309
return JSValueMakeUndefined(ctx);
311
Frame* coreFrame = frame->coreFrame();
313
return JSValueMakeUndefined(ctx);
315
Page* page = coreFrame->page();
317
return JSValueMakeUndefined(ctx);
319
page->chrome()->print(coreFrame);
321
return JSValueMakeUndefined(ctx);
324
JSObjectRef SimplePDFPlugin::makeJSPDFDoc(JSContextRef ctx)
326
static JSStaticFunction jsPDFDocStaticFunctions[] = {
327
{ "print", jsPDFDocPrint, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
331
static JSClassDefinition jsPDFDocClassDefinition = {
333
kJSClassAttributeNone,
337
jsPDFDocStaticFunctions,
338
jsPDFDocInitialize, jsPDFDocFinalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
341
static JSClassRef jsPDFDocClass = JSClassCreate(&jsPDFDocClassDefinition);
343
return JSObjectMake(ctx, jsPDFDocClass, this);
346
void SimplePDFPlugin::pdfDocumentDidLoad()
348
addArchiveResource();
350
m_pdfDocument.adoptNS([[pdfDocumentClass() alloc] initWithData:(NSData *)m_data.get()]);
355
controller()->invalidate(IntRect(0, 0, m_size.width(), m_size.height()));
357
runScriptsInPDFDocument();
360
void SimplePDFPlugin::runScriptsInPDFDocument()
362
Vector<RetainPtr<CFStringRef> > scripts;
363
getAllScriptsInPDFDocument([m_pdfDocument.get() documentRef], scripts);
365
size_t scriptCount = scripts.size();
369
JSGlobalContextRef ctx = JSGlobalContextCreate(0);
370
JSObjectRef jsPDFDoc = makeJSPDFDoc(ctx);
372
for (size_t i = 0; i < scriptCount; ++i) {
373
JSStringRef script = JSStringCreateWithCFString(scripts[i].get());
374
JSEvaluateScript(ctx, script, jsPDFDoc, 0, 0, 0);
375
JSStringRelease(script);
378
JSGlobalContextRelease(ctx);
381
void SimplePDFPlugin::computePageBoxes()
383
size_t pageCount = CGPDFDocumentGetNumberOfPages([m_pdfDocument.get() documentRef]);
384
for (size_t i = 0; i < pageCount; ++i) {
385
CGPDFPageRef pdfPage = CGPDFDocumentGetPage([m_pdfDocument.get() documentRef], i + 1);
388
CGRect box = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
389
if (CGRectIsEmpty(box))
390
box = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
391
m_pageBoxes.append(IntRect(box));
395
void SimplePDFPlugin::calculateSizes()
397
size_t pageCount = CGPDFDocumentGetNumberOfPages([m_pdfDocument.get() documentRef]);
398
for (size_t i = 0; i < pageCount; ++i) {
399
CGPDFPageRef pdfPage = CGPDFDocumentGetPage([m_pdfDocument.get() documentRef], i + 1);
402
CGRect box = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
403
if (CGRectIsEmpty(box))
404
box = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
405
m_pageBoxes.append(IntRect(box));
406
m_pdfDocumentSize.setWidth(max(m_pdfDocumentSize.width(), static_cast<int>(box.size.width)));
407
m_pdfDocumentSize.expand(0, box.size.height);
409
m_pdfDocumentSize.expand(0, gutterHeight * (m_pageBoxes.size() - 1));
412
bool SimplePDFPlugin::initialize(const Parameters& parameters)
414
// Load the src URL if needed.
415
m_sourceURL = parameters.url;
416
if (!parameters.shouldUseManualLoader && !parameters.url.isEmpty())
417
controller()->loadURL(pdfDocumentRequestID, "GET", parameters.url.string(), String(), HTTPHeaderMap(), Vector<uint8_t>(), false);
419
controller()->didInitializePlugin();
423
void SimplePDFPlugin::destroy()
426
if (FrameView* frameView = m_frame->coreFrame()->view())
427
frameView->removeScrollableArea(this);
430
destroyScrollbar(HorizontalScrollbar);
431
destroyScrollbar(VerticalScrollbar);
434
void SimplePDFPlugin::paint(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
436
contentAreaWillPaint();
438
paintBackground(graphicsContext, dirtyRect);
440
if (!m_pdfDocument) // FIXME: Draw loading progress.
443
paintContent(graphicsContext, dirtyRect);
444
paintControls(graphicsContext, dirtyRect);
447
void SimplePDFPlugin::paintBackground(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
449
GraphicsContextStateSaver stateSaver(*graphicsContext);
450
graphicsContext->setFillColor(Color::gray, ColorSpaceDeviceRGB);
451
graphicsContext->fillRect(dirtyRect);
454
void SimplePDFPlugin::paintContent(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
456
GraphicsContextStateSaver stateSaver(*graphicsContext);
457
CGContextRef context = graphicsContext->platformContext();
459
graphicsContext->setImageInterpolationQuality(InterpolationHigh);
460
graphicsContext->setShouldAntialias(true);
461
graphicsContext->setShouldSmoothFonts(true);
462
graphicsContext->setFillColor(Color::white, ColorSpaceDeviceRGB);
464
graphicsContext->clip(dirtyRect);
465
IntRect contentRect(dirtyRect);
466
contentRect.moveBy(IntPoint(m_scrollOffset));
467
graphicsContext->translate(-m_scrollOffset.width(), -m_scrollOffset.height());
469
CGContextScaleCTM(context, 1, -1);
472
for (size_t i = 0; i < m_pageBoxes.size(); ++i) {
473
IntRect pageBox = m_pageBoxes[i];
474
float extraOffsetForCenteringX = max(roundf((m_size.width() - pageBox.width()) / 2.0f), 0.0f);
475
float extraOffsetForCenteringY = (m_pageBoxes.size() == 1) ? max(roundf((m_size.height() - pageBox.height() + shadowOffsetY) / 2.0f), 0.0f) : 0;
477
if (pageTop > contentRect.maxY())
479
if (pageTop + pageBox.height() + extraOffsetForCenteringY + gutterHeight >= contentRect.y()) {
480
CGPDFPageRef pdfPage = CGPDFDocumentGetPage([m_pdfDocument.get() documentRef], i + 1);
482
graphicsContext->save();
483
graphicsContext->translate(extraOffsetForCenteringX - pageBox.x(), -extraOffsetForCenteringY - pageBox.y() - pageBox.height());
485
graphicsContext->setShadow(FloatSize(shadowOffsetX, shadowOffsetY), shadowSize, Color::black, ColorSpaceDeviceRGB);
486
graphicsContext->fillRect(pageBox);
487
graphicsContext->clearShadow();
489
graphicsContext->clip(pageBox);
491
CGContextDrawPDFPage(context, pdfPage);
492
graphicsContext->restore();
494
pageTop += pageBox.height() + gutterHeight;
495
CGContextTranslateCTM(context, 0, -pageBox.height() - gutterHeight);
499
void SimplePDFPlugin::paintControls(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
502
GraphicsContextStateSaver stateSaver(*graphicsContext);
503
IntRect scrollbarDirtyRect = dirtyRect;
504
scrollbarDirtyRect.moveBy(pluginView()->frameRect().location());
505
graphicsContext->translate(-pluginView()->frameRect().x(), -pluginView()->frameRect().y());
507
if (m_horizontalScrollbar)
508
m_horizontalScrollbar->paint(graphicsContext, scrollbarDirtyRect);
510
if (m_verticalScrollbar)
511
m_verticalScrollbar->paint(graphicsContext, scrollbarDirtyRect);
514
IntRect dirtyCornerRect = intersection(scrollCornerRect(), dirtyRect);
515
ScrollbarTheme::theme()->paintScrollCorner(0, graphicsContext, dirtyCornerRect);
518
void SimplePDFPlugin::updateControlTints(GraphicsContext* graphicsContext)
520
ASSERT(graphicsContext->updatingControlTints());
522
if (m_horizontalScrollbar)
523
m_horizontalScrollbar->invalidate();
524
if (m_verticalScrollbar)
525
m_verticalScrollbar->invalidate();
526
invalidateScrollCorner(scrollCornerRect());
529
PassRefPtr<ShareableBitmap> SimplePDFPlugin::snapshot()
535
PlatformLayer* SimplePDFPlugin::pluginLayer()
542
bool SimplePDFPlugin::isTransparent()
544
// This should never be called from the web process.
545
ASSERT_NOT_REACHED();
549
bool SimplePDFPlugin::wantsWheelEvents()
554
void SimplePDFPlugin::geometryDidChange(const IntSize& size, const IntRect& clipRect, const AffineTransform& pluginToRootViewTransform)
556
if (m_size == size) {
565
void SimplePDFPlugin::visibilityDidChange()
569
void SimplePDFPlugin::frameDidFinishLoading(uint64_t)
571
ASSERT_NOT_REACHED();
574
void SimplePDFPlugin::frameDidFail(uint64_t, bool)
576
ASSERT_NOT_REACHED();
579
void SimplePDFPlugin::didEvaluateJavaScript(uint64_t, const WTF::String&)
581
ASSERT_NOT_REACHED();
584
void SimplePDFPlugin::streamDidReceiveResponse(uint64_t streamID, const KURL&, uint32_t, uint32_t, const String&, const String&, const String& suggestedFilename)
586
ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
588
m_suggestedFilename = suggestedFilename;
591
void SimplePDFPlugin::streamDidReceiveData(uint64_t streamID, const char* bytes, int length)
593
ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
596
m_data.adoptCF(CFDataCreateMutable(0, 0));
598
CFDataAppendBytes(m_data.get(), reinterpret_cast<const UInt8*>(bytes), length);
601
void SimplePDFPlugin::streamDidFinishLoading(uint64_t streamID)
603
ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
605
pdfDocumentDidLoad();
608
void SimplePDFPlugin::streamDidFail(uint64_t streamID, bool wasCancelled)
610
ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
615
void SimplePDFPlugin::manualStreamDidReceiveResponse(const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, const String& mimeType, const String& headers, const String& suggestedFilename)
617
m_suggestedFilename = suggestedFilename;
620
void SimplePDFPlugin::manualStreamDidReceiveData(const char* bytes, int length)
623
m_data.adoptCF(CFDataCreateMutable(0, 0));
625
CFDataAppendBytes(m_data.get(), reinterpret_cast<const UInt8*>(bytes), length);
628
void SimplePDFPlugin::manualStreamDidFinishLoading()
630
pdfDocumentDidLoad();
633
void SimplePDFPlugin::manualStreamDidFail(bool)
638
bool SimplePDFPlugin::handleMouseEvent(const WebMouseEvent& event)
640
switch (event.type()) {
641
case WebEvent::MouseMove:
642
mouseMovedInContentArea();
643
// FIXME: Should also notify scrollbar to show hover effect. Should also send mouseExited to hide it.
645
case WebEvent::MouseDown: {
646
// Returning false as will make EventHandler unfocus the plug-in, which is appropriate when clicking scrollbars.
647
// Ideally, we wouldn't change focus at all, but PluginView already did that for us.
648
// When support for PDF forms is added, we'll need to actually focus the plug-in when clicking in a form.
651
case WebEvent::MouseUp: {
652
PlatformMouseEvent platformEvent = platform(event);
653
if (m_horizontalScrollbar)
654
m_horizontalScrollbar->mouseUp(platformEvent);
655
if (m_verticalScrollbar)
656
m_verticalScrollbar->mouseUp(platformEvent);
666
bool SimplePDFPlugin::handleWheelEvent(const WebWheelEvent& event)
668
PlatformWheelEvent platformEvent = platform(event);
669
return ScrollableArea::handleWheelEvent(platformEvent);
672
bool SimplePDFPlugin::handleMouseEnterEvent(const WebMouseEvent&)
674
mouseEnteredContentArea();
678
bool SimplePDFPlugin::handleMouseLeaveEvent(const WebMouseEvent&)
680
mouseExitedContentArea();
684
bool SimplePDFPlugin::handleContextMenuEvent(const WebMouseEvent&)
686
// Use default WebKit context menu.
690
bool SimplePDFPlugin::handleKeyboardEvent(const WebKeyboardEvent&)
695
void SimplePDFPlugin::setFocus(bool hasFocus)
699
NPObject* SimplePDFPlugin::pluginScriptableNPObject()
706
void SimplePDFPlugin::windowFocusChanged(bool)
710
void SimplePDFPlugin::windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates)
714
void SimplePDFPlugin::windowVisibilityChanged(bool)
718
void SimplePDFPlugin::contentsScaleFactorChanged(float)
722
uint64_t SimplePDFPlugin::pluginComplexTextInputIdentifier() const
727
void SimplePDFPlugin::sendComplexTextInput(const String&)
731
void SimplePDFPlugin::setLayerHostingMode(LayerHostingMode)
737
void SimplePDFPlugin::storageBlockingStateChanged(bool)
741
void SimplePDFPlugin::privateBrowsingStateChanged(bool)
745
bool SimplePDFPlugin::getFormValue(String&)
750
bool SimplePDFPlugin::handleScroll(ScrollDirection direction, ScrollGranularity granularity)
752
return scroll(direction, granularity);
755
Scrollbar* SimplePDFPlugin::horizontalScrollbar()
757
return m_horizontalScrollbar.get();
760
Scrollbar* SimplePDFPlugin::verticalScrollbar()
762
return m_verticalScrollbar.get();
765
IntRect SimplePDFPlugin::scrollCornerRect() const
767
if (!m_horizontalScrollbar || !m_verticalScrollbar)
769
if (m_horizontalScrollbar->isOverlayScrollbar()) {
770
ASSERT(m_verticalScrollbar->isOverlayScrollbar());
773
return IntRect(pluginView()->width() - m_verticalScrollbar->width(), pluginView()->height() - m_horizontalScrollbar->height(), m_verticalScrollbar->width(), m_horizontalScrollbar->height());
776
ScrollableArea* SimplePDFPlugin::enclosingScrollableArea() const
778
// FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
782
IntRect SimplePDFPlugin::scrollableAreaBoundingBox() const
784
return pluginView()->frameRect();
787
void SimplePDFPlugin::setScrollOffset(const IntPoint& offset)
789
m_scrollOffset = IntSize(offset.x(), offset.y());
790
// FIXME: It would be better for performance to blit parts that remain visible.
791
controller()->invalidate(IntRect(0, 0, m_size.width(), m_size.height()));
794
int SimplePDFPlugin::scrollSize(ScrollbarOrientation orientation) const
796
Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
797
return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
800
bool SimplePDFPlugin::isActive() const
802
if (Frame* coreFrame = m_frame->coreFrame()) {
803
if (Page* page = coreFrame->page())
804
return page->focusController()->isActive();
810
void SimplePDFPlugin::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
812
IntRect dirtyRect = rect;
813
dirtyRect.moveBy(scrollbar->location());
814
dirtyRect.moveBy(-pluginView()->location());
815
controller()->invalidate(dirtyRect);
818
void SimplePDFPlugin::invalidateScrollCornerRect(const IntRect& rect)
820
controller()->invalidate(rect);
823
bool SimplePDFPlugin::isScrollCornerVisible() const
828
int SimplePDFPlugin::scrollPosition(Scrollbar* scrollbar) const
830
if (scrollbar->orientation() == HorizontalScrollbar)
831
return m_scrollOffset.width();
832
if (scrollbar->orientation() == VerticalScrollbar)
833
return m_scrollOffset.height();
834
ASSERT_NOT_REACHED();
838
IntPoint SimplePDFPlugin::scrollPosition() const
840
return IntPoint(m_scrollOffset.width(), m_scrollOffset.height());
843
IntPoint SimplePDFPlugin::minimumScrollPosition() const
845
return IntPoint(0, 0);
848
IntPoint SimplePDFPlugin::maximumScrollPosition() const
850
int horizontalScrollbarHeight = (m_horizontalScrollbar && !m_horizontalScrollbar->isOverlayScrollbar()) ? m_horizontalScrollbar->height() : 0;
851
int verticalScrollbarWidth = (m_verticalScrollbar && !m_verticalScrollbar->isOverlayScrollbar()) ? m_verticalScrollbar->width() : 0;
853
IntPoint maximumOffset(m_pdfDocumentSize.width() - m_size.width() + verticalScrollbarWidth, m_pdfDocumentSize.height() - m_size.height() + horizontalScrollbarHeight);
854
maximumOffset.clampNegativeToZero();
855
return maximumOffset;
858
int SimplePDFPlugin::visibleHeight() const
860
return m_size.height();
863
int SimplePDFPlugin::visibleWidth() const
865
return m_size.width();
868
IntSize SimplePDFPlugin::contentsSize() const
870
return m_pdfDocumentSize;
873
bool SimplePDFPlugin::scrollbarsCanBeActive() const
875
return !pluginView()->frame()->document()->inPageCache();
878
void SimplePDFPlugin::scrollbarStyleChanged(int, bool forceUpdate)
883
// 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.
884
IntPoint newScrollOffset = IntPoint(m_scrollOffset).shrunkTo(maximumScrollPosition());
885
setScrollOffset(newScrollOffset);
887
// As size of the content area changes, scrollbars may need to appear or to disappear.
890
ScrollableArea::contentsResized();
893
IntRect SimplePDFPlugin::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
895
IntRect rect = scrollbarRect;
896
rect.move(scrollbar->location() - pluginView()->location());
898
return pluginView()->frame()->view()->convertFromRenderer(pluginView()->renderer(), rect);
901
IntRect SimplePDFPlugin::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
903
IntRect rect = pluginView()->frame()->view()->convertToRenderer(pluginView()->renderer(), parentRect);
904
rect.move(pluginView()->location() - scrollbar->location());
909
IntPoint SimplePDFPlugin::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
911
IntPoint point = scrollbarPoint;
912
point.move(scrollbar->location() - pluginView()->location());
914
return pluginView()->frame()->view()->convertFromRenderer(pluginView()->renderer(), point);
917
IntPoint SimplePDFPlugin::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
919
IntPoint point = pluginView()->frame()->view()->convertToRenderer(pluginView()->renderer(), parentPoint);
920
point.move(pluginView()->location() - scrollbar->location());
925
bool SimplePDFPlugin::isEditingCommandEnabled(const String&)
930
bool SimplePDFPlugin::handleEditingCommand(const String&, const String&)
935
bool SimplePDFPlugin::handlesPageScaleFactor()
940
} // namespace WebKit