438ec8d2c366903df0ff8db76f487b65fa7d5e76
[WebKit-https.git] / Source / WebKit2 / WebProcess / Plugins / PDF / BuiltInPDFView.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "BuiltInPDFView.h"
28
29 #include "PluginView.h"
30 #include "ShareableBitmap.h"
31 #include "WebEvent.h"
32 #include "WebEventConversion.h"
33 #include <WebCore/ArchiveResource.h>
34 #include <WebCore/DocumentLoader.h>
35 #include <WebCore/FocusController.h>
36 #include <WebCore/Frame.h>
37 #include <WebCore/FrameView.h>
38 #include <WebCore/GraphicsContext.h>
39 #include <WebCore/HTTPHeaderMap.h>
40 #include <WebCore/LocalizedStrings.h>
41 #include <WebCore/Page.h>
42 #include <WebCore/PluginData.h>
43 #include <WebCore/RenderBoxModelObject.h>
44 #include <WebCore/ScrollAnimator.h>
45 #include <WebCore/ScrollbarTheme.h>
46
47 using namespace WebCore;
48 using namespace std;
49
50 namespace WebKit {
51
52 const uint64_t pdfDocumentRequestID = 1; // PluginController supports loading multiple streams, but we only need one for PDF.
53
54 const int gutterHeight = 10;
55 const int shadowOffsetX = 0;
56 const int shadowOffsetY = -2;
57 const int shadowSize = 7;
58
59 PassRefPtr<BuiltInPDFView> BuiltInPDFView::create(Page* page)
60 {
61     return adoptRef(new BuiltInPDFView(page));
62 }
63
64 BuiltInPDFView::BuiltInPDFView(Page* page)
65     : m_page(page)
66 {
67 }
68
69 BuiltInPDFView::~BuiltInPDFView()
70 {
71 }
72
73 PluginInfo BuiltInPDFView::pluginInfo()
74 {
75     PluginInfo info;
76     info.name = builtInPDFPluginName();
77
78     MimeClassInfo mimeClassInfo;
79     mimeClassInfo.type ="application/pdf";
80     mimeClassInfo.desc = pdfDocumentTypeDescription();
81     mimeClassInfo.extensions.append("pdf");
82
83     info.mimes.append(mimeClassInfo);
84     return info;
85 }
86
87 PluginView* BuiltInPDFView::pluginView()
88 {
89     return static_cast<PluginView*>(controller());
90 }
91
92 const PluginView* BuiltInPDFView::pluginView() const
93 {
94     return static_cast<const PluginView*>(controller());
95 }
96
97 void BuiltInPDFView::updateScrollbars()
98 {
99     if (m_horizontalScrollbar) {
100         if (m_pluginSize.width() >= m_pdfDocumentSize.width())
101             destroyScrollbar(HorizontalScrollbar);
102     } else if (m_pluginSize.width() < m_pdfDocumentSize.width())
103         m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
104
105     if (m_verticalScrollbar) {
106         if (m_pluginSize.height() >= m_pdfDocumentSize.height())
107             destroyScrollbar(VerticalScrollbar);
108     } else if (m_pluginSize.height() < m_pdfDocumentSize.height())
109         m_verticalScrollbar = createScrollbar(VerticalScrollbar);
110
111     int horizontalScrollbarHeight = (m_horizontalScrollbar && !m_horizontalScrollbar->isOverlayScrollbar()) ? m_horizontalScrollbar->height() : 0;
112     int verticalScrollbarWidth = (m_verticalScrollbar && !m_verticalScrollbar->isOverlayScrollbar()) ? m_verticalScrollbar->width() : 0;
113
114     int pageStep = m_pageBoxes.isEmpty() ? 0 : m_pageBoxes[0].height();
115
116     if (m_horizontalScrollbar) {
117         m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
118         m_horizontalScrollbar->setProportion(m_pluginSize.width() - verticalScrollbarWidth, m_pdfDocumentSize.width());
119         IntRect scrollbarRect(pluginView()->x(), pluginView()->y() + m_pluginSize.height() - m_horizontalScrollbar->height(), m_pluginSize.width(), m_horizontalScrollbar->height());
120         if (m_verticalScrollbar)
121             scrollbarRect.contract(m_verticalScrollbar->width(), 0);
122         m_horizontalScrollbar->setFrameRect(scrollbarRect);
123     }
124     if (m_verticalScrollbar) {
125         m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
126         m_verticalScrollbar->setProportion(m_pluginSize.height() - horizontalScrollbarHeight, m_pdfDocumentSize.height());
127         IntRect scrollbarRect(IntRect(pluginView()->x() + m_pluginSize.width() - m_verticalScrollbar->width(), pluginView()->y(), m_verticalScrollbar->width(), m_pluginSize.height()));
128         if (m_horizontalScrollbar)
129             scrollbarRect.contract(0, m_horizontalScrollbar->height());
130         m_verticalScrollbar->setFrameRect(scrollbarRect);
131     }
132 }
133
134 void BuiltInPDFView::didAddHorizontalScrollbar(Scrollbar* scrollbar)
135 {
136     pluginView()->frame()->document()->didAddWheelEventHandler();
137     ScrollableArea::didAddHorizontalScrollbar(scrollbar);
138 }
139
140 void BuiltInPDFView::willRemoveHorizontalScrollbar(Scrollbar* scrollbar)
141 {
142     ScrollableArea::willRemoveHorizontalScrollbar(scrollbar);
143     // FIXME: Maybe need a separate ScrollableArea::didRemoveHorizontalScrollbar callback?
144     if (PluginView* pluginView = this->pluginView())
145         pluginView->frame()->document()->didRemoveWheelEventHandler();
146 }
147
148 void BuiltInPDFView::didAddVerticalScrollbar(Scrollbar* scrollbar)
149 {
150     pluginView()->frame()->document()->didAddWheelEventHandler();
151     ScrollableArea::didAddVerticalScrollbar(scrollbar);
152 }
153
154 void BuiltInPDFView::willRemoveVerticalScrollbar(Scrollbar* scrollbar)
155 {
156     ScrollableArea::willRemoveVerticalScrollbar(scrollbar);
157     // FIXME: Maybe need a separate ScrollableArea::didRemoveHorizontalScrollbar callback?
158     if (PluginView* pluginView = this->pluginView())
159         pluginView->frame()->document()->didRemoveWheelEventHandler();
160 }
161
162 PassRefPtr<Scrollbar> BuiltInPDFView::createScrollbar(ScrollbarOrientation orientation)
163 {
164     RefPtr<Scrollbar> widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
165     if (orientation == HorizontalScrollbar)
166         didAddHorizontalScrollbar(widget.get());
167     else 
168         didAddVerticalScrollbar(widget.get());
169     pluginView()->frame()->view()->addChild(widget.get());
170     return widget.release();
171 }
172
173 void BuiltInPDFView::destroyScrollbar(ScrollbarOrientation orientation)
174 {
175     RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_horizontalScrollbar : m_verticalScrollbar;
176     if (!scrollbar)
177         return;
178
179     if (orientation == HorizontalScrollbar)
180         willRemoveHorizontalScrollbar(scrollbar.get());
181     else
182         willRemoveVerticalScrollbar(scrollbar.get());
183
184     scrollbar->removeFromParent();
185     scrollbar->disconnectFromScrollableArea();
186     scrollbar = 0;
187 }
188
189 void BuiltInPDFView::addArchiveResource()
190 {
191     // FIXME: It's a hack to force add a resource to DocumentLoader. PDF documents should just be fetched as CachedResources.
192
193     // Add just enough data for context menu handling and web archives to work.
194     ResourceResponse synthesizedResponse;
195     synthesizedResponse.setSuggestedFilename(m_suggestedFilename);
196     synthesizedResponse.setURL(m_sourceURL); // Needs to match the HitTestResult::absolutePDFURL.
197     synthesizedResponse.setMimeType("application/pdf");
198
199     RefPtr<ArchiveResource> resource = ArchiveResource::create(SharedBuffer::wrapCFData(m_dataBuffer.get()), m_sourceURL, "application/pdf", String(), String(), synthesizedResponse);
200     pluginView()->frame()->document()->loader()->addArchiveResource(resource.release());
201 }
202
203 void BuiltInPDFView::pdfDocumentDidLoad()
204 {
205     addArchiveResource();
206
207     RetainPtr<CGDataProviderRef> pdfDataProvider(AdoptCF, CGDataProviderCreateWithCFData(m_dataBuffer.get()));
208     m_pdfDocument.adoptCF(CGPDFDocumentCreateWithProvider(pdfDataProvider.get()));
209
210     calculateSizes();
211     updateScrollbars();
212
213     controller()->invalidate(IntRect(0, 0, m_pluginSize.width(), m_pluginSize.height()));
214 }
215
216 void BuiltInPDFView::calculateSizes()
217 {
218     size_t pageCount = CGPDFDocumentGetNumberOfPages(m_pdfDocument.get());
219     for (size_t i = 0; i < pageCount; ++i) {
220         CGPDFPageRef pdfPage = CGPDFDocumentGetPage(m_pdfDocument.get(), i + 1);
221         ASSERT(pdfPage);
222
223         CGRect box = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
224         if (CGRectIsEmpty(box))
225             box = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);
226         m_pageBoxes.append(IntRect(box));
227         m_pdfDocumentSize.setWidth(max(m_pdfDocumentSize.width(), static_cast<int>(box.size.width)));
228         m_pdfDocumentSize.expand(0, box.size.height);
229     }
230     m_pdfDocumentSize.expand(0, gutterHeight * (m_pageBoxes.size() - 1));
231 }
232
233 bool BuiltInPDFView::initialize(const Parameters& parameters)
234 {
235     m_page->addScrollableArea(this);
236
237     // Load the src URL if needed.
238     m_sourceURL = parameters.url;
239     if (!parameters.loadManually && !parameters.url.isEmpty())
240         controller()->loadURL(pdfDocumentRequestID, "GET", parameters.url.string(), String(), HTTPHeaderMap(), Vector<uint8_t>(), false);
241
242     return true;
243 }
244
245 void BuiltInPDFView::destroy()
246 {
247     if (m_page)
248         m_page->removeScrollableArea(this);
249
250     destroyScrollbar(HorizontalScrollbar);
251     destroyScrollbar(VerticalScrollbar);
252 }
253
254 void BuiltInPDFView::paint(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
255 {
256     contentAreaWillPaint();
257
258     paintBackground(graphicsContext, dirtyRect);
259
260     if (!m_pdfDocument) // FIXME: Draw loading progress.
261         return;
262
263     paintContent(graphicsContext, dirtyRect);
264     paintControls(graphicsContext, dirtyRect);
265 }
266
267 void BuiltInPDFView::paintBackground(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
268 {
269     GraphicsContextStateSaver stateSaver(*graphicsContext);
270     graphicsContext->setFillColor(Color::gray, ColorSpaceDeviceRGB);
271     graphicsContext->fillRect(dirtyRect);
272 }
273
274 void BuiltInPDFView::paintContent(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
275 {
276     GraphicsContextStateSaver stateSaver(*graphicsContext);
277     CGContextRef context = graphicsContext->platformContext();
278
279     graphicsContext->setImageInterpolationQuality(InterpolationHigh);
280     graphicsContext->setShouldAntialias(true);
281     graphicsContext->setShouldSmoothFonts(true);
282     graphicsContext->setFillColor(Color::white, ColorSpaceDeviceRGB);
283
284     graphicsContext->clip(dirtyRect);
285     IntRect contentRect(dirtyRect);
286     contentRect.moveBy(IntPoint(m_scrollOffset));
287     graphicsContext->translate(-m_scrollOffset.width(), -m_scrollOffset.height());
288
289     CGContextScaleCTM(context, 1, -1);
290
291     int pageTop = 0;
292     for (size_t i = 0; i < m_pageBoxes.size(); ++i) {
293         IntRect pageBox = m_pageBoxes[i];
294         float extraOffsetForCenteringX = max(roundf((m_pluginSize.width() - pageBox.width()) / 2.0f), 0.0f);
295         float extraOffsetForCenteringY = (m_pageBoxes.size() == 1) ? max(roundf((m_pluginSize.height() - pageBox.height() + shadowOffsetY) / 2.0f), 0.0f) : 0;
296
297         if (pageTop > contentRect.maxY())
298             break;
299         if (pageTop + pageBox.height() + extraOffsetForCenteringY + gutterHeight >= contentRect.y()) {
300             CGPDFPageRef pdfPage = CGPDFDocumentGetPage(m_pdfDocument.get(), i + 1);
301
302             graphicsContext->save();
303             graphicsContext->translate(extraOffsetForCenteringX - pageBox.x(), -extraOffsetForCenteringY - pageBox.y() - pageBox.height());
304
305             graphicsContext->setShadow(FloatSize(shadowOffsetX, shadowOffsetY), shadowSize, Color::black, ColorSpaceDeviceRGB);
306             graphicsContext->fillRect(pageBox);
307             graphicsContext->clearShadow();
308
309             graphicsContext->clip(pageBox);
310
311             CGContextDrawPDFPage(context, pdfPage);
312             graphicsContext->restore();
313         }
314         pageTop += pageBox.height() + gutterHeight;
315         CGContextTranslateCTM(context, 0, -pageBox.height() - gutterHeight);
316     }
317 }
318
319 void BuiltInPDFView::paintControls(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
320 {
321     {
322         GraphicsContextStateSaver stateSaver(*graphicsContext);
323         IntRect scrollbarDirtyRect = dirtyRect;
324         scrollbarDirtyRect.moveBy(pluginView()->frameRect().location());
325         graphicsContext->translate(-pluginView()->frameRect().x(), -pluginView()->frameRect().y());
326
327         if (m_horizontalScrollbar)
328             m_horizontalScrollbar->paint(graphicsContext, scrollbarDirtyRect);
329
330         if (m_verticalScrollbar)
331             m_verticalScrollbar->paint(graphicsContext, scrollbarDirtyRect);
332     }
333
334     IntRect dirtyCornerRect = intersection(scrollCornerRect(), dirtyRect);
335     ScrollbarTheme::theme()->paintScrollCorner(0, graphicsContext, dirtyCornerRect);
336 }
337
338 void BuiltInPDFView::updateControlTints(GraphicsContext* graphicsContext)
339 {
340     ASSERT(graphicsContext->updatingControlTints());
341
342     if (m_horizontalScrollbar)
343         m_horizontalScrollbar->invalidate();
344     if (m_verticalScrollbar)
345         m_verticalScrollbar->invalidate();
346     invalidateScrollCorner(scrollCornerRect());
347 }
348
349 PassRefPtr<ShareableBitmap> BuiltInPDFView::snapshot()
350 {
351     return 0;
352 }
353
354 #if PLATFORM(MAC)
355 PlatformLayer* BuiltInPDFView::pluginLayer()
356 {
357     return 0;
358 }
359 #endif
360
361
362 bool BuiltInPDFView::isTransparent()
363 {
364     // This should never be called from the web process.
365     ASSERT_NOT_REACHED();
366     return false;
367 }
368
369 void BuiltInPDFView::geometryDidChange(const IntSize& pluginSize, const IntRect& clipRect, const AffineTransform& pluginToRootViewTransform)
370 {
371     if (m_pluginSize == pluginSize) {
372         // Nothing to do.
373         return;
374     }
375
376     m_pluginSize = pluginSize;
377     updateScrollbars();
378 }
379
380 void BuiltInPDFView::visibilityDidChange()
381 {
382 }
383
384 void BuiltInPDFView::frameDidFinishLoading(uint64_t)
385 {
386     ASSERT_NOT_REACHED();
387 }
388
389 void BuiltInPDFView::frameDidFail(uint64_t, bool)
390 {
391     ASSERT_NOT_REACHED();
392 }
393
394 void BuiltInPDFView::didEvaluateJavaScript(uint64_t, const WTF::String&)
395 {
396     ASSERT_NOT_REACHED();
397 }
398
399 void BuiltInPDFView::streamDidReceiveResponse(uint64_t streamID, const KURL&, uint32_t, uint32_t, const String&, const String&, const String& suggestedFilename)
400 {
401     ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
402
403     m_suggestedFilename = suggestedFilename;
404 }
405                                            
406 void BuiltInPDFView::streamDidReceiveData(uint64_t streamID, const char* bytes, int length)
407 {
408     ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
409
410     if (!m_dataBuffer)
411         m_dataBuffer.adoptCF(CFDataCreateMutable(0, 0));
412
413     CFDataAppendBytes(m_dataBuffer.get(), reinterpret_cast<const UInt8*>(bytes), length);
414 }
415
416 void BuiltInPDFView::streamDidFinishLoading(uint64_t streamID)
417 {
418     ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
419
420     pdfDocumentDidLoad();
421 }
422
423 void BuiltInPDFView::streamDidFail(uint64_t streamID, bool wasCancelled)
424 {
425     ASSERT_UNUSED(streamID, streamID == pdfDocumentRequestID);
426
427     m_dataBuffer.clear();
428 }
429
430 void BuiltInPDFView::manualStreamDidReceiveResponse(const KURL& responseURL, uint32_t streamLength,  uint32_t lastModifiedTime, const String& mimeType, const String& headers, const String& suggestedFilename)
431 {
432     m_suggestedFilename = suggestedFilename;
433 }
434
435 void BuiltInPDFView::manualStreamDidReceiveData(const char* bytes, int length)
436 {
437     if (!m_dataBuffer)
438         m_dataBuffer.adoptCF(CFDataCreateMutable(0, 0));
439
440     CFDataAppendBytes(m_dataBuffer.get(), reinterpret_cast<const UInt8*>(bytes), length);
441 }
442
443 void BuiltInPDFView::manualStreamDidFinishLoading()
444 {
445     pdfDocumentDidLoad();
446 }
447
448 void BuiltInPDFView::manualStreamDidFail(bool)
449 {
450     m_dataBuffer.clear();
451 }
452
453 bool BuiltInPDFView::handleMouseEvent(const WebMouseEvent& event)
454 {
455     switch (event.type()) {
456     case WebEvent::MouseMove:
457         mouseMovedInContentArea();
458         // FIXME: Should also notify scrollbar to show hover effect. Should also send mouseExited to hide it.
459         break;
460     case WebEvent::MouseDown: {
461         // Returning false as will make EventHandler unfocus the plug-in, which is appropriate when clicking scrollbars.
462         // Ideally, we wouldn't change focus at all, but PluginView already did that for us.
463         // When support for PDF forms is added, we'll need to actually focus the plug-in when clicking in a form.
464         break;
465     }
466     case WebEvent::MouseUp: {
467         PlatformMouseEvent platformEvent = platform(event);
468         if (m_horizontalScrollbar)
469             m_horizontalScrollbar->mouseUp(platformEvent);
470         if (m_verticalScrollbar)
471             m_verticalScrollbar->mouseUp(platformEvent);
472         break;
473     }
474     default:
475         break;
476     }
477         
478     return false;
479 }
480
481 bool BuiltInPDFView::handleWheelEvent(const WebWheelEvent& event)
482 {
483     PlatformWheelEvent platformEvent = platform(event);
484     return ScrollableArea::handleWheelEvent(platformEvent);
485 }
486
487 bool BuiltInPDFView::handleMouseEnterEvent(const WebMouseEvent&)
488 {
489     mouseEnteredContentArea();
490     return false;
491 }
492
493 bool BuiltInPDFView::handleMouseLeaveEvent(const WebMouseEvent&)
494 {
495     mouseExitedContentArea();
496     return false;
497 }
498
499 bool BuiltInPDFView::handleContextMenuEvent(const WebMouseEvent&)
500 {
501     // Use default WebKit context menu.
502     return false;
503 }
504
505 bool BuiltInPDFView::handleKeyboardEvent(const WebKeyboardEvent&)
506 {
507     return false;
508 }
509
510 void BuiltInPDFView::setFocus(bool hasFocus)
511 {
512 }
513
514 NPObject* BuiltInPDFView::pluginScriptableNPObject()
515 {
516     return 0;
517 }
518
519 #if PLATFORM(MAC)
520
521 void BuiltInPDFView::windowFocusChanged(bool)
522 {
523 }
524
525 void BuiltInPDFView::windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates)
526 {
527 }
528
529 void BuiltInPDFView::windowVisibilityChanged(bool)
530 {
531 }
532
533 void BuiltInPDFView::contentsScaleFactorChanged(float)
534 {
535 }
536
537 uint64_t BuiltInPDFView::pluginComplexTextInputIdentifier() const
538 {
539     return 0;
540 }
541
542 void BuiltInPDFView::sendComplexTextInput(const String&)
543 {
544 }
545
546 #endif
547
548 void BuiltInPDFView::privateBrowsingStateChanged(bool)
549 {
550 }
551
552 bool BuiltInPDFView::getFormValue(String&)
553 {
554     return false;
555 }
556
557 bool BuiltInPDFView::handleScroll(ScrollDirection direction, ScrollGranularity granularity)
558 {
559     return scroll(direction, granularity);
560 }
561
562 Scrollbar* BuiltInPDFView::horizontalScrollbar()
563 {
564     return m_horizontalScrollbar.get();
565 }
566
567 Scrollbar* BuiltInPDFView::verticalScrollbar()
568 {
569     return m_verticalScrollbar.get();
570 }
571
572 IntRect BuiltInPDFView::scrollCornerRect() const
573 {
574     if (!m_horizontalScrollbar || !m_verticalScrollbar)
575         return IntRect();
576     if (m_horizontalScrollbar->isOverlayScrollbar()) {
577         ASSERT(m_verticalScrollbar->isOverlayScrollbar());
578         return IntRect();
579     }
580     return IntRect(pluginView()->width() - m_verticalScrollbar->width(), pluginView()->height() - m_horizontalScrollbar->height(), m_verticalScrollbar->width(), m_horizontalScrollbar->height());
581 }
582
583 ScrollableArea* BuiltInPDFView::enclosingScrollableArea() const
584 {
585     // FIXME: Walk up the frame tree and look for a scrollable parent frame or RenderLayer.
586     return 0;
587 }
588
589 void BuiltInPDFView::setScrollOffset(const IntPoint& offset)
590 {
591     m_scrollOffset = IntSize(offset.x(), offset.y());
592     // FIXME: It would be better for performance to blit parts that remain visible.
593     controller()->invalidate(IntRect(0, 0, m_pluginSize.width(), m_pluginSize.height()));
594 }
595
596 int BuiltInPDFView::scrollSize(ScrollbarOrientation orientation) const
597 {
598     Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
599     return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
600 }
601
602 bool BuiltInPDFView::isActive() const
603 {
604     return m_page->focusController()->isActive();
605 }
606
607 void BuiltInPDFView::invalidateScrollbarRect(Scrollbar* scrollbar, const LayoutRect& rect)
608 {
609     IntRect dirtyRect = rect;
610     dirtyRect.moveBy(scrollbar->location());
611     dirtyRect.moveBy(-pluginView()->location());
612     controller()->invalidate(dirtyRect);
613 }
614
615 void BuiltInPDFView::invalidateScrollCornerRect(const IntRect& rect)
616 {
617     controller()->invalidate(rect);
618 }
619
620 bool BuiltInPDFView::isScrollCornerVisible() const
621 {
622     return false;
623 }
624
625 int BuiltInPDFView::scrollPosition(Scrollbar* scrollbar) const
626 {
627     if (scrollbar->orientation() == HorizontalScrollbar)
628         return m_scrollOffset.width();
629     if (scrollbar->orientation() == VerticalScrollbar)
630         return m_scrollOffset.height();
631     ASSERT_NOT_REACHED();
632     return 0;
633 }
634
635 IntPoint BuiltInPDFView::scrollPosition() const
636 {
637     return IntPoint(m_scrollOffset.width(), m_scrollOffset.height());
638 }
639
640 IntPoint BuiltInPDFView::minimumScrollPosition() const
641 {
642     return IntPoint(0, 0);
643 }
644
645 IntPoint BuiltInPDFView::maximumScrollPosition() const
646 {
647     int horizontalScrollbarHeight = (m_horizontalScrollbar && !m_horizontalScrollbar->isOverlayScrollbar()) ? m_horizontalScrollbar->height() : 0;
648     int verticalScrollbarWidth = (m_verticalScrollbar && !m_verticalScrollbar->isOverlayScrollbar()) ? m_verticalScrollbar->width() : 0;
649
650     IntPoint maximumOffset(m_pdfDocumentSize.width() - m_pluginSize.width() + verticalScrollbarWidth, m_pdfDocumentSize.height() - m_pluginSize.height() + horizontalScrollbarHeight);
651     maximumOffset.clampNegativeToZero();
652     return maximumOffset;
653 }
654
655 int BuiltInPDFView::visibleHeight() const
656 {
657     return m_pluginSize.height();
658 }
659
660 int BuiltInPDFView::visibleWidth() const
661 {
662     return m_pluginSize.width();
663 }
664
665 IntSize BuiltInPDFView::contentsSize() const
666 {
667     return m_pdfDocumentSize;
668 }
669
670 bool BuiltInPDFView::isOnActivePage() const
671 {
672     return !pluginView()->frame()->document()->inPageCache();
673 }
674
675 void BuiltInPDFView::scrollbarStyleChanged(int, bool forceUpdate)
676 {
677     if (!forceUpdate)
678         return;
679
680     // 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.
681     IntPoint newScrollOffset = IntPoint(m_scrollOffset).shrunkTo(maximumScrollPosition());
682     setScrollOffset(newScrollOffset);
683
684     // As size of the content area changes, scrollbars may need to appear or to disappear.
685     updateScrollbars();
686
687     ScrollableArea::contentsResized();
688 }
689
690 IntPoint BuiltInPDFView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
691 {
692     IntPoint point = pluginView()->frame()->view()->convertToRenderer(pluginView()->renderer(), parentPoint);
693     point.move(pluginView()->location() - scrollbar->location());
694
695     return point;
696 }
697
698 } // namespace WebKit