diff options
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage')
24 files changed, 1552 insertions, 384 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp b/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp index 47acc7a..6272fb5 100644 --- a/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp +++ b/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.cpp @@ -42,6 +42,7 @@ #endif using namespace WebCore; +using namespace std; namespace WebKit { @@ -159,7 +160,8 @@ void DrawingAreaImpl::forceRepaint() if (m_layerTreeHost) { m_layerTreeHost->forceRepaint(); - return; + if (!m_layerTreeHost->participatesInDisplay()) + return; } m_isWaitingForDidUpdate = false; @@ -190,6 +192,13 @@ void DrawingAreaImpl::setPageOverlayNeedsDisplay(const IntRect& rect) setNeedsDisplay(rect); } +void DrawingAreaImpl::setLayerHostNeedsDisplay() +{ + ASSERT(m_layerTreeHost); + ASSERT(m_layerTreeHost->participatesInDisplay()); + scheduleDisplay(); +} + void DrawingAreaImpl::layerHostDidFlushLayers() { ASSERT(m_layerTreeHost); @@ -201,8 +210,12 @@ void DrawingAreaImpl::layerHostDidFlushLayers() return; } - if (!m_layerTreeHost) + if (!m_layerTreeHost || m_layerTreeHost->participatesInDisplay()) { + // When the layer tree host participates in display, we never tell the UI process about + // accelerated compositing. From the UI process's point of view, we're still just sending + // it a series of bitmaps in Update messages. return; + } #if USE(ACCELERATED_COMPOSITING) m_webPage->send(Messages::DrawingAreaProxy::EnterAcceleratedCompositingMode(m_backingStoreStateID, m_layerTreeHost->layerTreeContext())); @@ -301,13 +314,13 @@ void DrawingAreaImpl::sendDidUpdateBackingStoreState() UpdateInfo updateInfo; - if (!m_isPaintingSuspended && !m_layerTreeHost) + if (!m_isPaintingSuspended && (!m_layerTreeHost || m_layerTreeHost->participatesInDisplay())) display(updateInfo); #if USE(ACCELERATED_COMPOSITING) LayerTreeContext layerTreeContext; - if (m_isPaintingSuspended || m_layerTreeHost) { + if (m_isPaintingSuspended || (m_layerTreeHost && !m_layerTreeHost->participatesInDisplay())) { updateInfo.viewSize = m_webPage->size(); if (m_layerTreeHost) { @@ -318,6 +331,7 @@ void DrawingAreaImpl::sendDidUpdateBackingStoreState() // message back to the UI process, but the updated layer tree context // will be sent back in the DidUpdateBackingStoreState message. m_layerTreeHost->setShouldNotifyAfterNextScheduledLayerFlush(false); + m_layerTreeHost->forceRepaint(); } } @@ -329,7 +343,7 @@ void DrawingAreaImpl::didUpdate() { // We might get didUpdate messages from the UI process even after we've // entered accelerated compositing mode. Ignore them. - if (m_layerTreeHost) + if (m_layerTreeHost && !m_layerTreeHost->participatesInDisplay()) return; m_isWaitingForDidUpdate = false; @@ -342,14 +356,24 @@ void DrawingAreaImpl::suspendPainting() { ASSERT(!m_isPaintingSuspended); + if (m_layerTreeHost) + m_layerTreeHost->pauseRendering(); + m_isPaintingSuspended = true; m_displayTimer.stop(); } void DrawingAreaImpl::resumePainting() { - ASSERT(m_isPaintingSuspended); - + if (!m_isPaintingSuspended) { + // FIXME: We can get a call to resumePainting when painting is not suspended. + // This happens when sending a synchronous message to create a new page. See <rdar://problem/8976531>. + return; + } + + if (m_layerTreeHost) + m_layerTreeHost->resumeRendering(); + m_isPaintingSuspended = false; // FIXME: We shouldn't always repaint everything here. @@ -372,8 +396,11 @@ void DrawingAreaImpl::enterAcceleratedCompositingMode(GraphicsLayer* graphicsLay m_dirtyRegion = Region(); m_scrollRect = IntRect(); m_scrollOffset = IntSize(); - m_displayTimer.stop(); - m_isWaitingForDidUpdate = false; + + if (!m_layerTreeHost->participatesInDisplay()) { + m_displayTimer.stop(); + m_isWaitingForDidUpdate = false; + } } void DrawingAreaImpl::exitAcceleratedCompositingMode() @@ -385,6 +412,8 @@ void DrawingAreaImpl::exitAcceleratedCompositingMode() ASSERT(m_layerTreeHost); + bool wasParticipatingInDisplay = m_layerTreeHost->participatesInDisplay(); + m_layerTreeHost->invalidate(); m_layerTreeHost = nullptr; m_dirtyRegion = m_webPage->bounds(); @@ -404,9 +433,16 @@ void DrawingAreaImpl::exitAcceleratedCompositingMode() display(updateInfo); #if USE(ACCELERATED_COMPOSITING) - // Send along a complete update of the page so we can paint the contents right after we exit the - // accelerated compositing mode, eliminiating flicker. - m_webPage->send(Messages::DrawingAreaProxy::ExitAcceleratedCompositingMode(m_backingStoreStateID, updateInfo)); + if (wasParticipatingInDisplay) { + // When the layer tree host participates in display, we never tell the UI process about + // accelerated compositing. From the UI process's point of view, we're still just sending + // it a series of bitmaps in Update messages. + m_webPage->send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo)); + } else { + // Send along a complete update of the page so we can paint the contents right after we exit the + // accelerated compositing mode, eliminiating flicker. + m_webPage->send(Messages::DrawingAreaProxy::ExitAcceleratedCompositingMode(m_backingStoreStateID, updateInfo)); + } #endif } @@ -420,14 +456,19 @@ void DrawingAreaImpl::exitAcceleratedCompositingModeSoon() void DrawingAreaImpl::scheduleDisplay() { + ASSERT(!m_layerTreeHost || m_layerTreeHost->participatesInDisplay()); + if (m_isWaitingForDidUpdate) return; if (m_isPaintingSuspended) return; - if (m_dirtyRegion.isEmpty()) - return; + if (m_layerTreeHost) { + if (!m_layerTreeHost->needsDisplay()) + return; + } else if (m_dirtyRegion.isEmpty()) + return; if (m_displayTimer.isActive()) return; @@ -440,7 +481,8 @@ void DrawingAreaImpl::displayTimerFired() static const double minimumFrameInterval = 1.0 / 60.0; double timeSinceLastDisplay = currentTime() - m_lastDisplayTime; - double timeUntilNextDisplay = minimumFrameInterval - timeSinceLastDisplay; + double timeUntilLayerTreeHostNeedsDisplay = m_layerTreeHost && m_layerTreeHost->participatesInDisplay() ? m_layerTreeHost->timeUntilNextDisplay() : 0; + double timeUntilNextDisplay = max(minimumFrameInterval - timeSinceLastDisplay, timeUntilLayerTreeHostNeedsDisplay); if (timeUntilNextDisplay > 0) { m_displayTimer.startOneShot(timeUntilNextDisplay); @@ -452,14 +494,17 @@ void DrawingAreaImpl::displayTimerFired() void DrawingAreaImpl::display() { - ASSERT(!m_layerTreeHost); + ASSERT(!m_layerTreeHost || m_layerTreeHost->participatesInDisplay()); ASSERT(!m_isWaitingForDidUpdate); ASSERT(!m_inUpdateBackingStoreState); if (m_isPaintingSuspended) return; - if (m_dirtyRegion.isEmpty()) + if (m_layerTreeHost) { + if (!m_layerTreeHost->needsDisplay()) + return; + } else if (m_dirtyRegion.isEmpty()) return; if (m_shouldSendDidUpdateBackingStoreState) { @@ -470,7 +515,7 @@ void DrawingAreaImpl::display() UpdateInfo updateInfo; display(updateInfo); - if (m_layerTreeHost) { + if (m_layerTreeHost && !m_layerTreeHost->participatesInDisplay()) { // The call to update caused layout which turned on accelerated compositing. // Don't send an Update message in this case. return; @@ -504,7 +549,7 @@ static bool shouldPaintBoundsRect(const IntRect& bounds, const Vector<IntRect>& void DrawingAreaImpl::display(UpdateInfo& updateInfo) { ASSERT(!m_isPaintingSuspended); - ASSERT(!m_layerTreeHost); + ASSERT(!m_layerTreeHost || m_layerTreeHost->participatesInDisplay()); ASSERT(!m_webPage->size().isEmpty()); // FIXME: It would be better if we could avoid painting altogether when there is a custom representation. @@ -516,44 +561,49 @@ void DrawingAreaImpl::display(UpdateInfo& updateInfo) m_webPage->layoutIfNeeded(); - // The layout may have put the page into accelerated compositing mode, in which case the - // LayerTreeHost is now in charge of displaying. - if (m_layerTreeHost) + // The layout may have put the page into accelerated compositing mode. If the LayerTreeHost is + // in charge of displaying, we have nothing more to do. + if (m_layerTreeHost && !m_layerTreeHost->participatesInDisplay()) return; - IntRect bounds = m_dirtyRegion.bounds(); - ASSERT(m_webPage->bounds().contains(bounds)); + updateInfo.viewSize = m_webPage->size(); + + if (m_layerTreeHost) + m_layerTreeHost->display(updateInfo); + else { + IntRect bounds = m_dirtyRegion.bounds(); + ASSERT(m_webPage->bounds().contains(bounds)); - RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(bounds.size(), ShareableBitmap::SupportsAlpha); - if (!bitmap->createHandle(updateInfo.bitmapHandle)) - return; + RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(bounds.size(), ShareableBitmap::SupportsAlpha); + if (!bitmap->createHandle(updateInfo.bitmapHandle)) + return; - Vector<IntRect> rects = m_dirtyRegion.rects(); + Vector<IntRect> rects = m_dirtyRegion.rects(); - if (shouldPaintBoundsRect(bounds, rects)) { - rects.clear(); - rects.append(bounds); - } + if (shouldPaintBoundsRect(bounds, rects)) { + rects.clear(); + rects.append(bounds); + } - updateInfo.scrollRect = m_scrollRect; - updateInfo.scrollOffset = m_scrollOffset; + updateInfo.scrollRect = m_scrollRect; + updateInfo.scrollOffset = m_scrollOffset; - m_dirtyRegion = Region(); - m_scrollRect = IntRect(); - m_scrollOffset = IntSize(); + m_dirtyRegion = Region(); + m_scrollRect = IntRect(); + m_scrollOffset = IntSize(); - OwnPtr<GraphicsContext> graphicsContext = bitmap->createGraphicsContext(); - - updateInfo.viewSize = m_webPage->size(); - updateInfo.updateRectBounds = bounds; + OwnPtr<GraphicsContext> graphicsContext = bitmap->createGraphicsContext(); + + updateInfo.updateRectBounds = bounds; - graphicsContext->translate(-bounds.x(), -bounds.y()); + graphicsContext->translate(-bounds.x(), -bounds.y()); - for (size_t i = 0; i < rects.size(); ++i) { - m_webPage->drawRect(*graphicsContext, rects[i]); - if (m_webPage->hasPageOverlay()) - m_webPage->drawPageOverlay(*graphicsContext, rects[i]); - updateInfo.updateRects.append(rects[i]); + for (size_t i = 0; i < rects.size(); ++i) { + m_webPage->drawRect(*graphicsContext, rects[i]); + if (m_webPage->hasPageOverlay()) + m_webPage->drawPageOverlay(*graphicsContext, rects[i]); + updateInfo.updateRects.append(rects[i]); + } } // Layout can trigger more calls to setNeedsDisplay and we don't want to process them diff --git a/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.h b/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.h index 9e93869..471ba56 100644 --- a/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.h +++ b/Source/WebKit2/WebProcess/WebPage/DrawingAreaImpl.h @@ -40,6 +40,7 @@ public: static PassOwnPtr<DrawingAreaImpl> create(WebPage*, const WebPageCreationParameters&); virtual ~DrawingAreaImpl(); + void setLayerHostNeedsDisplay(); void layerHostDidFlushLayers(); private: diff --git a/Source/WebKit2/WebProcess/WebPage/FindController.cpp b/Source/WebKit2/WebProcess/WebPage/FindController.cpp index 3e7b268..49f5786 100644 --- a/Source/WebKit2/WebProcess/WebPage/FindController.cpp +++ b/Source/WebKit2/WebProcess/WebPage/FindController.cpp @@ -38,6 +38,7 @@ #include <WebCore/GraphicsContext.h> #include <WebCore/Page.h> +using namespace std; using namespace WebCore; namespace WebKit { @@ -64,9 +65,16 @@ FindController::~FindController() void FindController::countStringMatches(const String& string, FindOptions options, unsigned maxMatchCount) { - unsigned matchCount = m_webPage->corePage()->markAllMatchesForText(string, core(options), false, maxMatchCount); + if (maxMatchCount == numeric_limits<unsigned>::max()) + --maxMatchCount; + + unsigned matchCount = m_webPage->corePage()->markAllMatchesForText(string, core(options), false, maxMatchCount + 1); m_webPage->corePage()->unmarkAllTextMatches(); + // Check if we have more matches than allowed. + if (matchCount > maxMatchCount) + matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount); + m_webPage->send(Messages::WebPageProxy::DidCountStringMatches(string, matchCount)); } @@ -102,6 +110,9 @@ void FindController::findString(const String& string, FindOptions options, unsig shouldShowOverlay = options & FindOptionsShowOverlay; if (shouldShowOverlay) { + if (maxMatchCount == numeric_limits<unsigned>::max()) + --maxMatchCount; + unsigned matchCount = m_webPage->corePage()->markAllMatchesForText(string, core(options), false, maxMatchCount + 1); // Check if we have more matches than allowed. @@ -122,7 +133,7 @@ void FindController::findString(const String& string, FindOptions options, unsig if (!shouldShowOverlay) { if (m_findPageOverlay) { // Get rid of the overlay. - m_webPage->uninstallPageOverlay(m_findPageOverlay); + m_webPage->uninstallPageOverlay(m_findPageOverlay, false); } ASSERT(!m_findPageOverlay); @@ -142,7 +153,7 @@ void FindController::findString(const String& string, FindOptions options, unsig void FindController::hideFindUI() { if (m_findPageOverlay) - m_webPage->uninstallPageOverlay(m_findPageOverlay); + m_webPage->uninstallPageOverlay(m_findPageOverlay, true); hideFindIndicator(); } @@ -259,27 +270,39 @@ static const float shadowOffsetY = 1.0; static const float shadowBlurRadius = 2.0; static const float whiteFrameThickness = 1.0; -static const int overlayBackgroundRed = 25; -static const int overlayBackgroundGreen = 25; -static const int overlayBackgroundBlue = 25; -static const int overlayBackgroundAlpha = 63; +static const float overlayBackgroundRed = 0.1; +static const float overlayBackgroundGreen = 0.1; +static const float overlayBackgroundBlue = 0.1; +static const float overlayBackgroundAlpha = 0.25; + +static Color overlayBackgroundColor(float fractionFadedIn) +{ + return Color(overlayBackgroundRed, overlayBackgroundGreen, overlayBackgroundBlue, overlayBackgroundAlpha * fractionFadedIn); +} -static Color overlayBackgroundColor() +static Color holeShadowColor(float fractionFadedIn) { - return Color(overlayBackgroundRed, overlayBackgroundGreen, overlayBackgroundBlue, overlayBackgroundAlpha); + return Color(0.0f, 0.0f, 0.0f, fractionFadedIn); } -void FindController::drawRect(PageOverlay*, GraphicsContext& graphicsContext, const IntRect& dirtyRect) +static Color holeFillColor(float fractionFadedIn) { + return Color(1.0f, 1.0f, 1.0f, fractionFadedIn); +} + +void FindController::drawRect(PageOverlay* pageOverlay, GraphicsContext& graphicsContext, const IntRect& dirtyRect) +{ + float fractionFadedIn = pageOverlay->fractionFadedIn(); + Vector<IntRect> rects = rectsForTextMatches(); // Draw the background. - graphicsContext.fillRect(dirtyRect, overlayBackgroundColor(), ColorSpaceSRGB); + graphicsContext.fillRect(dirtyRect, overlayBackgroundColor(fractionFadedIn), ColorSpaceSRGB); graphicsContext.save(); - graphicsContext.setShadow(FloatSize(shadowOffsetX, shadowOffsetY), shadowBlurRadius, Color::black, ColorSpaceSRGB); + graphicsContext.setShadow(FloatSize(shadowOffsetX, shadowOffsetY), shadowBlurRadius, holeShadowColor(fractionFadedIn), ColorSpaceSRGB); - graphicsContext.setFillColor(Color::white, ColorSpaceSRGB); + graphicsContext.setFillColor(holeFillColor(fractionFadedIn), ColorSpaceSRGB); // Draw white frames around the holes. for (size_t i = 0; i < rects.size(); ++i) { diff --git a/Source/WebKit2/WebProcess/WebPage/LayerTreeHost.cpp b/Source/WebKit2/WebProcess/WebPage/LayerTreeHost.cpp index 737e195..24cbcc6 100644 --- a/Source/WebKit2/WebProcess/WebPage/LayerTreeHost.cpp +++ b/Source/WebKit2/WebProcess/WebPage/LayerTreeHost.cpp @@ -26,8 +26,12 @@ #include "config.h" #include "LayerTreeHost.h" +#if USE(CA) #if PLATFORM(MAC) -#include "LayerTreeHostCA.h" +#include "LayerTreeHostCAMac.h" +#elif PLATFORM(WIN) +#include "LayerTreeHostCAWin.h" +#endif #endif #if !PLATFORM(MAC) && !PLATFORM(WIN) @@ -41,10 +45,12 @@ namespace WebKit { PassRefPtr<LayerTreeHost> LayerTreeHost::create(WebPage* webPage) { #if PLATFORM(MAC) - return LayerTreeHostCA::create(webPage); -#endif - + return LayerTreeHostCAMac::create(webPage); +#elif PLATFORM(WIN) && HAVE(WKQCA) + return LayerTreeHostCAWin::create(webPage); +#else return 0; +#endif } LayerTreeHost::LayerTreeHost(WebPage* webPage) diff --git a/Source/WebKit2/WebProcess/WebPage/LayerTreeHost.h b/Source/WebKit2/WebProcess/WebPage/LayerTreeHost.h index bbb94e8..004bdb7 100644 --- a/Source/WebKit2/WebProcess/WebPage/LayerTreeHost.h +++ b/Source/WebKit2/WebProcess/WebPage/LayerTreeHost.h @@ -38,6 +38,7 @@ namespace WebCore { namespace WebKit { class LayerTreeContext; +class UpdateInfo; class WebPage; class LayerTreeHost : public RefCounted<LayerTreeHost> { @@ -45,6 +46,8 @@ public: static PassRefPtr<LayerTreeHost> create(WebPage*); virtual ~LayerTreeHost(); + static bool supportsAcceleratedCompositing(); + virtual const LayerTreeContext& layerTreeContext() = 0; virtual void scheduleLayerFlush() = 0; virtual void setShouldNotifyAfterNextScheduledLayerFlush(bool) = 0; @@ -60,12 +63,29 @@ public: virtual void didUninstallPageOverlay() = 0; virtual void setPageOverlayNeedsDisplay(const WebCore::IntRect&) = 0; + virtual void pauseRendering() { } + virtual void resumeRendering() { } + + // If a derived class overrides this function to return true, the derived class must also + // override the functions beneath it. + virtual bool participatesInDisplay() { return false; } + virtual bool needsDisplay() { ASSERT_NOT_REACHED(); return false; } + virtual double timeUntilNextDisplay() { ASSERT_NOT_REACHED(); return 0; } + virtual void display(UpdateInfo&) { ASSERT_NOT_REACHED(); } + protected: explicit LayerTreeHost(WebPage*); WebPage* m_webPage; }; +#if !PLATFORM(WIN) +inline bool LayerTreeHost::supportsAcceleratedCompositing() +{ + return true; +} +#endif + } // namespace WebKit #endif // LayerTreeHost_h diff --git a/Source/WebKit2/WebProcess/WebPage/PageOverlay.cpp b/Source/WebKit2/WebProcess/WebPage/PageOverlay.cpp index 67c1165..d4b1b41 100644 --- a/Source/WebKit2/WebProcess/WebPage/PageOverlay.cpp +++ b/Source/WebKit2/WebProcess/WebPage/PageOverlay.cpp @@ -27,6 +27,7 @@ #include "PageOverlay.h" #include "WebPage.h" +#include "WebProcess.h" #include <WebCore/Frame.h> #include <WebCore/FrameView.h> #include <WebCore/GraphicsContext.h> @@ -37,6 +38,9 @@ using namespace WebCore; namespace WebKit { +static const double fadeAnimationDuration = 0.2; +static const double fadeAnimationFrameRate = 30; + PassRefPtr<PageOverlay> PageOverlay::create(Client* client) { return adoptRef(new PageOverlay(client)); @@ -45,6 +49,11 @@ PassRefPtr<PageOverlay> PageOverlay::create(Client* client) PageOverlay::PageOverlay(Client* client) : m_client(client) , m_webPage(0) + , m_fadeAnimationTimer(WebProcess::shared().runLoop(), this, &PageOverlay::fadeAnimationTimerFired) + , m_fadeAnimationStartTime(0.0) + , m_fadeAnimationDuration(fadeAnimationDuration) + , m_fadeAnimationType(NoAnimation) + , m_fractionFadedIn(1.0) { } @@ -54,7 +63,7 @@ PageOverlay::~PageOverlay() IntRect PageOverlay::bounds() const { - FrameView* frameView = webPage()->corePage()->mainFrame()->view(); + FrameView* frameView = m_webPage->corePage()->mainFrame()->view(); int width = frameView->width(); int height = frameView->height(); @@ -73,6 +82,8 @@ void PageOverlay::setPage(WebPage* webPage) m_client->willMoveToWebPage(this, webPage); m_webPage = webPage; m_client->didMoveToWebPage(this, webPage); + + m_fadeAnimationTimer.stop(); } void PageOverlay::setNeedsDisplay(const IntRect& dirtyRect) @@ -112,4 +123,54 @@ bool PageOverlay::mouseEvent(const WebMouseEvent& mouseEvent) return m_client->mouseEvent(this, mouseEvent); } +void PageOverlay::startFadeInAnimation() +{ + m_fractionFadedIn = 0.0; + m_fadeAnimationType = FadeInAnimation; + + startFadeAnimation(); +} + +void PageOverlay::startFadeOutAnimation() +{ + m_fractionFadedIn = 1.0; + m_fadeAnimationType = FadeOutAnimation; + + startFadeAnimation(); +} + +void PageOverlay::startFadeAnimation() +{ + m_fadeAnimationStartTime = currentTime(); + + // Start the timer + m_fadeAnimationTimer.startRepeating(1 / fadeAnimationFrameRate); +} + +void PageOverlay::fadeAnimationTimerFired() +{ + float animationProgress = (currentTime() - m_fadeAnimationStartTime) / m_fadeAnimationDuration; + + if (animationProgress >= 1.0) + animationProgress = 1.0; + + double sine = sin(piOverTwoFloat * animationProgress); + float fadeAnimationValue = sine * sine; + + m_fractionFadedIn = (m_fadeAnimationType == FadeInAnimation) ? fadeAnimationValue : 1 - fadeAnimationValue; + setNeedsDisplay(); + + if (animationProgress == 1.0) { + m_fadeAnimationTimer.stop(); + + bool wasFadingOut = m_fadeAnimationType == FadeOutAnimation; + m_fadeAnimationType = NoAnimation; + + if (wasFadingOut) { + // If this was a fade out, go ahead and uninstall the page overlay. + m_webPage->uninstallPageOverlay(this, false); + } + } +} + } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/PageOverlay.h b/Source/WebKit2/WebProcess/WebPage/PageOverlay.h index 6f1f70f..1f61ceb 100644 --- a/Source/WebKit2/WebProcess/WebPage/PageOverlay.h +++ b/Source/WebKit2/WebProcess/WebPage/PageOverlay.h @@ -27,6 +27,7 @@ #define PageOverlay_h #include "APIObject.h" +#include "RunLoop.h" #include <wtf/PassRefPtr.h> namespace WebCore { @@ -65,20 +66,38 @@ public: void drawRect(WebCore::GraphicsContext&, const WebCore::IntRect& dirtyRect); bool mouseEvent(const WebMouseEvent&); + void startFadeInAnimation(); + void startFadeOutAnimation(); + + float fractionFadedIn() const { return m_fractionFadedIn; } + protected: explicit PageOverlay(Client*); - WebPage* webPage() const { return m_webPage; } - private: // APIObject virtual Type type() const { return APIType; } WebCore::IntRect bounds() const; - Client* m_client; + void startFadeAnimation(); + void fadeAnimationTimerFired(); + Client* m_client; WebPage* m_webPage; + + RunLoop::Timer<PageOverlay> m_fadeAnimationTimer; + double m_fadeAnimationStartTime; + double m_fadeAnimationDuration; + + enum FadeAnimationType { + NoAnimation, + FadeInAnimation, + FadeOutAnimation, + }; + + FadeAnimationType m_fadeAnimationType; + float m_fractionFadedIn; }; } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/WebContextMenu.cpp b/Source/WebKit2/WebProcess/WebPage/WebContextMenu.cpp index 35058de..cbed180 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebContextMenu.cpp +++ b/Source/WebKit2/WebProcess/WebPage/WebContextMenu.cpp @@ -82,7 +82,8 @@ void WebContextMenu::show() contextMenuState.absoluteImageURLString = controller->hitTestResult().absoluteImageURL().string(); contextMenuState.absoluteLinkURLString = controller->hitTestResult().absoluteLinkURL().string(); - // Notify the UIProcess. + // Mark the WebPage has having a shown context menu then notify the UIProcess. + m_page->contextMenuShowing(); m_page->send(Messages::WebPageProxy::ShowContextMenu(view->contentsToWindow(controller->hitTestResult().point()), contextMenuState, proposedMenu, InjectedBundleUserMessageEncoder(userData.get()))); } diff --git a/Source/WebKit2/WebProcess/WebPage/WebFrame.cpp b/Source/WebKit2/WebProcess/WebPage/WebFrame.cpp index 574634f..0d550c9 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebFrame.cpp +++ b/Source/WebKit2/WebProcess/WebPage/WebFrame.cpp @@ -512,6 +512,30 @@ IntSize WebFrame::scrollOffset() const return view->scrollOffset(); } +bool WebFrame::hasHorizontalScrollbar() const +{ + if (!m_coreFrame) + return false; + + FrameView* view = m_coreFrame->view(); + if (!view) + return false; + + return view->horizontalScrollbar(); +} + +bool WebFrame::hasVerticalScrollbar() const +{ + if (!m_coreFrame) + return false; + + FrameView* view = m_coreFrame->view(); + if (!view) + return false; + + return view->verticalScrollbar(); +} + bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha) { if (!m_coreFrame) @@ -550,6 +574,9 @@ WebFrame* WebFrame::frameForContext(JSContextRef context) JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world) { + if (!m_coreFrame) + return 0; + JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld()); ExecState* exec = globalObject->globalExec(); @@ -559,6 +586,9 @@ JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, Inj JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world) { + if (!m_coreFrame) + return 0; + JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld()); ExecState* exec = globalObject->globalExec(); diff --git a/Source/WebKit2/WebProcess/WebPage/WebFrame.h b/Source/WebKit2/WebProcess/WebPage/WebFrame.h index 3c63cf3..b6e1e13 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebFrame.h +++ b/Source/WebKit2/WebProcess/WebPage/WebFrame.h @@ -93,6 +93,8 @@ public: WebCore::IntRect visibleContentBounds() const; WebCore::IntRect visibleContentBoundsExcludingScrollbars() const; WebCore::IntSize scrollOffset() const; + bool hasHorizontalScrollbar() const; + bool hasVerticalScrollbar() const; bool getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha); static WebFrame* frameForContext(JSContextRef); diff --git a/Source/WebKit2/WebProcess/WebPage/WebPage.cpp b/Source/WebKit2/WebProcess/WebPage/WebPage.cpp index d5f3724..7707965 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit2/WebProcess/WebPage/WebPage.cpp @@ -32,6 +32,7 @@ #include "DrawingArea.h" #include "InjectedBundle.h" #include "InjectedBundleBackForwardList.h" +#include "LayerTreeHost.h" #include "MessageID.h" #include "NetscapePlugin.h" #include "PageOverlay.h" @@ -66,8 +67,8 @@ #include "WebPopupMenu.h" #include "WebPreferencesStore.h" #include "WebProcess.h" -#include "WebProcessProxyMessageKinds.h" #include "WebProcessProxyMessages.h" +#include <JavaScriptCore/APICast.h> #include <WebCore/AbstractDatabase.h> #include <WebCore/ArchiveResource.h> #include <WebCore/Chrome.h> @@ -77,18 +78,23 @@ #include <WebCore/DocumentMarkerController.h> #include <WebCore/DragController.h> #include <WebCore/DragData.h> +#include <WebCore/EditingBehavior.h> #include <WebCore/EventHandler.h> #include <WebCore/FocusController.h> +#include <WebCore/FormState.h> #include <WebCore/Frame.h> +#include <WebCore/FrameLoadRequest.h> #include <WebCore/FrameLoaderTypes.h> #include <WebCore/FrameView.h> +#include <WebCore/HTMLFormElement.h> #include <WebCore/HistoryItem.h> #include <WebCore/KeyboardEvent.h> +#include <WebCore/MouseEvent.h> #include <WebCore/Page.h> #include <WebCore/PlatformKeyboardEvent.h> #include <WebCore/PrintContext.h> -#include <WebCore/RenderTreeAsText.h> #include <WebCore/RenderLayer.h> +#include <WebCore/RenderTreeAsText.h> #include <WebCore/RenderView.h> #include <WebCore/ReplaceSelectionCommand.h> #include <WebCore/ResourceRequest.h> @@ -110,9 +116,10 @@ #endif #if ENABLE(PLUGIN_PROCESS) -// FIXME: This is currently Mac-specific! +#if PLATFORM(MAC) #include "MachPort.h" #endif +#endif #if PLATFORM(QT) #include "HitTestResult.h" @@ -151,6 +158,7 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters) #if PLATFORM(MAC) , m_windowIsVisible(false) , m_isSmartInsertDeleteEnabled(parameters.isSmartInsertDeleteEnabled) + , m_keyboardEventBeingInterpreted(0) #elif PLATFORM(WIN) , m_nativeWindow(parameters.nativeWindow) #endif @@ -163,6 +171,10 @@ WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters) , m_userSpaceScaleFactor(parameters.userSpaceScaleFactor) , m_cachedMainFrameIsPinnedToLeftSide(false) , m_cachedMainFrameIsPinnedToRightSide(false) + , m_isShowingContextMenu(false) +#if PLATFORM(WIN) + , m_gestureReachedScrollingLimit(false) +#endif { ASSERT(m_pageID); @@ -282,6 +294,13 @@ void WebPage::initializeInjectedBundleUIClient(WKBundlePageUIClient* client) m_uiClient.initialize(client); } +#if ENABLE(FULLSCREEN_API) +void WebPage::initializeInjectedBundleFullScreenClient(WKBundlePageFullScreenClient* client) +{ + m_fullScreenClient.initialize(client); +} +#endif + PassRefPtr<Plugin> WebPage::createPlugin(const Plugin::Parameters& parameters) { String pluginPath; @@ -302,6 +321,22 @@ PassRefPtr<Plugin> WebPage::createPlugin(const Plugin::Parameters& parameters) #endif } +EditorState WebPage::editorState() const +{ + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + ASSERT(frame); + + EditorState result; + result.selectionIsNone = frame->selection()->isNone(); + result.selectionIsRange = frame->selection()->isRange(); + result.isContentEditable = frame->selection()->isContentEditable(); + result.isContentRichlyEditable = frame->selection()->isContentRichlyEditable(); + result.isInPasswordField = frame->selection()->isInPasswordField(); + result.hasComposition = frame->editor()->hasComposition(); + + return result; +} + String WebPage::renderTreeExternalRepresentation() const { return externalRepresentation(m_mainFrame->coreFrame(), RenderAsTextBehaviorNormal); @@ -440,6 +475,20 @@ void WebPage::loadPlainTextString(const String& string) loadData(sharedBuffer, "text/plain", "utf-16", blankURL(), KURL()); } +void WebPage::linkClicked(const String& url, const WebMouseEvent& event) +{ + Frame* frame = m_page->mainFrame(); + if (!frame) + return; + + RefPtr<Event> coreEvent; + if (event.type() != WebEvent::NoType) + coreEvent = MouseEvent::create(eventNames().clickEvent, frame->document()->defaultView(), platform(event), 0, 0); + + frame->loader()->loadFrameRequest(FrameLoadRequest(frame->document()->securityOrigin(), ResourceRequest(url)), + false, false, coreEvent.get(), 0, SendReferrer); +} + void WebPage::stopLoadingFrame(uint64_t frameID) { WebFrame* frame = WebProcess::shared().webFrame(frameID); @@ -697,22 +746,38 @@ void WebPage::setFixedLayoutSize(const IntSize& size) void WebPage::installPageOverlay(PassRefPtr<PageOverlay> pageOverlay) { - if (m_pageOverlay) - pageOverlay->setPage(0); + bool shouldFadeIn = true; + + if (m_pageOverlay) { + m_pageOverlay->setPage(0); + + if (pageOverlay) { + // We're installing a page overlay when a page overlay is already active. + // In this case we don't want to fade in the new overlay. + shouldFadeIn = false; + } + } m_pageOverlay = pageOverlay; m_pageOverlay->setPage(this); - m_drawingArea->didInstallPageOverlay(); + if (shouldFadeIn) + m_pageOverlay->startFadeInAnimation(); + m_drawingArea->didInstallPageOverlay(); m_pageOverlay->setNeedsDisplay(); } -void WebPage::uninstallPageOverlay(PageOverlay* pageOverlay) +void WebPage::uninstallPageOverlay(PageOverlay* pageOverlay, bool fadeOut) { if (pageOverlay != m_pageOverlay) return; + if (fadeOut) { + m_pageOverlay->startFadeOutAnimation(); + return; + } + m_pageOverlay->setPage(0); m_pageOverlay = nullptr; @@ -804,35 +869,6 @@ WebContextMenu* WebPage::contextMenu() return m_contextMenu.get(); } -void WebPage::getLocationAndLengthFromRange(Range* range, uint64_t& location, uint64_t& length) -{ - location = notFound; - length = 0; - - if (!range || !range->startContainer()) - return; - - Element* selectionRoot = range->ownerDocument()->frame()->selection()->rootEditableElement(); - Element* scope = selectionRoot ? selectionRoot : range->ownerDocument()->documentElement(); - - // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view - // that is not inside the current editable region. These checks ensure we don't produce - // potentially invalid data when responding to such requests. - if (range->startContainer() != scope && !range->startContainer()->isDescendantOf(scope)) - return; - if (range->endContainer() != scope && !range->endContainer()->isDescendantOf(scope)) - return; - - RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset()); - ASSERT(testRange->startContainer() == scope); - location = TextIterator::rangeLength(testRange.get()); - - ExceptionCode ec; - testRange->setEnd(range->endContainer(), range->endOffset(), ec); - ASSERT(testRange->startContainer() == scope); - length = TextIterator::rangeLength(testRange.get()) - location; -} - // Events static const WebEvent* g_currentEvent = 0; @@ -913,6 +949,12 @@ static bool handleMouseEvent(const WebMouseEvent& mouseEvent, Page* page) void WebPage::mouseEvent(const WebMouseEvent& mouseEvent) { + // Don't try to handle any pending mouse events if a context menu is showing. + if (m_isShowingContextMenu) { + send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(mouseEvent.type()), false)); + return; + } + bool handled = false; if (m_pageOverlay) { @@ -962,6 +1004,7 @@ void WebPage::keyEvent(const WebKeyboardEvent& keyboardEvent) CurrentEvent currentEvent(keyboardEvent); bool handled = handleKeyEvent(keyboardEvent, m_page.get()); + // FIXME: Platform default behaviors should be performed during normal DOM event dispatch (in most cases, in default keydown event handler). if (!handled) handled = performDefaultBehaviorForKeyEvent(keyboardEvent); @@ -1142,8 +1185,9 @@ void WebPage::viewWillEndLiveResize() void WebPage::setFocused(bool isFocused) { - if (!isFocused) + if (!isFocused && m_page->focusController()->focusedOrMainFrame()->editor()->behavior().shouldClearSelectionWhenLosingWebPageFocus()) m_page->focusController()->focusedOrMainFrame()->selection()->clear(); + m_page->focusController()->setFocused(isFocused); } @@ -1240,7 +1284,8 @@ void WebPage::runJavaScriptInMainFrame(const String& script, uint64_t callbackID JSLock lock(SilenceAssertionsOnly); if (JSValue resultValue = m_mainFrame->coreFrame()->script()->executeScript(script, true).jsValue()) { - if ((serializedResultValue = SerializedScriptValue::create(m_mainFrame->coreFrame()->script()->globalObject(mainThreadNormalWorld())->globalExec(), resultValue))) + if ((serializedResultValue = SerializedScriptValue::create(m_mainFrame->jsContext(), + toRef(m_mainFrame->coreFrame()->script()->globalObject(mainThreadNormalWorld())->globalExec(), resultValue), 0))) dataReference = CoreIPC::DataReference(serializedResultValue->data().data(), serializedResultValue->data().size()); } @@ -1360,6 +1405,7 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) settings->setJavaScriptEnabled(store.getBoolValueForKey(WebPreferencesKey::javaScriptEnabledKey())); settings->setLoadsImagesAutomatically(store.getBoolValueForKey(WebPreferencesKey::loadsImagesAutomaticallyKey())); + settings->setLoadsSiteIconsIgnoringImageLoadingSetting(store.getBoolValueForKey(WebPreferencesKey::loadsSiteIconsIgnoringImageLoadingPreferenceKey())); settings->setPluginsEnabled(store.getBoolValueForKey(WebPreferencesKey::pluginsEnabledKey())); settings->setJavaEnabled(store.getBoolValueForKey(WebPreferencesKey::javaEnabledKey())); settings->setOfflineWebApplicationCacheEnabled(store.getBoolValueForKey(WebPreferencesKey::offlineWebApplicationCacheEnabledKey())); @@ -1391,17 +1437,11 @@ void WebPage::updatePreferences(const WebPreferencesStore& store) settings->setMinimumLogicalFontSize(store.getUInt32ValueForKey(WebPreferencesKey::minimumLogicalFontSizeKey())); settings->setDefaultFontSize(store.getUInt32ValueForKey(WebPreferencesKey::defaultFontSizeKey())); settings->setDefaultFixedFontSize(store.getUInt32ValueForKey(WebPreferencesKey::defaultFixedFontSizeKey())); + settings->setEditableLinkBehavior(static_cast<WebCore::EditableLinkBehavior>(store.getUInt32ValueForKey(WebPreferencesKey::editableLinkBehaviorKey()))); -#if PLATFORM(WIN) - // Temporarily turn off accelerated compositing until we have a good solution for rendering it. - settings->setAcceleratedCompositingEnabled(false); - settings->setAcceleratedDrawingEnabled(false); - settings->setCanvasUsesAcceleratedDrawing(false); -#else - settings->setAcceleratedCompositingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedCompositingEnabledKey())); - settings->setAcceleratedDrawingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedDrawingEnabledKey())); - settings->setCanvasUsesAcceleratedDrawing(store.getBoolValueForKey(WebPreferencesKey::canvasUsesAcceleratedDrawingKey())); -#endif + settings->setAcceleratedCompositingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedCompositingEnabledKey()) && LayerTreeHost::supportsAcceleratedCompositing()); + settings->setAcceleratedDrawingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedDrawingEnabledKey()) && LayerTreeHost::supportsAcceleratedCompositing()); + settings->setCanvasUsesAcceleratedDrawing(store.getBoolValueForKey(WebPreferencesKey::canvasUsesAcceleratedDrawingKey()) && LayerTreeHost::supportsAcceleratedCompositing()); settings->setShowDebugBorders(store.getBoolValueForKey(WebPreferencesKey::compositingBordersVisibleKey())); settings->setShowRepaintCounter(store.getBoolValueForKey(WebPreferencesKey::compositingRepaintCountersVisibleKey())); settings->setWebGLEnabled(store.getBoolValueForKey(WebPreferencesKey::webGLEnabledKey())); @@ -1441,7 +1481,7 @@ WebFullScreenManager* WebPage::fullScreenManager() } #endif -#if !PLATFORM(MAC) +#if !PLATFORM(GTK) && !PLATFORM(MAC) bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* evt) { Node* node = evt->target()->toNode(); @@ -1504,7 +1544,7 @@ void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint cli } } #else -void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const String& dragStorageName, uint32_t flags) +void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const String& dragStorageName, uint32_t flags, const SandboxExtension::Handle& sandboxExtensionHandle) { if (!m_page) { send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone)); @@ -1525,10 +1565,23 @@ void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint cli m_page->dragController()->dragExited(&dragData); break; - case DragControllerActionPerformDrag: + case DragControllerActionPerformDrag: { + ASSERT(!m_pendingDropSandboxExtension); + + m_pendingDropSandboxExtension = SandboxExtension::create(sandboxExtensionHandle); + m_page->dragController()->performDrag(&dragData); + + // If we started loading a local file, the sandbox extension tracker would have adopted this + // pending drop sandbox extension. If not, we'll play it safe and invalidate it. + if (m_pendingDropSandboxExtension) { + m_pendingDropSandboxExtension->invalidate(); + m_pendingDropSandboxExtension = nullptr; + } + break; - + } + default: ASSERT_NOT_REACHED(); } @@ -1550,6 +1603,11 @@ void WebPage::dragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint glob m_page->mainFrame()->eventHandler()->dragSourceEndedAt(event, (DragOperation)operation); } +void WebPage::willPerformLoadDragDestinationAction() +{ + m_sandboxExtensionTracker.willPerformLoadDragDestinationAction(m_pendingDropSandboxExtension.release()); +} + WebEditCommand* WebPage::webEditCommand(uint64_t commandID) { return m_editCommandMap.get(commandID).get(); @@ -1734,8 +1792,9 @@ void WebPage::didChangeScrollOffsetForMainFrame() Frame* frame = m_page->mainFrame(); IntPoint scrollPosition = frame->view()->scrollPosition(); IntPoint maximumScrollPosition = frame->view()->maximumScrollPosition(); + IntPoint minimumScrollPosition = frame->view()->minimumScrollPosition(); - bool isPinnedToLeftSide = (scrollPosition.x() <= 0); + bool isPinnedToLeftSide = (scrollPosition.x() <= minimumScrollPosition.x()); bool isPinnedToRightSide = (scrollPosition.x() >= maximumScrollPosition.x()); if (isPinnedToLeftSide != m_cachedMainFrameIsPinnedToLeftSide || isPinnedToRightSide != m_cachedMainFrameIsPinnedToRightSide) { @@ -1877,18 +1936,28 @@ void WebPage::SandboxExtensionTracker::invalidate() } } +void WebPage::SandboxExtensionTracker::willPerformLoadDragDestinationAction(PassRefPtr<SandboxExtension> pendingDropSandboxExtension) +{ + setPendingProvisionalSandboxExtension(pendingDropSandboxExtension); +} + void WebPage::SandboxExtensionTracker::beginLoad(WebFrame* frame, const SandboxExtension::Handle& handle) { ASSERT(frame->isMainFrame()); + setPendingProvisionalSandboxExtension(SandboxExtension::create(handle)); +} + +void WebPage::SandboxExtensionTracker::setPendingProvisionalSandboxExtension(PassRefPtr<SandboxExtension> pendingProvisionalSandboxExtension) +{ // If we get two beginLoad calls in succession, without a provisional load starting, then // m_pendingProvisionalSandboxExtension will be non-null. Invalidate and null out the extension if that is the case. if (m_pendingProvisionalSandboxExtension) { m_pendingProvisionalSandboxExtension->invalidate(); m_pendingProvisionalSandboxExtension = nullptr; } - - m_pendingProvisionalSandboxExtension = SandboxExtension::create(handle); + + m_pendingProvisionalSandboxExtension = pendingProvisionalSandboxExtension; } static bool shouldReuseCommittedSandboxExtension(WebFrame* frame) @@ -1907,8 +1976,7 @@ static bool shouldReuseCommittedSandboxExtension(WebFrame* frame) if (!documentLoader || !provisionalDocumentLoader) return false; - if (documentLoader->url().isLocalFile() && provisionalDocumentLoader->url().isLocalFile() - && provisionalDocumentLoader->triggeringAction().type() == NavigationTypeLinkClicked) + if (documentLoader->url().isLocalFile() && provisionalDocumentLoader->url().isLocalFile()) return true; return false; @@ -1953,7 +2021,6 @@ void WebPage::SandboxExtensionTracker::didFailProvisionalLoad(WebFrame* frame) if (!frame->isMainFrame()) return; - ASSERT(!m_pendingProvisionalSandboxExtension); if (!m_provisionalSandboxExtension) return; @@ -2058,7 +2125,7 @@ void WebPage::drawRectToPDF(uint64_t frameID, const WebCore::IntRect& rect, uint if (coreFrame) { ASSERT(coreFrame->document()->printing()); -#if PLATFORM(CG) +#if USE(CG) // FIXME: Use CGDataConsumerCreate with callbacks to avoid copying the data. RetainPtr<CGDataConsumerRef> pdfDataConsumer(AdoptCF, CGDataConsumerCreateWithCFData(pdfPageData.get())); @@ -2090,7 +2157,7 @@ void WebPage::drawPagesToPDF(uint64_t frameID, uint32_t first, uint32_t count, u if (coreFrame) { ASSERT(coreFrame->document()->printing()); -#if PLATFORM(CG) +#if USE(CG) // FIXME: Use CGDataConsumerCreate with callbacks to avoid copying the data. RetainPtr<CGDataConsumerRef> pdfDataConsumer(AdoptCF, CGDataConsumerCreateWithCFData(pdfPageData.get())); @@ -2159,4 +2226,19 @@ void WebPage::handleCorrectionPanelResult(const String& result) } #endif +void WebPage::simulateMouseDown(int button, WebCore::IntPoint position, int clickCount, WKEventModifiers modifiers, double time) +{ + mouseEvent(WebMouseEvent(WebMouseEvent::MouseDown, static_cast<WebMouseEvent::Button>(button), position, position, 0, 0, 0, clickCount, static_cast<WebMouseEvent::Modifiers>(modifiers), time)); +} + +void WebPage::simulateMouseUp(int button, WebCore::IntPoint position, int clickCount, WKEventModifiers modifiers, double time) +{ + mouseEvent(WebMouseEvent(WebMouseEvent::MouseUp, static_cast<WebMouseEvent::Button>(button), position, position, 0, 0, 0, clickCount, static_cast<WebMouseEvent::Modifiers>(modifiers), time)); +} + +void WebPage::simulateMouseMotion(WebCore::IntPoint position, double time) +{ + mouseEvent(WebMouseEvent(WebMouseEvent::MouseMove, WebMouseEvent::NoButton, position, position, 0, 0, 0, 0, WebMouseEvent::Modifiers(), time)); +} + } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/WebPage.h b/Source/WebKit2/WebProcess/WebPage/WebPage.h index 8e4e71c..7828b45 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebPage.h +++ b/Source/WebKit2/WebProcess/WebPage/WebPage.h @@ -34,6 +34,7 @@ #include "InjectedBundlePageContextMenuClient.h" #include "InjectedBundlePageEditorClient.h" #include "InjectedBundlePageFormClient.h" +#include "InjectedBundlePageFullScreenClient.h" #include "InjectedBundlePageLoaderClient.h" #include "InjectedBundlePagePolicyClient.h" #include "InjectedBundlePageResourceLoadClient.h" @@ -81,6 +82,7 @@ namespace WebCore { class ResourceRequest; class SharedBuffer; class VisibleSelection; + struct KeypressCommand; } namespace WebKit { @@ -103,6 +105,8 @@ class WebOpenPanelResultListener; class WebPageGroupProxy; class WebPopupMenu; class WebWheelEvent; +struct AttributedString; +struct EditorState; struct PrintInfo; struct WebPageCreationParameters; struct WebPreferencesStore; @@ -159,9 +163,12 @@ public: void layoutIfNeeded(); // -- Called from WebCore clients. -#if !PLATFORM(MAC) +#if PLATFORM(MAC) + bool handleEditingKeyboardEvent(WebCore::KeyboardEvent*, bool saveCommands); +#elif !PLATFORM(GTK) bool handleEditingKeyboardEvent(WebCore::KeyboardEvent*); #endif + void show(); String userAgent() const { return m_userAgent; } WebCore::IntRect windowResizerRect() const; @@ -189,6 +196,9 @@ public: void initializeInjectedBundlePolicyClient(WKBundlePagePolicyClient*); void initializeInjectedBundleResourceLoadClient(WKBundlePageResourceLoadClient*); void initializeInjectedBundleUIClient(WKBundlePageUIClient*); +#if ENABLE(FULLSCREEN_API) + void initializeInjectedBundleFullScreenClient(WKBundlePageFullScreenClient*); +#endif InjectedBundlePageContextMenuClient& injectedBundleContextMenuClient() { return m_contextMenuClient; } InjectedBundlePageEditorClient& injectedBundleEditorClient() { return m_editorClient; } @@ -197,12 +207,17 @@ public: InjectedBundlePagePolicyClient& injectedBundlePolicyClient() { return m_policyClient; } InjectedBundlePageResourceLoadClient& injectedBundleResourceLoadClient() { return m_resourceLoadClient; } InjectedBundlePageUIClient& injectedBundleUIClient() { return m_uiClient; } +#if ENABLE(FULLSCREEN_API) + InjectedBundlePageFullScreenClient& injectedBundleFullScreenClient() { return m_fullScreenClient; } +#endif bool findStringFromInjectedBundle(const String&, FindOptions); WebFrame* mainFrame() const { return m_mainFrame.get(); } PassRefPtr<Plugin> createPlugin(const Plugin::Parameters&); + EditorState editorState() const; + String renderTreeExternalRepresentation() const; void executeEditingCommand(const String& commandName, const String& argument); bool isEditingCommandEnabled(const String& commandName); @@ -240,14 +255,13 @@ public: bool windowIsVisible() const { return m_windowIsVisible; } const WebCore::IntRect& windowFrameInScreenCoordinates() const { return m_windowFrameInScreenCoordinates; } const WebCore::IntRect& viewFrameInWindowCoordinates() const { return m_viewFrameInWindowCoordinates; } - bool interceptEditingKeyboardEvent(WebCore::KeyboardEvent*, bool); #elif PLATFORM(WIN) HWND nativeWindow() const { return m_nativeWindow; } #endif bool windowIsFocused() const; void installPageOverlay(PassRefPtr<PageOverlay>); - void uninstallPageOverlay(PageOverlay*); + void uninstallPageOverlay(PageOverlay*, bool fadeOut); bool hasPageOverlay() const { return m_pageOverlay; } WebCore::IntRect windowToScreen(const WebCore::IntRect&); @@ -285,10 +299,14 @@ public: void invalidate(); void beginLoad(WebFrame*, const SandboxExtension::Handle& handle); + void willPerformLoadDragDestinationAction(PassRefPtr<SandboxExtension> pendingDropSandboxExtension); void didStartProvisionalLoad(WebFrame*); void didCommitProvisionalLoad(WebFrame*); void didFailProvisionalLoad(WebFrame*); + private: + void setPendingProvisionalSandboxExtension(PassRefPtr<SandboxExtension>); + RefPtr<SandboxExtension> m_pendingProvisionalSandboxExtension; RefPtr<SandboxExtension> m_provisionalSandboxExtension; RefPtr<SandboxExtension> m_committedSandboxExtension; @@ -296,8 +314,6 @@ public: SandboxExtensionTracker& sandboxExtensionTracker() { return m_sandboxExtensionTracker; } - static void getLocationAndLengthFromRange(WebCore::Range*, uint64_t& location, uint64_t& length); - #if PLATFORM(MAC) void registerUIProcessAccessibilityTokens(const CoreIPC::DataReference& elemenToken, const CoreIPC::DataReference& windowToken); AccessibilityWebPageObject* accessibilityRemoteObject(); @@ -305,16 +321,29 @@ public: void sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput); + void setComposition(const String& text, Vector<WebCore::CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, EditorState& newState); + void confirmComposition(EditorState& newState); + void insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, bool& handled, EditorState& newState); void getMarkedRange(uint64_t& location, uint64_t& length); + void getSelectedRange(uint64_t& location, uint64_t& length); + void getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString&); void characterIndexForPoint(const WebCore::IntPoint point, uint64_t& result); void firstRectForCharacterRange(uint64_t location, uint64_t length, WebCore::IntRect& resultRect); + void executeKeypressCommands(const Vector<WebCore::KeypressCommand>&, bool& handled, EditorState& newState); void writeSelectionToPasteboard(const WTF::String& pasteboardName, const WTF::Vector<WTF::String>& pasteboardTypes, bool& result); void readSelectionFromPasteboard(const WTF::String& pasteboardName, bool& result); + void shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent&, bool& result); + void acceptsFirstMouse(int eventNumber, const WebKit::WebMouseEvent&, bool& result); + bool performNonEditingBehaviorForSelector(const String&); #elif PLATFORM(WIN) void confirmComposition(const String& compositionString); void setComposition(const WTF::String& compositionString, const WTF::Vector<WebCore::CompositionUnderline>& underlines, uint64_t cursorPosition); void firstRectForCharacterInSelectedRange(const uint64_t characterPosition, WebCore::IntRect& resultRect); void getSelectedText(WTF::String&); + + void gestureWillBegin(const WebCore::IntPoint&, bool& canBeginPanning); + void gestureDidScroll(const WebCore::IntSize&); + void gestureDidEnd(); #endif // FIXME: This a dummy message, to avoid breaking the build for platforms that don't require @@ -335,10 +364,12 @@ public: #if PLATFORM(WIN) void performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const WebCore::DragDataMap&, uint32_t flags); #else - void performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const WTF::String& dragStorageName, uint32_t flags); + void performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const WTF::String& dragStorageName, uint32_t flags, const SandboxExtension::Handle&); #endif void dragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t operation); + void willPerformLoadDragDestinationAction(); + void beginPrinting(uint64_t frameID, const PrintInfo&); void endPrinting(); void computePagesForPrinting(uint64_t frameID, const PrintInfo&, uint64_t callbackID); @@ -365,6 +396,9 @@ public: void forceRepaintWithoutCallback(); + void unmarkAllMisspellings(); + void unmarkAllBadGrammar(); + #if PLATFORM(MAC) void setDragSource(NSObject *); #endif @@ -373,6 +407,12 @@ public: void handleCorrectionPanelResult(const String&); #endif + void simulateMouseDown(int button, WebCore::IntPoint, int clickCount, WKEventModifiers, double time); + void simulateMouseUp(int button, WebCore::IntPoint, int clickCount, WKEventModifiers, double time); + void simulateMouseMotion(WebCore::IntPoint, double time); + + void contextMenuShowing() { m_isShowingContextMenu = true; } + private: WebPage(uint64_t pageID, const WebPageCreationParameters&); @@ -383,9 +423,15 @@ private: void didReceiveWebPageMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*); CoreIPC::SyncReplyMode didReceiveSyncWebPageMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*, CoreIPC::ArgumentEncoder*); +#if !PLATFORM(MAC) static const char* interpretKeyEvent(const WebCore::KeyboardEvent*); +#endif bool performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&); +#if PLATFORM(MAC) + bool executeKeypressCommandsInternal(const Vector<WebCore::KeypressCommand>&, WebCore::KeyboardEvent*); +#endif + String sourceForFrame(WebFrame*); void loadData(PassRefPtr<WebCore::SharedBuffer>, const String& MIMEType, const String& encodingName, const WebCore::KURL& baseURL, const WebCore::KURL& failingURL); @@ -399,6 +445,7 @@ private: void loadHTMLString(const String& htmlString, const String& baseURL); void loadAlternateHTMLString(const String& htmlString, const String& baseURL, const String& unreachableURL); void loadPlainTextString(const String&); + void linkClicked(const String& url, const WebMouseEvent&); void reload(bool reloadFromOrigin); void goForward(uint64_t, const SandboxExtension::Handle&); void goBack(uint64_t, const SandboxExtension::Handle&); @@ -420,6 +467,7 @@ private: #if ENABLE(TOUCH_EVENTS) void touchEvent(const WebTouchEvent&); #endif + void contextMenuHidden() { m_isShowingContextMenu = false; } static void scroll(WebCore::Page*, WebCore::ScrollDirection, WebCore::ScrollGranularity); static void logicalScroll(WebCore::Page*, WebCore::ScrollLogicalDirection, WebCore::ScrollGranularity); @@ -486,8 +534,6 @@ private: void advanceToNextMisspelling(bool startBeforeSelection); void changeSpellingToWord(const String& word); - void unmarkAllMisspellings(); - void unmarkAllBadGrammar(); #if PLATFORM(MAC) void uppercaseWord(); void lowercaseWord(); @@ -545,9 +591,14 @@ private: RetainPtr<AccessibilityWebPageObject> m_mockAccessibilityElement; RetainPtr<NSObject> m_dragSource; + + WebCore::KeyboardEvent* m_keyboardEventBeingInterpreted; + #elif PLATFORM(WIN) // Our view's window (in the UI process). HWND m_nativeWindow; + + RefPtr<WebCore::Node> m_gestureTargetNode; #endif HashMap<uint64_t, RefPtr<WebEditCommand> > m_editCommandMap; @@ -561,6 +612,9 @@ private: InjectedBundlePagePolicyClient m_policyClient; InjectedBundlePageResourceLoadClient m_resourceLoadClient; InjectedBundlePageUIClient m_uiClient; +#if ENABLE(FULLSCREEN_API) + InjectedBundlePageFullScreenClient m_fullScreenClient; +#endif #if ENABLE(TILED_BACKING_STORE) WebCore::IntSize m_resizesToContentsLayoutSize; @@ -585,6 +639,8 @@ private: SandboxExtensionTracker m_sandboxExtensionTracker; uint64_t m_pageID; + RefPtr<SandboxExtension> m_pendingDropSandboxExtension; + bool m_canRunBeforeUnloadConfirmPanel; bool m_canRunModal; @@ -594,6 +650,12 @@ private: bool m_cachedMainFrameIsPinnedToLeftSide; bool m_cachedMainFrameIsPinnedToRightSide; + + bool m_isShowingContextMenu; + +#if PLATFORM(WIN) + bool m_gestureReachedScrollingLimit; +#endif }; } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in index 69bd54d..673e8d6 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in +++ b/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in @@ -42,6 +42,8 @@ messages -> WebPage { TouchEvent(WebKit::WebTouchEvent event) #endif + ContextMenuHidden() + ScrollBy(uint32_t scrollDirection, uint32_t scrollGranularity) GoBack(uint64_t backForwardItemID, WebKit::SandboxExtension::Handle sandboxExtensionHandle) @@ -52,6 +54,7 @@ messages -> WebPage { LoadPlainTextString(WTF::String string) LoadURL(WTF::String url, WebKit::SandboxExtension::Handle sandboxExtensionHandle) LoadURLRequest(WebCore::ResourceRequest request, WebKit::SandboxExtension::Handle sandboxExtensionHandle) + LinkClicked(WTF::String url, WebKit::WebMouseEvent event) Reload(bool reloadFromOrigin) StopLoading() @@ -119,7 +122,7 @@ messages -> WebPage { PerformDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, HashMap<UINT,Vector<String>> dataMap, uint32_t flags) #endif #if !PLATFORM(WIN) - PerformDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, WTF::String dragStorageName, uint32_t flags) + PerformDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, WTF::String dragStorageName, uint32_t flags, WebKit::SandboxExtension::Handle sandboxExtensionHandle) #endif DragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t operation) @@ -140,8 +143,6 @@ messages -> WebPage { # Spelling and grammar. AdvanceToNextMisspelling(bool startBeforeSelection) ChangeSpellingToWord(WTF::String word) - UnmarkAllMisspellings() - UnmarkAllBadGrammar() #if PLATFORM(MAC) UppercaseWord(); LowercaseWord(); @@ -179,18 +180,33 @@ messages -> WebPage { SetWindowIsVisible(bool windowIsVisible) WindowAndViewFramesChanged(WebCore::IntRect windowFrameInScreenCoordinates, WebCore::IntRect viewFrameInWindowCoordinates, WebCore::IntPoint accessibilityViewCoordinates) - GetMarkedRange() -> (uint64_t location, uint64_t length) - CharacterIndexForPoint(WebCore::IntPoint point) -> (uint64_t result) - FirstRectForCharacterRange(uint64_t location, uint64_t length) -> (WebCore::IntRect resultRect) RegisterUIProcessAccessibilityTokens(CoreIPC::DataReference elemenToken, CoreIPC::DataReference windowToken) WriteSelectionToPasteboard(WTF::String pasteboardName, WTF::Vector<WTF::String> pasteboardTypes) -> (bool result) ReadSelectionFromPasteboard(WTF::String pasteboardName) -> (bool result) + + # Text input. + SetComposition(WTF::String text, WTF::Vector<WebCore::CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd) -> (WebKit::EditorState newState) + ConfirmComposition() -> (WebKit::EditorState newState) + InsertText(WTF::String text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd) -> (bool handled, WebKit::EditorState newState) + GetMarkedRange() -> (uint64_t location, uint64_t length) + GetSelectedRange() -> (uint64_t location, uint64_t length) + GetAttributedSubstringFromRange(uint64_t location, uint64_t length) -> (WebKit::AttributedString result) + CharacterIndexForPoint(WebCore::IntPoint point) -> (uint64_t result) + FirstRectForCharacterRange(uint64_t location, uint64_t length) -> (WebCore::IntRect resultRect) + ExecuteKeypressCommands(Vector<WebCore::KeypressCommand> savedCommands) -> (bool handled, WebKit::EditorState newState) + ShouldDelayWindowOrderingEvent(WebKit::WebMouseEvent event) -> (bool result) + AcceptsFirstMouse(int eventNumber, WebKit::WebMouseEvent event) -> (bool result) #endif #if PLATFORM(WIN) + // FIXME: Unify with Mac counterparts. ConfirmComposition(WTF::String compositionString) SetComposition(WTF::String compositionString, WTF::Vector<WebCore::CompositionUnderline> underlines, uint64_t cursorPosition) FirstRectForCharacterInSelectedRange(uint64_t characterPosition) -> (WebCore::IntRect resultRect) GetSelectedText() -> (WTF::String text) + + GestureWillBegin(WebCore::IntPoint point) -> (bool canBeginPanning) + GestureDidScroll(WebCore::IntSize size) + GestureDidEnd() #endif #if PLATFORM(QT) FindZoomableAreaForPoint(WebCore::IntPoint point) diff --git a/Source/WebKit2/WebProcess/WebPage/WebPageGroupProxy.h b/Source/WebKit2/WebProcess/WebPage/WebPageGroupProxy.h index 55cf629..91e6c5c 100644 --- a/Source/WebKit2/WebProcess/WebPage/WebPageGroupProxy.h +++ b/Source/WebKit2/WebProcess/WebPage/WebPageGroupProxy.h @@ -42,6 +42,7 @@ public: const String& identifier() const { return m_data.identifer; } uint64_t pageGroupID() const { return m_data.pageGroupID; } bool isVisibleToInjectedBundle() const { return m_data.visibleToInjectedBundle; } + bool isVisibleToHistoryClient() const { return m_data.visibleToHistoryClient; } private: WebPageGroupProxy(const WebPageGroupData& data) diff --git a/Source/WebKit2/WebProcess/WebPage/ca/LayerTreeHostCA.cpp b/Source/WebKit2/WebProcess/WebPage/ca/LayerTreeHostCA.cpp index 2460607..42a2dc9 100644 --- a/Source/WebKit2/WebProcess/WebPage/ca/LayerTreeHostCA.cpp +++ b/Source/WebKit2/WebProcess/WebPage/ca/LayerTreeHostCA.cpp @@ -31,39 +31,41 @@ #include "WebProcess.h" #include <WebCore/Frame.h> #include <WebCore/FrameView.h> +#include <WebCore/GraphicsLayerCA.h> #include <WebCore/Page.h> +#include <WebCore/PlatformCALayer.h> #include <WebCore/Settings.h> using namespace WebCore; namespace WebKit { -PassRefPtr<LayerTreeHostCA> LayerTreeHostCA::create(WebPage* webPage) -{ - return adoptRef(new LayerTreeHostCA(webPage)); -} - LayerTreeHostCA::LayerTreeHostCA(WebPage* webPage) : LayerTreeHost(webPage) , m_isValid(true) , m_notifyAfterScheduledLayerFlush(false) { +} +void LayerTreeHostCA::initialize() +{ // Create a root layer. m_rootLayer = GraphicsLayer::create(this); #ifndef NDEBUG m_rootLayer->setName("LayerTreeHost root layer"); #endif m_rootLayer->setDrawsContent(false); - m_rootLayer->setSize(webPage->size()); + m_rootLayer->setSize(m_webPage->size()); + static_cast<GraphicsLayerCA*>(m_rootLayer.get())->platformCALayer()->setGeometryFlipped(true); m_nonCompositedContentLayer = GraphicsLayer::create(this); + static_cast<GraphicsLayerCA*>(m_nonCompositedContentLayer.get())->setAllowTiledLayer(false); #ifndef NDEBUG m_nonCompositedContentLayer->setName("LayerTreeHost non-composited content"); #endif m_nonCompositedContentLayer->setDrawsContent(true); m_nonCompositedContentLayer->setContentsOpaque(m_webPage->drawsBackground() && !m_webPage->drawsTransparentBackground()); - m_nonCompositedContentLayer->setSize(webPage->size()); + m_nonCompositedContentLayer->setSize(m_webPage->size()); if (m_webPage->corePage()->settings()->acceleratedDrawingEnabled()) m_nonCompositedContentLayer->setAcceleratesDrawing(true); @@ -72,7 +74,7 @@ LayerTreeHostCA::LayerTreeHostCA(WebPage* webPage) if (m_webPage->hasPageOverlay()) createPageOverlayLayer(); - platformInitialize(); + platformInitialize(m_layerTreeContext); scheduleLayerFlush(); } @@ -81,10 +83,6 @@ LayerTreeHostCA::~LayerTreeHostCA() { ASSERT(!m_isValid); ASSERT(!m_rootLayer); -#if PLATFORM(MAC) - ASSERT(!m_flushPendingLayerChangesRunLoopObserver); - ASSERT(!m_remoteLayerClient); -#endif } const LayerTreeContext& LayerTreeHostCA::layerTreeContext() @@ -109,7 +107,6 @@ void LayerTreeHostCA::setRootCompositingLayer(GraphicsLayer* graphicsLayer) void LayerTreeHostCA::invalidate() { ASSERT(m_isValid); - platformInvalidate(); m_rootLayer = nullptr; m_isValid = false; } @@ -138,16 +135,12 @@ void LayerTreeHostCA::sizeDidChange(const IntSize& newSize) scheduleLayerFlush(); flushPendingLayerChanges(); - - platformSizeDidChange(); } void LayerTreeHostCA::forceRepaint() { scheduleLayerFlush(); flushPendingLayerChanges(); - - platformForceRepaint(); } void LayerTreeHostCA::didInstallPageOverlay() @@ -218,8 +211,6 @@ void LayerTreeHostCA::performScheduledLayerFlush() void LayerTreeHostCA::didPerformScheduledLayerFlush() { - platformDidPerformScheduledLayerFlush(); - if (m_notifyAfterScheduledLayerFlush) { // Let the drawing area know that we've done a flush of the layer changes. static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->layerHostDidFlushLayers(); diff --git a/Source/WebKit2/WebProcess/WebPage/ca/LayerTreeHostCA.h b/Source/WebKit2/WebProcess/WebPage/ca/LayerTreeHostCA.h index ba4e33a..3a62d15 100644 --- a/Source/WebKit2/WebProcess/WebPage/ca/LayerTreeHostCA.h +++ b/Source/WebKit2/WebProcess/WebPage/ca/LayerTreeHostCA.h @@ -31,35 +31,36 @@ #include <WebCore/GraphicsLayerClient.h> #include <wtf/OwnPtr.h> -#if PLATFORM(MAC) -#include <wtf/RetainPtr.h> -#endif - -#if PLATFORM(MAC) -typedef struct __WKCARemoteLayerClientRef* WKCARemoteLayerClientRef; -#endif - namespace WebKit { class LayerTreeHostCA : public LayerTreeHost, WebCore::GraphicsLayerClient { public: - static PassRefPtr<LayerTreeHostCA> create(WebPage*); - ~LayerTreeHostCA(); + virtual ~LayerTreeHostCA(); -private: +protected: explicit LayerTreeHostCA(WebPage*); + WebCore::GraphicsLayer* rootLayer() const { return m_rootLayer.get(); } + + void initialize(); + void performScheduledLayerFlush(); + + // LayerTreeHost. + virtual void invalidate(); + virtual void sizeDidChange(const WebCore::IntSize& newSize); + virtual void forceRepaint(); + + // LayerTreeHostCA + virtual void didPerformScheduledLayerFlush(); + +private: // LayerTreeHost. virtual const LayerTreeContext& layerTreeContext(); - virtual void scheduleLayerFlush(); virtual void setShouldNotifyAfterNextScheduledLayerFlush(bool); virtual void setRootCompositingLayer(WebCore::GraphicsLayer*); - virtual void invalidate(); virtual void setNonCompositedContentsNeedDisplay(const WebCore::IntRect&); virtual void scrollNonCompositedContents(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset); - virtual void sizeDidChange(const WebCore::IntSize& newSize); - virtual void forceRepaint(); virtual void didInstallPageOverlay(); virtual void didUninstallPageOverlay(); @@ -72,23 +73,14 @@ private: virtual bool showDebugBorders() const; virtual bool showRepaintCounter() const; - void platformInitialize(); - void platformInvalidate(); - void platformSizeDidChange(); - void platformForceRepaint(); + // LayerTreeHostCA + virtual void platformInitialize(LayerTreeContext&) = 0; - void performScheduledLayerFlush(); - void didPerformScheduledLayerFlush(); - void platformDidPerformScheduledLayerFlush(); bool flushPendingLayerChanges(); void createPageOverlayLayer(); void destroyPageOverlayLayer(); -#if PLATFORM(MAC) - static void flushPendingLayerChangesRunLoopObserverCallback(CFRunLoopObserverRef, CFRunLoopActivity, void*); -#endif - // The context for this layer tree. LayerTreeContext m_layerTreeContext; @@ -107,11 +99,6 @@ private: // The page overlay layer. Will be null if there's no page overlay. OwnPtr<WebCore::GraphicsLayer> m_pageOverlayLayer; - -#if PLATFORM(MAC) - RetainPtr<WKCARemoteLayerClientRef> m_remoteLayerClient; - RetainPtr<CFRunLoopObserverRef> m_flushPendingLayerChangesRunLoopObserver; -#endif }; } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/ca/mac/LayerTreeHostCAMac.h b/Source/WebKit2/WebProcess/WebPage/ca/mac/LayerTreeHostCAMac.h new file mode 100644 index 0000000..e3a0160 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/ca/mac/LayerTreeHostCAMac.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LayerTreeHostCAMac_h +#define LayerTreeHostCAMac_h + +#include "LayerTreeHostCA.h" +#include <wtf/RetainPtr.h> + +typedef struct __WKCARemoteLayerClientRef* WKCARemoteLayerClientRef; + +namespace WebKit { + +class LayerTreeHostCAMac : public LayerTreeHostCA { +public: + static PassRefPtr<LayerTreeHostCAMac> create(WebPage*); + virtual ~LayerTreeHostCAMac(); + +private: + explicit LayerTreeHostCAMac(WebPage*); + + // LayerTreeHost. + virtual void scheduleLayerFlush(); + virtual void invalidate(); + virtual void sizeDidChange(const WebCore::IntSize& newSize); + virtual void forceRepaint(); + virtual void pauseRendering(); + virtual void resumeRendering(); + + // LayerTreeHostCA + virtual void platformInitialize(LayerTreeContext&); + virtual void didPerformScheduledLayerFlush(); + + static void flushPendingLayerChangesRunLoopObserverCallback(CFRunLoopObserverRef, CFRunLoopActivity, void*); + + RetainPtr<WKCARemoteLayerClientRef> m_remoteLayerClient; + RetainPtr<CFRunLoopObserverRef> m_flushPendingLayerChangesRunLoopObserver; +}; + +} // namespace WebKit + +#endif // LayerTreeHostCAMac_h diff --git a/Source/WebKit2/WebProcess/WebPage/ca/mac/LayerTreeHostCAMac.mm b/Source/WebKit2/WebProcess/WebPage/ca/mac/LayerTreeHostCAMac.mm index 50776d7..69cfa44 100644 --- a/Source/WebKit2/WebProcess/WebPage/ca/mac/LayerTreeHostCAMac.mm +++ b/Source/WebKit2/WebProcess/WebPage/ca/mac/LayerTreeHostCAMac.mm @@ -24,32 +24,50 @@ */ #import "config.h" -#import "LayerTreeHostCA.h" +#import "LayerTreeHostCAMac.h" #import "WebProcess.h" #import <QuartzCore/CATransaction.h> #import <WebCore/GraphicsLayer.h> #import <WebKitSystemInterface.h> +using namespace WebCore; + @interface CATransaction (Details) + (void)synchronize; @end namespace WebKit { -void LayerTreeHostCA::platformInitialize() +PassRefPtr<LayerTreeHostCAMac> LayerTreeHostCAMac::create(WebPage* webPage) +{ + RefPtr<LayerTreeHostCAMac> host = adoptRef(new LayerTreeHostCAMac(webPage)); + host->initialize(); + return host.release(); +} + +LayerTreeHostCAMac::LayerTreeHostCAMac(WebPage* webPage) + : LayerTreeHostCA(webPage) +{ +} + +LayerTreeHostCAMac::~LayerTreeHostCAMac() +{ + ASSERT(!m_flushPendingLayerChangesRunLoopObserver); + ASSERT(!m_remoteLayerClient); +} + +void LayerTreeHostCAMac::platformInitialize(LayerTreeContext& layerTreeContext) { mach_port_t serverPort = WebProcess::shared().compositingRenderServerPort(); m_remoteLayerClient = WKCARemoteLayerClientMakeWithServerPort(serverPort); - [m_rootLayer->platformLayer() setGeometryFlipped:YES]; + WKCARemoteLayerClientSetLayer(m_remoteLayerClient.get(), rootLayer()->platformLayer()); - WKCARemoteLayerClientSetLayer(m_remoteLayerClient.get(), m_rootLayer->platformLayer()); - - m_layerTreeContext.contextID = WKCARemoteLayerClientGetClientId(m_remoteLayerClient.get()); + layerTreeContext.contextID = WKCARemoteLayerClientGetClientId(m_remoteLayerClient.get()); } -void LayerTreeHostCA::scheduleLayerFlush() +void LayerTreeHostCAMac::scheduleLayerFlush() { CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent(); @@ -67,7 +85,7 @@ void LayerTreeHostCA::scheduleLayerFlush() CFRunLoopAddObserver(currentRunLoop, m_flushPendingLayerChangesRunLoopObserver.get(), kCFRunLoopCommonModes); } -void LayerTreeHostCA::platformInvalidate() +void LayerTreeHostCAMac::invalidate() { if (m_flushPendingLayerChangesRunLoopObserver) { CFRunLoopObserverInvalidate(m_flushPendingLayerChangesRunLoopObserver.get()); @@ -76,34 +94,54 @@ void LayerTreeHostCA::platformInvalidate() WKCARemoteLayerClientInvalidate(m_remoteLayerClient.get()); m_remoteLayerClient = nullptr; + + LayerTreeHostCA::invalidate(); } -void LayerTreeHostCA::platformSizeDidChange() +void LayerTreeHostCAMac::sizeDidChange(const IntSize& newSize) { + LayerTreeHostCA::sizeDidChange(newSize); [CATransaction flush]; [CATransaction synchronize]; } -void LayerTreeHostCA::platformForceRepaint() +void LayerTreeHostCAMac::forceRepaint() { + LayerTreeHostCA::forceRepaint(); [CATransaction flush]; [CATransaction synchronize]; -} +} + +void LayerTreeHostCAMac::pauseRendering() +{ + CALayer* root = rootLayer()->platformLayer(); + [root setValue:(id)kCFBooleanTrue forKey:@"NSCAViewRenderPaused"]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"NSCAViewRenderDidPauseNotification" object:nil userInfo:[NSDictionary dictionaryWithObject:root forKey:@"layer"]]; +} -void LayerTreeHostCA::flushPendingLayerChangesRunLoopObserverCallback(CFRunLoopObserverRef, CFRunLoopActivity, void* context) +void LayerTreeHostCAMac::resumeRendering() +{ + CALayer* root = rootLayer()->platformLayer(); + [root setValue:(id)kCFBooleanFalse forKey:@"NSCAViewRenderPaused"]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"NSCAViewRenderDidResumeNotification" object:nil userInfo:[NSDictionary dictionaryWithObject:root forKey:@"layer"]]; +} + +void LayerTreeHostCAMac::flushPendingLayerChangesRunLoopObserverCallback(CFRunLoopObserverRef, CFRunLoopActivity, void* context) { // This gets called outside of the normal event loop so wrap in an autorelease pool NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - static_cast<LayerTreeHostCA*>(context)->performScheduledLayerFlush(); + static_cast<LayerTreeHostCAMac*>(context)->performScheduledLayerFlush(); [pool drain]; } -void LayerTreeHostCA::platformDidPerformScheduledLayerFlush() +void LayerTreeHostCAMac::didPerformScheduledLayerFlush() { // We successfully flushed the pending layer changes, remove the run loop observer. ASSERT(m_flushPendingLayerChangesRunLoopObserver); CFRunLoopObserverInvalidate(m_flushPendingLayerChangesRunLoopObserver.get()); m_flushPendingLayerChangesRunLoopObserver = 0; + + LayerTreeHostCA::didPerformScheduledLayerFlush(); } } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp b/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp index 81db03e..699a1fe 100644 --- a/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp +++ b/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.cpp @@ -24,46 +24,276 @@ */ #include "config.h" -#include "LayerTreeHostCA.h" +#include "LayerTreeHostCAWin.h" -#include <WebCore/NotImplemented.h> +#if HAVE(WKQCA) + +#include "DrawingAreaImpl.h" +#include "ShareableBitmap.h" +#include "UpdateInfo.h" +#include "WebPage.h" +#include <WebCore/GraphicsLayerCA.h> +#include <WebCore/LayerChangesFlusher.h> +#include <WebCore/PlatformCALayer.h> +#include <WebCore/WebCoreInstanceHandle.h> +#include <WebKitQuartzCoreAdditions/WKCACFImage.h> +#include <WebKitQuartzCoreAdditions/WKCACFView.h> +#include <wtf/CurrentTime.h> +#include <wtf/Threading.h> + +#ifdef DEBUG_ALL +#pragma comment(lib, "WebKitQuartzCoreAdditions_debug") +#else +#pragma comment(lib, "WebKitQuartzCoreAdditions") +#endif + +using namespace WebCore; namespace WebKit { -void LayerTreeHostCA::platformInitialize() +static HWND dummyWindow; +static LPCWSTR dummyWindowClass = L"LayerTreeHostCAWindowClass"; +static size_t validLayerTreeHostCount; + +static void registerDummyWindowClass() +{ + static bool didRegister; + if (didRegister) + return; + didRegister = true; + + WNDCLASSW wndClass = {0}; + wndClass.lpszClassName = dummyWindowClass; + wndClass.lpfnWndProc = ::DefWindowProcW; + wndClass.hInstance = instanceHandle(); + + ::RegisterClassW(&wndClass); +} + +// This window is never shown. It is only needed so that D3D can determine the display mode, etc. +static HWND createDummyWindow() { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); + registerDummyWindowClass(); + return ::CreateWindowW(dummyWindowClass, 0, WS_POPUP, 0, 0, 10, 10, 0, 0, instanceHandle(), 0); } -void LayerTreeHostCA::scheduleLayerFlush() +bool LayerTreeHostCAWin::supportsAcceleratedCompositing() { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); + static bool initialized; + static bool supportsAcceleratedCompositing; + if (initialized) + return supportsAcceleratedCompositing; + initialized = true; + + ASSERT(!dummyWindow); + dummyWindow = createDummyWindow(); + RetainPtr<WKCACFViewRef> view(AdoptCF, WKCACFViewCreate(kWKCACFViewDrawingDestinationImage)); + CGRect fakeBounds = CGRectMake(0, 0, 10, 10); + WKCACFViewUpdate(view.get(), dummyWindow, &fakeBounds); + + supportsAcceleratedCompositing = WKCACFViewCanDraw(view.get()); + + WKCACFViewUpdate(view.get(), 0, 0); + ::DestroyWindow(dummyWindow); + dummyWindow = 0; + + return supportsAcceleratedCompositing; } -void LayerTreeHostCA::platformInvalidate() +PassRefPtr<LayerTreeHostCAWin> LayerTreeHostCAWin::create(WebPage* webPage) { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); + RefPtr<LayerTreeHostCAWin> host = adoptRef(new LayerTreeHostCAWin(webPage)); + host->initialize(); + return host.release(); } -void LayerTreeHostCA::platformSizeDidChange() +LayerTreeHostCAWin::LayerTreeHostCAWin(WebPage* webPage) + : LayerTreeHostCA(webPage) + , m_isFlushingLayerChanges(false) + , m_nextDisplayTime(0) { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); } -void LayerTreeHostCA::platformForceRepaint() +LayerTreeHostCAWin::~LayerTreeHostCAWin() { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); } -void LayerTreeHostCA::platformDidPerformScheduledLayerFlush() +void LayerTreeHostCAWin::platformInitialize(LayerTreeContext&) { - // FIXME: <http://webkit.org/b/45567> Implement this! - notImplemented(); + ++validLayerTreeHostCount; + if (!dummyWindow) + dummyWindow = createDummyWindow(); + + m_view.adoptCF(WKCACFViewCreate(kWKCACFViewDrawingDestinationImage)); + WKCACFViewSetContextUserData(m_view.get(), static_cast<AbstractCACFLayerTreeHost*>(this)); + WKCACFViewSetLayer(m_view.get(), rootLayer()->platformLayer()); + WKCACFViewSetContextDidChangeCallback(m_view.get(), contextDidChangeCallback, this); + + CGRect bounds = m_webPage->bounds(); + WKCACFViewUpdate(m_view.get(), dummyWindow, &bounds); +} + +void LayerTreeHostCAWin::invalidate() +{ + LayerChangesFlusher::shared().cancelPendingFlush(this); + + WKCACFViewUpdate(m_view.get(), 0, 0); + WKCACFViewSetContextUserData(m_view.get(), 0); + WKCACFViewSetLayer(m_view.get(), 0); + WKCACFViewSetContextDidChangeCallback(m_view.get(), 0, 0); + + LayerTreeHostCA::invalidate(); + + if (--validLayerTreeHostCount) + return; + ::DestroyWindow(dummyWindow); + dummyWindow = 0; +} + +void LayerTreeHostCAWin::scheduleLayerFlush() +{ + LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this); +} + +bool LayerTreeHostCAWin::participatesInDisplay() +{ + return true; +} + +bool LayerTreeHostCAWin::needsDisplay() +{ + return timeUntilNextDisplay() <= 0; +} + +double LayerTreeHostCAWin::timeUntilNextDisplay() +{ + return m_nextDisplayTime - currentTime(); +} + +static IntSize size(WKCACFImageRef image) +{ + return IntSize(WKCACFImageGetWidth(image), WKCACFImageGetHeight(image)); +} + +static PassRefPtr<ShareableBitmap> toShareableBitmap(WKCACFImageRef image) +{ + size_t fileMappingSize; + HANDLE mapping = WKCACFImageCopyFileMapping(image, &fileMappingSize); + if (!mapping) + return 0; + + RefPtr<SharedMemory> sharedMemory = SharedMemory::adopt(mapping, fileMappingSize, SharedMemory::ReadWrite); + if (!sharedMemory) { + ::CloseHandle(mapping); + return 0; + } + + // WKCACFImage never has an alpha channel. + return ShareableBitmap::create(size(image), 0, sharedMemory.release()); +} + +void LayerTreeHostCAWin::display(UpdateInfo& updateInfo) +{ + CGPoint imageOrigin; + CFTimeInterval nextDrawTime; + RetainPtr<WKCACFImageRef> image(AdoptCF, WKCACFViewCopyDrawnImage(m_view.get(), &imageOrigin, &nextDrawTime)); + m_nextDisplayTime = nextDrawTime - CACurrentMediaTime() + currentTime(); + if (!image) + return; + RefPtr<ShareableBitmap> bitmap = toShareableBitmap(image.get()); + if (!bitmap) + return; + if (!bitmap->createHandle(updateInfo.bitmapHandle)) + return; + updateInfo.updateRectBounds = IntRect(IntPoint(imageOrigin.x, m_webPage->size().height() - imageOrigin.y - bitmap->size().height()), bitmap->size()); + updateInfo.updateRects.append(updateInfo.updateRectBounds); +} + +void LayerTreeHostCAWin::sizeDidChange(const IntSize& newSize) +{ + LayerTreeHostCA::sizeDidChange(newSize); + CGRect bounds = CGRectMake(0, 0, newSize.width(), newSize.height()); + WKCACFViewUpdate(m_view.get(), dummyWindow, &bounds); + WKCACFViewFlushContext(m_view.get()); +} + +void LayerTreeHostCAWin::forceRepaint() +{ + LayerTreeHostCA::forceRepaint(); + WKCACFViewFlushContext(m_view.get()); +} + +void LayerTreeHostCAWin::contextDidChangeCallback(WKCACFViewRef view, void* info) +{ + // This should only be called on a background thread when no changes have actually + // been committed to the context, eg. when a video frame has been added to an image + // queue, so return without triggering animations etc. + if (!isMainThread()) + return; + + LayerTreeHostCAWin* host = static_cast<LayerTreeHostCAWin*>(info); + ASSERT_ARG(view, view == host->m_view); + host->contextDidChange(); +} + +void LayerTreeHostCAWin::contextDidChange() +{ + // Send currentTime to the pending animations. This function is called by CACF in a callback + // which occurs after the drawInContext calls. So currentTime is very close to the time + // the animations actually start + double currentTime = WTF::currentTime(); + + HashSet<RefPtr<PlatformCALayer> >::iterator end = m_pendingAnimatedLayers.end(); + for (HashSet<RefPtr<PlatformCALayer> >::iterator it = m_pendingAnimatedLayers.begin(); it != end; ++it) + (*it)->animationStarted(currentTime); + + m_pendingAnimatedLayers.clear(); + + m_nextDisplayTime = 0; + static_cast<DrawingAreaImpl*>(m_webPage->drawingArea())->setLayerHostNeedsDisplay(); +} + +PlatformCALayer* LayerTreeHostCAWin::rootLayer() const +{ + return static_cast<GraphicsLayerCA*>(LayerTreeHostCA::rootLayer())->platformCALayer(); +} + +void LayerTreeHostCAWin::addPendingAnimatedLayer(PassRefPtr<PlatformCALayer> layer) +{ + m_pendingAnimatedLayers.add(layer); +} + +void LayerTreeHostCAWin::layerTreeDidChange() +{ + if (m_isFlushingLayerChanges) { + // The layer tree is changing as a result of flushing GraphicsLayer changes to their + // underlying PlatformCALayers. We'll flush those changes to the context as part of that + // process, so there's no need to schedule another flush here. + return; + } + + // The layer tree is changing as a result of someone modifying a PlatformCALayer that doesn't + // have a corresponding GraphicsLayer. Schedule a flush since we won't schedule one through the + // normal GraphicsLayer mechanisms. + LayerChangesFlusher::shared().flushPendingLayerChangesSoon(this); +} + +void LayerTreeHostCAWin::flushPendingLayerChangesNow() +{ + RefPtr<LayerTreeHostCA> protector(this); + + m_isFlushingLayerChanges = true; + + // Flush changes stored up in GraphicsLayers to their underlying PlatformCALayers, if + // requested. + performScheduledLayerFlush(); + + // Flush changes stored up in PlatformCALayers to the context so they will be rendered. + WKCACFViewFlushContext(m_view.get()); + + m_isFlushingLayerChanges = false; } } // namespace WebKit + +#endif // HAVE(WKQCA) diff --git a/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.h b/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.h new file mode 100644 index 0000000..2232b08 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/ca/win/LayerTreeHostCAWin.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LayerTreeHostCAWin_h +#define LayerTreeHostCAWin_h + +#include "HeaderDetection.h" + +#if HAVE(WKQCA) + +#include "LayerTreeHostCA.h" +#include <WebCore/AbstractCACFLayerTreeHost.h> +#include <wtf/HashSet.h> +#include <wtf/RetainPtr.h> + +typedef struct _WKCACFView* WKCACFViewRef; + +namespace WebKit { + +class LayerTreeHostCAWin : public LayerTreeHostCA, private WebCore::AbstractCACFLayerTreeHost { +public: + static bool supportsAcceleratedCompositing(); + + static PassRefPtr<LayerTreeHostCAWin> create(WebPage*); + virtual ~LayerTreeHostCAWin(); + +private: + explicit LayerTreeHostCAWin(WebPage*); + + static void contextDidChangeCallback(WKCACFViewRef, void* info); + void contextDidChange(); + + // LayerTreeHost + virtual void invalidate(); + virtual void forceRepaint(); + virtual void sizeDidChange(const WebCore::IntSize& newSize); + virtual void scheduleLayerFlush(); + virtual bool participatesInDisplay(); + virtual bool needsDisplay(); + virtual double timeUntilNextDisplay(); + virtual void display(UpdateInfo&); + + // LayerTreeHostCA + virtual void platformInitialize(LayerTreeContext&); + + // AbstractCACFLayerTreeHost + virtual WebCore::PlatformCALayer* rootLayer() const; + virtual void addPendingAnimatedLayer(PassRefPtr<WebCore::PlatformCALayer>); + virtual void layerTreeDidChange(); + virtual void flushPendingLayerChangesNow(); + + RetainPtr<WKCACFViewRef> m_view; + HashSet<RefPtr<WebCore::PlatformCALayer> > m_pendingAnimatedLayers; + bool m_isFlushingLayerChanges; + double m_nextDisplayTime; +}; + +} // namespace WebKit + +#endif // HAVE(WKQCA) + +#endif // LayerTreeHostCAWin_h diff --git a/Source/WebKit2/WebProcess/WebPage/gtk/WebPageGtk.cpp b/Source/WebKit2/WebProcess/WebPage/gtk/WebPageGtk.cpp new file mode 100644 index 0000000..57c9977 --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/gtk/WebPageGtk.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved. + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPage.h" + +#include "NotImplemented.h" +#include "WebEvent.h" +#include "WindowsKeyboardCodes.h" +#include <WebCore/FocusController.h> +#include <WebCore/Frame.h> +#include <WebCore/KeyboardEvent.h> +#include <WebCore/Page.h> +#include <WebCore/PlatformKeyboardEvent.h> +#include <WebCore/Settings.h> + +using namespace WebCore; + +namespace WebKit { + +void WebPage::platformInitialize() +{ + notImplemented(); +} + +void WebPage::platformPreferencesDidChange(const WebPreferencesStore&) +{ + notImplemented(); +} + +static inline void scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity) +{ + page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity); +} + +bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent) +{ + if (keyboardEvent.type() != WebEvent::KeyDown && keyboardEvent.type() != WebEvent::RawKeyDown) + return false; + + switch (keyboardEvent.windowsVirtualKeyCode()) { + case VK_BACK: + if (keyboardEvent.shiftKey()) + m_page->goForward(); + else + m_page->goBack(); + break; + case VK_SPACE: + scroll(m_page.get(), keyboardEvent.shiftKey() ? ScrollUp : ScrollDown, ScrollByPage); + break; + case VK_LEFT: + scroll(m_page.get(), ScrollLeft, ScrollByLine); + break; + case VK_RIGHT: + scroll(m_page.get(), ScrollRight, ScrollByLine); + break; + case VK_UP: + scroll(m_page.get(), ScrollUp, ScrollByLine); + break; + case VK_DOWN: + scroll(m_page.get(), ScrollDown, ScrollByLine); + break; + case VK_HOME: + scroll(m_page.get(), ScrollUp, ScrollByDocument); + break; + case VK_END: + scroll(m_page.get(), ScrollDown, ScrollByDocument); + break; + case VK_PRIOR: + scroll(m_page.get(), ScrollUp, ScrollByPage); + break; + case VK_NEXT: + scroll(m_page.get(), ScrollDown, ScrollByPage); + break; + default: + return false; + } + + return true; +} + +bool WebPage::platformHasLocalDataForURL(const WebCore::KURL&) +{ + // FIXME: Implement + notImplemented(); + return false; +} + +String WebPage::cachedResponseMIMETypeForURL(const WebCore::KURL&) +{ + // FIXME: Implement + return String(); +} + +bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest&) +{ + // FIXME: Implement + return true; +} + +} // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm index 8d81889..d7b352c 100644 --- a/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm +++ b/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm @@ -27,10 +27,13 @@ #import "WebPage.h" #import "AccessibilityWebPageObject.h" +#import "AttributedString.h" #import "DataReference.h" +#import "EditorState.h" #import "PluginView.h" #import "WebCoreArgumentCoders.h" #import "WebEvent.h" +#import "WebEventConversion.h" #import "WebFrame.h" #import "WebPageProxyMessages.h" #import "WebProcess.h" @@ -39,6 +42,7 @@ #import <WebCore/Frame.h> #import <WebCore/FrameView.h> #import <WebCore/HitTestResult.h> +#import <WebCore/HTMLConverter.h> #import <WebCore/KeyboardEvent.h> #import <WebCore/Page.h> #import <WebCore/PlatformKeyboardEvent.h> @@ -53,6 +57,8 @@ using namespace WebCore; namespace WebKit { +static PassRefPtr<Range> convertToRange(Frame*, NSRange); + void WebPage::platformInitialize() { m_page->addSchedulePair(SchedulePair::create([NSRunLoop currentRunLoop], kCFRunLoopCommonModes)); @@ -77,68 +83,131 @@ void WebPage::platformPreferencesDidChange(const WebPreferencesStore&) { } -bool WebPage::interceptEditingKeyboardEvent(KeyboardEvent* evt, bool shouldSaveCommand) +typedef HashMap<String, String> SelectorNameMap; + +// Map selectors into Editor command names. +// This is not needed for any selectors that have the same name as the Editor command. +static const SelectorNameMap* createSelectorExceptionMap() +{ + SelectorNameMap* map = new HashMap<String, String>; + + map->add("insertNewlineIgnoringFieldEditor:", "InsertNewline"); + map->add("insertParagraphSeparator:", "InsertNewline"); + map->add("insertTabIgnoringFieldEditor:", "InsertTab"); + map->add("pageDown:", "MovePageDown"); + map->add("pageDownAndModifySelection:", "MovePageDownAndModifySelection"); + map->add("pageUp:", "MovePageUp"); + map->add("pageUpAndModifySelection:", "MovePageUpAndModifySelection"); + + return map; +} + +static String commandNameForSelectorName(const String& selectorName) +{ + // Check the exception map first. + static const SelectorNameMap* exceptionMap = createSelectorExceptionMap(); + SelectorNameMap::const_iterator it = exceptionMap->find(selectorName); + if (it != exceptionMap->end()) + return it->second; + + // Remove the trailing colon. + // No need to capitalize the command name since Editor command names are not case sensitive. + size_t selectorNameLength = selectorName.length(); + if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':') + return String(); + return selectorName.left(selectorNameLength - 1); +} + +static Frame* frameForEvent(KeyboardEvent* event) { - Node* node = evt->target()->toNode(); + Node* node = event->target()->toNode(); ASSERT(node); Frame* frame = node->document()->frame(); ASSERT(frame); + return frame; +} + +bool WebPage::executeKeypressCommandsInternal(const Vector<WebCore::KeypressCommand>& commands, KeyboardEvent* event) +{ + Frame* frame = frameForEvent(event); + ASSERT(frame->page() == corePage()); + + bool eventWasHandled = false; + for (size_t i = 0; i < commands.size(); ++i) { + if (commands[i].commandName == "insertText:") { + ASSERT(!frame->editor()->hasComposition()); + + if (!frame->editor()->canEdit()) + continue; + + // An insertText: might be handled by other responders in the chain if we don't handle it. + // One example is space bar that results in scrolling down the page. + eventWasHandled |= frame->editor()->insertText(commands[i].text, event); + } else { + Editor::Command command = frame->editor()->command(commandNameForSelectorName(commands[i].commandName)); + if (command.isSupported()) { + bool commandExecutedByEditor = command.execute(event); + eventWasHandled |= commandExecutedByEditor; + if (!commandExecutedByEditor) { + bool performedNonEditingBehavior = event->keyEvent()->type() == PlatformKeyboardEvent::RawKeyDown && performNonEditingBehaviorForSelector(commands[i].commandName); + eventWasHandled |= performedNonEditingBehavior; + } + } else { + bool commandWasHandledByUIProcess = false; + WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::ExecuteSavedCommandBySelector(commands[i].commandName), + Messages::WebPageProxy::ExecuteSavedCommandBySelector::Reply(commandWasHandledByUIProcess), m_pageID); + eventWasHandled |= commandWasHandledByUIProcess; + } + } + } + return eventWasHandled; +} + +bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event, bool saveCommands) +{ + ASSERT(!saveCommands || event->keypressCommands().isEmpty()); // Save commands once for each event. + + Frame* frame = frameForEvent(event); - const PlatformKeyboardEvent* keyEvent = evt->keyEvent(); - if (!keyEvent) + const PlatformKeyboardEvent* platformEvent = event->keyEvent(); + if (!platformEvent) return false; - const Vector<KeypressCommand>& commands = evt->keypressCommands(); - bool hasKeypressCommand = !commands.isEmpty(); - + Vector<KeypressCommand>& commands = event->keypressCommands(); + + if ([platformEvent->macEvent() type] == NSFlagsChanged) + return false; + bool eventWasHandled = false; - if (shouldSaveCommand || !hasKeypressCommand) { - Vector<KeypressCommand> commandsList; - Vector<CompositionUnderline> underlines; - unsigned start; - unsigned end; - if (!WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(keyEvent->type()), - Messages::WebPageProxy::InterpretKeyEvent::Reply(commandsList, start, end, underlines), - m_pageID, CoreIPC::Connection::NoTimeout)) + if (saveCommands) { + KeyboardEvent* oldEvent = m_keyboardEventBeingInterpreted; + m_keyboardEventBeingInterpreted = event; + bool sendResult = WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretQueuedKeyEvent(editorState()), + Messages::WebPageProxy::InterpretQueuedKeyEvent::Reply(eventWasHandled, commands), m_pageID); + m_keyboardEventBeingInterpreted = oldEvent; + if (!sendResult) + return false; + + // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline. + // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that + // should be handled like normal text input after DOM event dispatch. + if (!event->keypressCommands().isEmpty()) return false; - if (commandsList.isEmpty()) - return eventWasHandled; - - if (commandsList[0].commandName == "setMarkedText") { - frame->editor()->setComposition(commandsList[0].text, underlines, start, end); - eventWasHandled = true; - } else if (commandsList[0].commandName == "insertText" && frame->editor()->hasComposition()) { - frame->editor()->confirmComposition(commandsList[0].text); - eventWasHandled = true; - } else if (commandsList[0].commandName == "unmarkText") { - frame->editor()->confirmComposition(); - eventWasHandled = true; - } else { - for (size_t i = 0; i < commandsList.size(); i++) - evt->keypressCommands().append(commandsList[i]); - } } else { - size_t size = commands.size(); - // Are there commands that would just cause text insertion if executed via Editor? + // Are there commands that could just cause text insertion if executed via Editor? // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated // (e.g. Tab that inserts a Tab character, or Enter). bool haveTextInsertionCommands = false; - for (size_t i = 0; i < size; ++i) { - if (frame->editor()->command(commands[i].commandName).isTextInsertion()) + for (size_t i = 0; i < commands.size(); ++i) { + if (frame->editor()->command(commandNameForSelectorName(commands[i].commandName)).isTextInsertion()) haveTextInsertionCommands = true; } - if (!haveTextInsertionCommands || keyEvent->type() == PlatformKeyboardEvent::Char) { - for (size_t i = 0; i < size; ++i) { - if (commands[i].commandName == "insertText") { - // Don't insert null or control characters as they can result in unexpected behaviour - if (evt->charCode() < ' ') - return false; - eventWasHandled = frame->editor()->insertText(commands[i].text, evt); - } else - if (frame->editor()->command(commands[i].commandName).isSupported()) - eventWasHandled = frame->editor()->command(commands[i].commandName).execute(evt); - } + // If there are no text insertion commands, default keydown handler is the right time to execute the commands. + // Keypress (Char event) handler is the latest opportunity to execute. + if (!haveTextInsertionCommands || platformEvent->type() == PlatformKeyboardEvent::Char) { + eventWasHandled = executeKeypressCommandsInternal(event->keypressCommands(), event); + event->keypressCommands().clear(); } } return eventWasHandled; @@ -152,6 +221,54 @@ void WebPage::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdenti } } +void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, EditorState& newState) +{ + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + + if (frame->selection()->isContentEditable()) { + RefPtr<Range> replacementRange; + if (replacementRangeStart != NSNotFound) { + replacementRange = convertToRange(frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart)); + frame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY)); + } + + frame->editor()->setComposition(text, underlines, selectionStart, selectionEnd); + } + + newState = editorState(); +} + +void WebPage::confirmComposition(EditorState& newState) +{ + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + + frame->editor()->confirmComposition(); + + newState = editorState(); +} + +void WebPage::insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, bool& handled, EditorState& newState) +{ + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + + RefPtr<Range> replacementRange; + if (replacementRangeStart != NSNotFound) { + replacementRange = convertToRange(frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart)); + frame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY)); + } + + if (!frame->editor()->hasComposition()) { + // An insertText: might be handled by other responders in the chain if we don't handle it. + // One example is space bar that results in scrolling down the page. + handled = frame->editor()->insertText(text, m_keyboardEventBeingInterpreted); + } else { + handled = true; + frame->editor()->confirmComposition(text); + } + + newState = editorState(); +} + void WebPage::getMarkedRange(uint64_t& location, uint64_t& length) { location = NSNotFound; @@ -159,38 +276,59 @@ void WebPage::getMarkedRange(uint64_t& location, uint64_t& length) Frame* frame = m_page->focusController()->focusedOrMainFrame(); if (!frame) return; - - getLocationAndLengthFromRange(frame->editor()->compositionRange().get(), location, length); -} + RefPtr<Range> range = frame->editor()->compositionRange(); + size_t locationSize; + size_t lengthSize; + if (range && TextIterator::locationAndLengthFromRange(range.get(), locationSize, lengthSize)) { + location = static_cast<uint64_t>(locationSize); + length = static_cast<uint64_t>(lengthSize); + } +} -static PassRefPtr<Range> characterRangeAtPositionForPoint(Frame* frame, const VisiblePosition& position, const IntPoint& point) +void WebPage::getSelectedRange(uint64_t& location, uint64_t& length) { - if (position.isNull()) - return 0; + location = NSNotFound; + length = 0; + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame) + return; - VisiblePosition previous = position.previous(); - if (previous.isNotNull()) { - RefPtr<Range> previousCharacterRange = makeRange(previous, position); - IntRect rect = frame->editor()->firstRectForRange(previousCharacterRange.get()); - if (rect.contains(point)) - return previousCharacterRange.release(); - } - - VisiblePosition next = position.next(); - if (next.isNotNull()) { - RefPtr<Range> nextCharacterRange = makeRange(position, next); - IntRect rect = frame->editor()->firstRectForRange(nextCharacterRange.get()); - if (rect.contains(point)) - return nextCharacterRange.release(); + size_t locationSize; + size_t lengthSize; + RefPtr<Range> range = frame->selection()->toNormalizedRange(); + if (range && TextIterator::locationAndLengthFromRange(range.get(), locationSize, lengthSize)) { + location = static_cast<uint64_t>(locationSize); + length = static_cast<uint64_t>(lengthSize); } - - return 0; } -static PassRefPtr<Range> characterRangeAtPoint(Frame* frame, const IntPoint& point) +void WebPage::getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString& result) { - return characterRangeAtPositionForPoint(frame, frame->visiblePositionForPoint(point), point); + NSRange nsRange = NSMakeRange(location, length - location); + + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame) + return; + + if (frame->selection()->isNone() || !frame->selection()->isContentEditable() || frame->selection()->isInPasswordField()) + return; + + RefPtr<Range> range = convertToRange(frame, nsRange); + if (!range) + return; + + result.string = [WebHTMLConverter editingAttributedStringFromRange:range.get()]; + NSAttributedString* attributedString = result.string.get(); + + // [WebHTMLConverter editingAttributedStringFromRange:] insists on inserting a trailing + // whitespace at the end of the string which breaks the ATOK input method. <rdar://problem/5400551> + // To work around this we truncate the resultant string to the correct length. + if ([attributedString length] > nsRange.length) { + ASSERT([attributedString length] == nsRange.length + 1); + ASSERT([[attributedString string] characterAtIndex:nsRange.length] == '\n' || [[attributedString string] characterAtIndex:nsRange.length] == ' '); + result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, nsRange.length)]; + } } void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index) @@ -203,15 +341,17 @@ void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index) HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(point, false); frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame(); - RefPtr<Range> range = characterRangeAtPoint(frame, result.point()); + RefPtr<Range> range = frame->rangeForPoint(result.point()); if (!range) return; - uint64_t length; - getLocationAndLengthFromRange(range.get(), index, length); + size_t location; + size_t length; + if (TextIterator::locationAndLengthFromRange(range.get(), location, length)) + index = static_cast<uint64_t>(location); } -static PassRefPtr<Range> convertToRange(Frame* frame, NSRange nsrange) +PassRefPtr<Range> convertToRange(Frame* frame, NSRange nsrange) { if (nsrange.location > INT_MAX) return 0; @@ -246,6 +386,12 @@ void WebPage::firstRectForCharacterRange(uint64_t location, uint64_t length, Web resultRect = frame->view()->contentsToWindow(rect); } +void WebPage::executeKeypressCommands(const Vector<WebCore::KeypressCommand>& commands, bool& handled, EditorState& newState) +{ + handled = executeKeypressCommandsInternal(commands, m_keyboardEventBeingInterpreted); + newState = editorState(); +} + static bool isPositionInRange(const VisiblePosition& position, Range* range) { RefPtr<Range> positionRange = makeRange(position, position); @@ -284,12 +430,12 @@ void WebPage::performDictionaryLookupAtLocation(const FloatPoint& floatPoint) frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame(); IntPoint translatedPoint = frame->view()->windowToContents(point); - VisiblePosition position = frame->visiblePositionForPoint(translatedPoint); // Don't do anything if there is no character at the point. - if (!characterRangeAtPositionForPoint(frame, position, translatedPoint)) + if (!frame->rangeForPoint(translatedPoint)) return; + VisiblePosition position = frame->visiblePositionForPoint(translatedPoint); VisibleSelection selection = m_page->focusController()->focusedOrMainFrame()->selection()->selection(); if (shouldUseSelection(position, selection)) { performDictionaryLookupForSelection(DictionaryPopupInfo::HotKey, frame, selection); @@ -378,96 +524,54 @@ void WebPage::performDictionaryLookupForRange(DictionaryPopupInfo::Type type, Fr dictionaryPopupInfo.type = type; dictionaryPopupInfo.origin = FloatPoint(rangeRect.x(), rangeRect.y()); dictionaryPopupInfo.fontInfo.fontAttributeDictionary = fontDescriptorAttributes; +#if !defined(BUILDING_ON_SNOW_LEOPARD) dictionaryPopupInfo.options = (CFDictionaryRef)options; +#endif send(Messages::WebPageProxy::DidPerformDictionaryLookup(rangeText, dictionaryPopupInfo)); } -bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent) +bool WebPage::performNonEditingBehaviorForSelector(const String& selector) { - if (keyboardEvent.type() != WebEvent::KeyDown) - return false; - - // FIXME: This should be in WebCore. - - switch (keyboardEvent.windowsVirtualKeyCode()) { - case VK_BACK: - if (keyboardEvent.shiftKey()) - m_page->goForward(); - else - m_page->goBack(); - break; - case VK_SPACE: - if (keyboardEvent.shiftKey()) - logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage); - else - logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage); - break; - case VK_PRIOR: - logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage); - break; - case VK_NEXT: - logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage); - break; - case VK_HOME: - logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument); - break; - case VK_END: - logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument); - break; - case VK_UP: - if (keyboardEvent.shiftKey()) - return false; - if (keyboardEvent.metaKey()) { - scroll(m_page.get(), ScrollUp, ScrollByDocument); - scroll(m_page.get(), ScrollLeft, ScrollByDocument); - } else if (keyboardEvent.altKey() || keyboardEvent.controlKey()) - scroll(m_page.get(), ScrollUp, ScrollByPage); - else - scroll(m_page.get(), ScrollUp, ScrollByLine); - break; - case VK_DOWN: - if (keyboardEvent.shiftKey()) - return false; - if (keyboardEvent.metaKey()) { - scroll(m_page.get(), ScrollDown, ScrollByDocument); - scroll(m_page.get(), ScrollLeft, ScrollByDocument); - } else if (keyboardEvent.altKey() || keyboardEvent.controlKey()) - scroll(m_page.get(), ScrollDown, ScrollByPage); - else - scroll(m_page.get(), ScrollDown, ScrollByLine); - break; - case VK_LEFT: - if (keyboardEvent.shiftKey()) - return false; - if (keyboardEvent.metaKey()) - m_page->goBack(); - else { - if (keyboardEvent.altKey() || keyboardEvent.controlKey()) - scroll(m_page.get(), ScrollLeft, ScrollByPage); - else - scroll(m_page.get(), ScrollLeft, ScrollByLine); - } - break; - case VK_RIGHT: - if (keyboardEvent.shiftKey()) - return false; - if (keyboardEvent.metaKey()) - m_page->goForward(); - else { - if (keyboardEvent.altKey() || keyboardEvent.controlKey()) - scroll(m_page.get(), ScrollRight, ScrollByPage); - else - scroll(m_page.get(), ScrollRight, ScrollByLine); - } - break; - default: + // FIXME: All these selectors have corresponding Editor commands, but the commands only work in editable content. + // Should such non-editing behaviors be implemented in Editor or EventHandler::defaultArrowEventHandler() perhaps? + if (selector == "moveUp:") + scroll(m_page.get(), ScrollUp, ScrollByLine); + else if (selector == "moveToBeginningOfParagraph:") + scroll(m_page.get(), ScrollUp, ScrollByPage); + else if (selector == "moveToBeginningOfDocument:") { + scroll(m_page.get(), ScrollUp, ScrollByDocument); + scroll(m_page.get(), ScrollLeft, ScrollByDocument); + } else if (selector == "moveDown:") + scroll(m_page.get(), ScrollDown, ScrollByLine); + else if (selector == "moveToEndOfParagraph:") + scroll(m_page.get(), ScrollDown, ScrollByPage); + else if (selector == "moveToEndOfDocument:") { + scroll(m_page.get(), ScrollDown, ScrollByDocument); + scroll(m_page.get(), ScrollLeft, ScrollByDocument); + } else if (selector == "moveLeft:") + scroll(m_page.get(), ScrollLeft, ScrollByLine); + else if (selector == "moveWordLeft:") + scroll(m_page.get(), ScrollLeft, ScrollByPage); + else if (selector == "moveToLeftEndOfLine:") + m_page->goBack(); + else if (selector == "moveRight:") + scroll(m_page.get(), ScrollRight, ScrollByLine); + else if (selector == "moveWordRight:") + scroll(m_page.get(), ScrollRight, ScrollByPage); + else if (selector == "moveToRightEndOfLine:") + m_page->goForward(); + else return false; - } return true; } +bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&) +{ + return false; +} + void WebPage::registerUIProcessAccessibilityTokens(const CoreIPC::DataReference& elementToken, const CoreIPC::DataReference& windowToken) { #if !defined(BUILDING_ON_SNOW_LEOPARD) @@ -484,6 +588,10 @@ void WebPage::registerUIProcessAccessibilityTokens(const CoreIPC::DataReference& void WebPage::writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes, bool& result) { Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame || frame->selection()->isNone()) { + result = false; + return; + } frame->editor()->writeSelectionToPasteboard(pasteboardName, pasteboardTypes); result = true; } @@ -491,6 +599,10 @@ void WebPage::writeSelectionToPasteboard(const String& pasteboardName, const Vec void WebPage::readSelectionFromPasteboard(const String& pasteboardName, bool& result) { Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame || frame->selection()->isNone()) { + result = false; + return; + } frame->editor()->readSelectionFromPasteboard(pasteboardName); result = true; } @@ -548,10 +660,39 @@ void WebPage::setDragSource(NSObject *dragSource) void WebPage::platformDragEnded() { + // The draggedImage method releases its responder; we retain here to balance that. + [m_dragSource.get() retain]; // The drag source we care about here is NSFilePromiseDragSource, which doesn't look at // the arguments. It's OK to just pass arbitrary constant values, so we just pass all zeroes. [m_dragSource.get() draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationNone]; m_dragSource = nullptr; } +void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent& event, bool& result) +{ + result = false; + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame) + return; + + HitTestResult hitResult = frame->eventHandler()->hitTestResultAtPoint(event.position(), true); + if (hitResult.isSelected()) + result = frame->eventHandler()->eventMayStartDrag(platform(event)); +} + +void WebPage::acceptsFirstMouse(int eventNumber, const WebKit::WebMouseEvent& event, bool& result) +{ + result = false; + Frame* frame = m_page->focusController()->focusedOrMainFrame(); + if (!frame) + return; + + HitTestResult hitResult = frame->eventHandler()->hitTestResultAtPoint(event.position(), true); + frame->eventHandler()->setActivationEventNumber(eventNumber); + if (hitResult.isSelected()) + result = frame->eventHandler()->eventMayStartDrag(platform(event)); + else + result = !!hitResult.scrollbar(); +} + } // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/win/LayerTreeHostWin.cpp b/Source/WebKit2/WebProcess/WebPage/win/LayerTreeHostWin.cpp new file mode 100644 index 0000000..57c04bb --- /dev/null +++ b/Source/WebKit2/WebProcess/WebPage/win/LayerTreeHostWin.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LayerTreeHost.h" + +#if USE(CA) +#include "LayerTreeHostCAWin.h" +#endif + +namespace WebKit { + +bool LayerTreeHost::supportsAcceleratedCompositing() +{ +#if USE(CA) && HAVE(WKQCA) + return LayerTreeHostCAWin::supportsAcceleratedCompositing(); +#else + return false; +#endif +} + +} // namespace WebKit diff --git a/Source/WebKit2/WebProcess/WebPage/win/WebPageWin.cpp b/Source/WebKit2/WebProcess/WebPage/win/WebPageWin.cpp index 41bb219..9c7206a 100644 --- a/Source/WebKit2/WebProcess/WebPage/win/WebPageWin.cpp +++ b/Source/WebKit2/WebProcess/WebPage/win/WebPageWin.cpp @@ -28,17 +28,22 @@ #include "FontSmoothingLevel.h" #include "WebEvent.h" +#include "WebPageProxyMessages.h" #include "WebPreferencesStore.h" #include <WebCore/FocusController.h> #include <WebCore/FontRenderingMode.h> #include <WebCore/Frame.h> #include <WebCore/FrameView.h> +#include <WebCore/HitTestRequest.h> +#include <WebCore/HitTestResult.h> #include <WebCore/KeyboardEvent.h> #include <WebCore/Page.h> #include <WebCore/PlatformKeyboardEvent.h> +#include <WebCore/RenderLayer.h> +#include <WebCore/RenderView.h> #include <WebCore/ResourceHandle.h> #include <WebCore/Settings.h> -#if PLATFORM(CG) +#if USE(CG) #include <WebKitSystemInterface/WebKitSystemInterface.h> #endif #include <WinUser.h> @@ -62,7 +67,7 @@ void WebPage::platformPreferencesDidChange(const WebPreferencesStore& store) { FontSmoothingLevel fontSmoothingLevel = static_cast<FontSmoothingLevel>(store.getUInt32ValueForKey(WebPreferencesKey::fontSmoothingLevelKey())); -#if PLATFORM(CG) +#if USE(CG) FontSmoothingLevel adjustedLevel = fontSmoothingLevel; if (adjustedLevel == FontSmoothingLevelWindows) adjustedLevel = FontSmoothingLevelMedium; @@ -351,4 +356,89 @@ void WebPage::getSelectedText(String& text) text = selectedRange->text(); } +void WebPage::gestureWillBegin(const WebCore::IntPoint& point, bool& canBeginPanning) +{ + m_gestureReachedScrollingLimit = false; + + bool hitScrollbar = false; + + HitTestRequest request(HitTestRequest::ReadOnly); + for (Frame* childFrame = m_page->mainFrame(); childFrame; childFrame = EventHandler::subframeForTargetNode(m_gestureTargetNode.get())) { + ScrollView* scollView = childFrame->view(); + if (!scollView) + break; + + RenderView* renderView = childFrame->document()->renderView(); + if (!renderView) + break; + + RenderLayer* layer = renderView->layer(); + if (!layer) + break; + + HitTestResult result = scollView->windowToContents(point); + layer->hitTest(request, result); + m_gestureTargetNode = result.innerNode(); + + if (!hitScrollbar) + hitScrollbar = result.scrollbar(); + } + + if (hitScrollbar) { + canBeginPanning = false; + return; + } + + if (!m_gestureTargetNode) { + canBeginPanning = false; + return; + } + + for (RenderObject* renderer = m_gestureTargetNode->renderer(); renderer; renderer = renderer->parent()) { + if (renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) { + canBeginPanning = true; + return; + } + } + + canBeginPanning = false; +} + +static bool scrollbarAtTopOrBottomOfDocument(Scrollbar* scrollbar) +{ + ASSERT_ARG(scrollbar, scrollbar); + return !scrollbar->currentPos() || scrollbar->currentPos() >= scrollbar->maximum(); +} + +void WebPage::gestureDidScroll(const IntSize& size) +{ + ASSERT_ARG(size, !size.isZero()); + + if (!m_gestureTargetNode || !m_gestureTargetNode->renderer() || !m_gestureTargetNode->renderer()->enclosingLayer()) + return; + + Scrollbar* verticalScrollbar = 0; + if (Frame* frame = m_page->mainFrame()) { + if (ScrollView* view = frame->view()) + verticalScrollbar = view->verticalScrollbar(); + } + + m_gestureTargetNode->renderer()->enclosingLayer()->scrollByRecursively(size.width(), size.height()); + bool gestureReachedScrollingLimit = verticalScrollbar && scrollbarAtTopOrBottomOfDocument(verticalScrollbar); + + // FIXME: We really only want to update this state if the state was updated via scrolling the main frame, + // not scrolling something in a main frame when the main frame had already reached its scrolling limit. + + if (gestureReachedScrollingLimit == m_gestureReachedScrollingLimit) + return; + + send(Messages::WebPageProxy::SetGestureReachedScrollingLimit(gestureReachedScrollingLimit)); + m_gestureReachedScrollingLimit = gestureReachedScrollingLimit; +} + +void WebPage::gestureDidEnd() +{ + m_gestureTargetNode = nullptr; +} + } // namespace WebKit |